Locating our own node is ^Y, not ^U

Y for you, on the map and in the mesh walk alike.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jean-Pierre MartineauandClaude Opus 5.5 committed 2026-10-01 23:05:06 -04:00
1 parent 71edf6a937
commit f847ebd637
7 files changed
+23 -23

No files matched your search

+1 -1
View File
@@ -647,7 +647,7 @@ branch on the platform per frame, and never `from meshterm.platforms import PLAT
thing that just isn't available this paint. Dimming is presentational — `handle` stays
the authority and no-ops. The lane is also the *only* affordance advertisement here, so
anything the desktop reaches by a chord or a bare letter (a list's `^PgUp/^PgDn` section
jumps, the Time Machine's `w`, the map's `^U`, a row's `Del`) earns a slot — otherwise
jumps, the Time Machine's `w`, the map's `^Y`, a row's `Del`) earns a slot — otherwise
it is undiscoverable on the device.
- `meshterm specimen` prints the whole visual language through the real funnels — the
acceptance card on-device, a preview under `--platform picocalc` on the desktop.
+5 -5
View File
@@ -15,7 +15,7 @@ render_map`. Keys:
* ``PgUp`` / ``PgDn`` zoom in / out,
* ``Home`` recenters and refits to the dense core of the nodes — the *region* the mesh
covers, and the same default view the map opens on,
* ``^U`` (for *you*) recenters on **your own node**, keeping the zoom you chose and
* ``^Y`` (for *you*) recenters on **your own node**, keeping the zoom you chose and
clearing any find (the lane's ``You`` chip; its Shift half also zooms in close),
* **typing finds nodes**: every letter key feeds a live name filter — matching nodes keep
bright labels while the rest dim to context, ``Backspace`` edits, ``^Enter`` frames the
@@ -287,7 +287,7 @@ class MapScreen(Screen):
editing keys, so the typed text is always visible somewhere fixed.
The line spends its whole 72-cell budget, so the two view-jump keys share one atom
(``Home/^U region/you``) and ``⇧ fine`` — a refinement of a key the line already
(``Home/^Y region/you``) and ``⇧ fine`` — a refinement of a key the line already
names, and the only atom here that documents a *modifier* rather than a binding —
is the one that gives way to make room for them. The basemap's state used to hang
off the end of this line as a suffix; it is a status atom, not a key, so it moved
@@ -296,7 +296,7 @@ class MapScreen(Screen):
"""
if self._filter:
return f"find: {self._filter}▏ · ^Enter frame · ⌫ erase · Enter/Esc clear"
return "↑↓←→ pan · PgUp/PgDn zoom · Home/^U region/you · type to find · Esc back"
return "↑↓←→ pan · PgUp/PgDn zoom · Home/^Y region/you · type to find · Esc back"
def consume_edge_scrub(self) -> int:
"""Right-edge columns the session should force-repaint on the next paint (0 = none).
@@ -958,7 +958,7 @@ class MapScreen(Screen):
active filter first, the map itself only once the filter is clear.
Three actions reframe the view, and each has both a key and an F-key chip:
``home`` the whole region, ``locate`` (^U, for *you*) our own node — ``locate_zoom``
``home`` the whole region, ``locate`` (^Y, for *you*) our own node — ``locate_zoom``
the Shift-bank variant that also homes in — and ``frame`` (^Enter) the find
matches. ``clear_find`` drops the query without moving the view, which is also
what plain **Enter** does.
@@ -1041,7 +1041,7 @@ class MapScreen(Screen):
return next((m for m in self._markers if m.is_self), None)
def _locate(self, vp: Viewport, *, zoom_in: bool = False) -> None:
"""Recentre on our own node (``^U`` / the ``You`` chip), clearing any find.
"""Recentre on our own node (``^Y`` / the ``You`` chip), clearing any find.
Plain ``You`` keeps the zoom the user chose — pressing it twice does the same
thing twice, and pairing it with one Zoom + is a single extra press. Its Shift
+2 -2
View File
@@ -229,9 +229,9 @@ _HINT_KEY_ACTIONS: dict[str, str] = {
}
#: Marks a word as *some* key notation even where it isn't one this module can map: a
#: chord (``^U``), a shifted key (``⇧Tab``), or a bare glyph key (``⌫``). An atom whose
#: chord (``^Y``), a shifted key (``⇧Tab``), or a bare glyph key (``⌫``). An atom whose
#: verb half carries one of these names more than the keys it opened with, so it is never
#: dropped on the strength of the ones it did name (the map's ``Home/^U region/you``).
#: dropped on the strength of the ones it did name (the map's ``Home/^Y region/you``).
_KEYISH = ("^", "⇧", "⌫", "↑", "↓", "←", "→")
+3 -3
View File
@@ -64,8 +64,8 @@ from .spinner import spinner_interval
#: ``m``/``i``/``h`` are not free: prompt_toolkit spells Enter, Tab and Backspace as
#: ``Keys.ControlM``/``ControlI``/``ControlH``, so claiming them here would rebind those keys.
#: A chord's letter is the mnemonic of the *action*, not of one screen's word for it —
#: ``locate`` is ^U for **you** (JP, 2026-08-09), the same key on the map and in the mesh
#: walk, because what it names on both is our own node.
#: ``locate`` is ^Y for **you** (JP, 2026-08-09; ^U until 2026-10-01), the same key on the
#: map and in the mesh walk, because what it names on both is our own node.
#:
#: Two of these are app-wide rather than a screen's: ``to_menu`` (^W) unwinds the whole
#: navigation stack back to the main menu, and ``quit`` (^Q, alongside the older ^C) asks
@@ -85,9 +85,9 @@ _CTRL_LETTER_CHORDS: dict[str, str] = {
# ^S is XOFF's key, and safe here for the same reason ^Q is not XON (see above): raw
# mode clears IXON/IXOFF, so the terminal never eats it to freeze the screen.
"s": "reveal",
"u": "locate",
"v": "paste_clipboard",
"w": "to_menu",
"y": "locate",
}
#: Maps prompt_toolkit keys to the normalized action names screens understand.
+7 -7
View File
@@ -46,7 +46,7 @@ window, drawn whole while whole fits and *cropped* at either edge the walk conti
past — a chip sheared on its own half block, the way every path row in the app that
outgrows its lane is cut. At rest the window sits at the tail, so the focus and the
steps just taken are in view and it is the walk's start that is cropped; **←→ slide
it** to read back over a long walk. **^U** refocuses our own node.
it** to read back over a long walk. **^Y** refocuses our own node.
**Typing finds** — a global filter over every node in the graph, islands included — and
narrows the canvas's fan to matching neighbours as it goes, the focus and the came-from
node holding through it; Enter teleports the focus to the highlighted match (the trail
@@ -239,7 +239,7 @@ class WalkScreen(Screen):
to stand in for *Top* and leave *Bottom* blank to keep the pretence. It takes a
slot of the screen's own instead (JP, 2026-08-09), which is what F1-F3 are for,
and the pager's Shift bank goes back to meaning here what it means everywhere
else: the two ends of the list this screen scrolls. ^U reaches the same action on
else: the two ends of the list this screen scrolls. ^Y reaches the same action on
a keyboard, the same chord the map spends on our node.
Both nav slots need rows to move through, which a leaf node in a sparse graph may
@@ -285,7 +285,7 @@ class WalkScreen(Screen):
self._self_label = self_label
self._prefix_bytes = prefix_bytes
#: The walked trail of canonical ids; the focus is its last entry. Walking
#: appends, ⌫ pops, ^U resets to us, a find teleport restarts it.
#: appends, ⌫ pops, ^Y resets to us, a find teleport restarts it.
self._trail: list[str] = [topo.self_id]
#: Hops the breadcrumb line is scrolled off its *tail* end (see
#: :meth:`_trail_text`). 0 is the resting state — the focus flush right — and
@@ -431,7 +431,7 @@ class WalkScreen(Screen):
atoms = ["↑↓ move"]
if scrolls:
atoms.append("←→ trail")
atoms += ["Enter focus", "⌫ back", "^U you"]
atoms += ["Enter focus", "⌫ back", "^Y you"]
if not scrolls:
atoms.append("type to find")
atoms.append("Esc back")
@@ -441,7 +441,7 @@ class WalkScreen(Screen):
"""Move the highlight, walk, back up, find, or dismiss.
Home/End are the list's own ends here, as on every other scrolling screen; the jump
back to our own node is ``locate`` (^U, and the lane's F3), which is not a place in
back to our own node is ``locate`` (^Y, and the lane's F3), which is not a place in
this list at all — see :attr:`fkey_lane`.
"""
rows = self._rows()
@@ -491,7 +491,7 @@ class WalkScreen(Screen):
elif action == "right":
self._trail_scroll = max(0, self._trail_scroll - _HSCROLL_STEP)
elif action == "locate":
# ^U (and F3): abandon the walk rather than move within it — the trail goes
# ^Y (and F3): abandon the walk rather than move within it — the trail goes
# back to just us and any find narrowing the list is dropped with it.
self._trail = [self._topo.self_id]
self._filter = ""
@@ -644,7 +644,7 @@ class WalkScreen(Screen):
costs the window a cell, so the crop is measured only once both are known, else the
line would draw a cell past the row. Sliding stops where the head comes into view
rather than running the line off the edge, and any change to the trail itself
resets it: a walk, a step back, a teleport and ^U all end with the focus in view,
resets it: a walk, a step back, a teleport and ^Y all end with the focus in view,
which is where the next move is read from.
"""
self._trail_width = width
+4 -4
View File
@@ -359,15 +359,15 @@ def test_dialogs_draw_no_lane_at_all() -> None:
def test_map_locate_is_reachable_from_both_control_keys() -> None:
"""``locate`` is bound as a chord app-wide, so both Ctrl keys and F2 reach the same action.
The letter is the mnemonic of the action — ^U for *you* — so it is the same chord on
The letter is the mnemonic of the action — ^Y for *you* — so it is the same chord on
every screen that can point at our own node, not one screen's initial.
"""
from prompt_toolkit.keys import Keys
from meshterm.ui.tui.session import _CTRL_LETTER_CHORDS, _KEY_ACTIONS
assert _CTRL_LETTER_CHORDS["u"] == "locate" # the right-Ctrl rescue's half
assert _KEY_ACTIONS[Keys.ControlU] == "locate" # the ordinary binding, generated from it
assert _CTRL_LETTER_CHORDS["y"] == "locate" # the right-Ctrl rescue's half
assert _KEY_ACTIONS[Keys.ControlY] == "locate" # the ordinary binding, generated from it
def test_host_battery_reads_the_sysfs_supply(tmp_path, monkeypatch) -> None:
@@ -458,7 +458,7 @@ def test_an_atom_the_lane_only_half_covers_stands() -> None:
# The atom documents the arrows too, and no slot ever claims those.
assert strip_lane_atoms("↑↓ PgUp/PgDn scroll", DEFAULT_LANE) == "↑↓ PgUp/PgDn scroll"
# A second key riding in the verb half keeps the atom whole (the map's region/you).
assert strip_lane_atoms("Home/^U region/you", DEFAULT_LANE) == "Home/^U region/you"
assert strip_lane_atoms("Home/^Y region/you", DEFAULT_LANE) == "Home/^Y region/you"
def test_a_dimmed_chip_still_covers_its_atom() -> None:
+1 -1
View File
@@ -367,7 +367,7 @@ def test_walk_trail_names_carry_their_node_hues() -> None:
def test_walk_locate_refocuses_us_and_home_end_walk_the_list() -> None:
"""^U resets the walk to our own node from anywhere; Home/End are the list's ends."""
"""^Y resets the walk to our own node from anywhere; Home/End are the list's ends."""
# A hub of spokes off one of our neighbours: a walked-away focus with a list to move in.
topo = MeshTopology(US, contacts=[Hub])
hub = topo.canonical(Hub.public_key)