Theme: the cursor row is white, not the wordmark's teal
The row `❯` points at borrowed `brand` — so the app's identity ink and "the row you're on" were the same hue, and worse, teal/cyan is itself a node hue: a cyan-keyed node's name vanished into its own highlight. Give the highlight its own name. `cursor` is white on both platforms (slot 15 on the VT, the top of the bright bank, so the row's bold cannot promote it further and every dim-slot `not bold` pin inside a highlighted row goes on meaning what it meant). White sits outside the per-node spectrum, so it can never collide with an identity; it does share ink with `you`, which is the accepted cost — spans that set their own colour keep it over the base, so only unstyled text goes white, and only on the row already under the reader's eye. Every surface that draws its own cursor row follows: the select list and its reorder mode, the feed, chat, routes and actions on the node page, the composer, records, trace, tx, the walk, the paths screen, the prompt's suggestions. The composer's insertion-slot chip takes the same white — its docstring already tied it to "the colour the list cursor below it wears", and the chip ink was already picked to stay readable on white. Reverse-video chips keep `selected`: on the VT a reversed white lands on the light grey the F-key lane already owns, so a white default button would stop reading as the committing verb. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1b6a5cc1e7
commit
602bceea3b
18 files changed
+75
-49
No files matched your search
@@ -180,6 +180,15 @@ as a grouped list does. Filling a page in is editing its `.md`; no Python follow
|
||||
characters. `node.unknown` is deliberately not `muted`: muted is chrome and may sit a
|
||||
step darker, while an unidentified node is content you can still act on. Our own node
|
||||
is the pure-white `you` style; a context colouring (chart quality) may still win.
|
||||
- The cursor row — the row `❯` points at, in a select list or in a screen drawing its own
|
||||
rows — wears `cursor` (white), never `brand`: the wordmark's teal is the app's identity,
|
||||
not a selection, and teal/cyan is itself a node hue, so a cyan-keyed node used to vanish
|
||||
into its own highlight. White is outside the node spectrum, so it can never collide with
|
||||
an identity. It rides *under* the row's spans, so every lane keeps its own colour and
|
||||
only the gaps take the tint; the path composer's insertion-slot chip takes the same white
|
||||
so the row you pick and the slot it lands in read as one gesture. Reverse-video chips
|
||||
(dialog buttons, the editor cursor) keep their own `selected` fill — on the VT a reversed
|
||||
white lands on the light grey the F-key lane already owns.
|
||||
Recency heat colours heard/first-heard ages, never names — seven steps on plain human
|
||||
boundaries (`widgets._HEAT_STEPS`), each `heat.*` style named for how old the node it
|
||||
colours is: white under 5 minutes, then yellow, light red, brown, red, light grey, and
|
||||
|
||||
+5
-5
@@ -468,12 +468,12 @@ class ChatScreen(Screen):
|
||||
sender — otherwise a run of same-sender messages would appear to share one time.
|
||||
A long body wraps with a hanging indent so continuation lines align under the body
|
||||
rather than under the timestamp gutter. When ``selected``, the line is marked as the
|
||||
reply target (matching the select screen's ``❯`` pointer and brand highlight).
|
||||
reply target (matching the select screen's ``❯`` pointer and cursor highlight).
|
||||
"""
|
||||
stamp = message.created_at.astimezone()
|
||||
prefix = Text()
|
||||
prefix.append("❯ " if selected else " ", style="brand" if selected else None)
|
||||
prefix.append(f"{stamp:%H:%M} ", style="brand" if selected else "muted")
|
||||
prefix.append("❯ " if selected else " ", style="cursor" if selected else None)
|
||||
prefix.append(f"{stamp:%H:%M} ", style="cursor" if selected else "muted")
|
||||
body_text = self._body_text(body, message, selected=selected)
|
||||
return render_hanging(prefix, body_text, width, indent=prefix.cell_len)
|
||||
|
||||
@@ -499,10 +499,10 @@ class ChatScreen(Screen):
|
||||
The reply flow primes the compose line with an ``@[Name]`` token (see
|
||||
:meth:`_begin_reply`); here it reads back as a bare ``@Name`` colored in that
|
||||
sender's stable hue, so a mention is visually tied to the person it names. Text
|
||||
around the mentions keeps the line's base style (brand when the message is the
|
||||
around the mentions keeps the line's base style (``cursor`` when the message is the
|
||||
picked reply target, otherwise unstyled).
|
||||
"""
|
||||
base = "brand" if selected else None
|
||||
base = "cursor" if selected else None
|
||||
text = Text()
|
||||
pos = 0
|
||||
for match in _MENTION.finditer(body):
|
||||
|
||||
@@ -478,13 +478,13 @@ class LiveFeedScreen(Screen):
|
||||
The very rows :func:`~meshterm.ui.menus.back_rows` gives a select list, drawn here
|
||||
by hand because the feed is a rendered screen rather than a list of choices — same
|
||||
blank line, same bare word, no arrow and no icon, and the same ``❯`` cursor over a
|
||||
brand row when it is the stop the cursor rests on.
|
||||
highlighted row when it is the stop the cursor rests on.
|
||||
"""
|
||||
selected = self._selected is None
|
||||
row = Text(_CURSOR if selected else " ", style="brand" if selected else "")
|
||||
row = Text(_CURSOR if selected else " ", style="cursor" if selected else "")
|
||||
row.append("Back")
|
||||
if selected:
|
||||
row.style = "brand"
|
||||
row.style = "cursor"
|
||||
return ["", render_to_ansi(row, width, no_wrap=True)]
|
||||
|
||||
def _heading(self) -> Text:
|
||||
@@ -563,14 +563,14 @@ class LiveFeedScreen(Screen):
|
||||
72-column screen precisely because it doesn't try to, and the route is drawn
|
||||
properly one keypress away, in the packet viewer.
|
||||
|
||||
The highlight is the app's own: the ``❯`` pointer and a brand base style under the
|
||||
The highlight is the app's own: the ``❯`` pointer and a ``cursor`` base under the
|
||||
whole row, exactly as every select list draws its cursor. The lanes keep their own
|
||||
colours over it — the SNR its quality hue, a name its palette hue — because those
|
||||
colours are the content; the pointer and the base tint are what say "this row".
|
||||
The one row that can wear a *different* pointer is the newest, which takes ``^``
|
||||
while the cursor is pinned to the top of the stream rather than to the packet
|
||||
currently sitting there (:data:`_PIN_CURSOR`, and the module docstring). Same lane,
|
||||
same brand tint, same one cell — only the mark differs, because only the meaning
|
||||
same cursor tint, same one cell — only the mark differs, because only the meaning
|
||||
does.
|
||||
|
||||
A row that runs past the right edge — a terminal narrower than the lanes need —
|
||||
@@ -582,7 +582,7 @@ class LiveFeedScreen(Screen):
|
||||
"""
|
||||
row = Text(no_wrap=True, overflow="ellipsis")
|
||||
cursor = _PIN_CURSOR if self._pinned else _CURSOR
|
||||
row.append(cursor if selected else " ", style="brand" if selected else "")
|
||||
row.append(cursor if selected else " ", style="cursor" if selected else "")
|
||||
avail = max(1, width - 2)
|
||||
|
||||
body = Text(no_wrap=True, overflow="ellipsis")
|
||||
@@ -626,9 +626,9 @@ class LiveFeedScreen(Screen):
|
||||
body = crop_cells(body, self._hshift, avail)
|
||||
row.append_text(body)
|
||||
if selected:
|
||||
# The brand tint rides *under* the row's spans (the select list's own
|
||||
# The cursor tint rides *under* the row's spans (the select list's own
|
||||
# convention), so the lanes keep their colours and only the gaps take it.
|
||||
row.style = "brand"
|
||||
row.style = "cursor"
|
||||
return row
|
||||
|
||||
def _feed_subject(self, entry: PacketEntry) -> Text:
|
||||
|
||||
@@ -319,7 +319,7 @@ class MessagePathsScreen(Screen):
|
||||
left_more = 1 if shift > 0 else 0
|
||||
right_more = 1 if shift + avail < full.cell_len else 0
|
||||
inner = max(1, avail - left_more - right_more)
|
||||
line = Text("❯ ", style="brand", no_wrap=True)
|
||||
line = Text("❯ ", style="cursor", no_wrap=True)
|
||||
# The marks stand for the cell just outside the window on their own side, so each
|
||||
# takes its colour from the nearest cell still drawn — the chip the reader can see
|
||||
# being the one that visibly runs on.
|
||||
@@ -328,7 +328,7 @@ class MessagePathsScreen(Screen):
|
||||
line.append_text(crop_cells(full, shift + left_more, inner))
|
||||
if right_more:
|
||||
line.append_text(cut_mark(full, shift + left_more + inner - 1, ELIDE_TAIL))
|
||||
line.style = "brand"
|
||||
line.style = "cursor"
|
||||
return render_to_ansi(line, width, no_wrap=True)
|
||||
|
||||
# -- the graph --
|
||||
|
||||
@@ -975,7 +975,7 @@ class NodeDetailScreen(Screen):
|
||||
|
||||
The route keeps its per-node colours even when selected (the pointer, and the white
|
||||
line in the graph above, carry the selection) — unlike the plain action rows, which
|
||||
go fully brand, since here the colour *is* the content. The trailing ``…`` is the
|
||||
take the highlight, since here the colour *is* the content. The trailing ``…`` is the
|
||||
app-wide opens-further-prompts mark: Enter on the row arms a trace on it. It rides
|
||||
*outside* the lane (:func:`~meshterm.ui.pathline.with_action_mark`) — chrome buys no
|
||||
cells off the route, so a chain that fits stays whole and closes on its rounded cap
|
||||
@@ -999,7 +999,7 @@ class NodeDetailScreen(Screen):
|
||||
"""
|
||||
indent = _ROUTE_INDENT
|
||||
avail = max(1, width - indent)
|
||||
pointer = Text("❯ " if selected else " ", style="brand" if selected else "")
|
||||
pointer = Text("❯ " if selected else " ", style="cursor" if selected else "")
|
||||
marked = route.path
|
||||
if selected and self._hshift:
|
||||
total = cell_len(marked.plain)
|
||||
@@ -1042,8 +1042,8 @@ class NodeDetailScreen(Screen):
|
||||
return lines
|
||||
|
||||
def _action_line(self, action: _Action, selected: bool, width: int) -> str:
|
||||
"""One action row: ``❯`` + icon + label, the whole row brand when it is the cursor's."""
|
||||
text = Text("❯ " if selected else " ", style="brand" if selected else "")
|
||||
"""One action row: ``❯`` + icon + label, the whole row lit when it is the cursor's."""
|
||||
text = Text("❯ " if selected else " ", style="cursor" if selected else "")
|
||||
# The icon lane is decoration a platform may drop whole (command_icon); the label
|
||||
# is what names the action, so an emptied lane simply gives it the cells.
|
||||
mark = command_icon(action.glyph) if action.glyph else ""
|
||||
@@ -1051,7 +1051,7 @@ class NodeDetailScreen(Screen):
|
||||
text.append(f"{mark} ", style=action.glyph_style)
|
||||
text.append(action.label)
|
||||
if selected:
|
||||
text.style = "brand"
|
||||
text.style = "cursor"
|
||||
text.no_wrap = True
|
||||
text.truncate(width, overflow="ellipsis")
|
||||
return render_to_ansi(text, width)
|
||||
|
||||
@@ -26,7 +26,7 @@ Interaction, following the reorder screen's cursor-over-rows-and-actions pattern
|
||||
* ↑/↓ move over suggestions and the action rows; Enter on a suggestion inserts it
|
||||
at the route's insertion cursor.
|
||||
* ←/→ slide that insertion cursor along the editable leg — it rides *in* the route as
|
||||
a hop of its own, the brand-accent ``+`` slot the next chosen node drops into — so a
|
||||
a hop of its own, the ``cursor``-white ``+`` slot the next chosen node drops into — so a
|
||||
hop can be spliced in (at the slot) or removed (⌫, to its left) anywhere in the
|
||||
route, not just at the end. It opens at the end of the composed leg, where inserting
|
||||
is appending — the classic flow unchanged. The suggestion list follows: it always
|
||||
@@ -496,7 +496,7 @@ class PathComposerScreen(Screen):
|
||||
|
||||
The insertion cursor is *in* the route, not between two of its hops: the
|
||||
``+`` slot (:data:`~meshterm.ui.pathline.CURSOR_GLYPH`) sits where the next
|
||||
chosen node will, in the brand accent the row cursor below it wears. Drawing an
|
||||
chosen node will, in the ``cursor`` white the row cursor below it wears. Drawing an
|
||||
insertion point as a position rather than as a gap is what lets the preview stay
|
||||
the picture the trace window paints — chips and all, rather than falling back to
|
||||
arrows for the sake of a seam to sit in — and lets a wrapped route carry the
|
||||
@@ -610,10 +610,10 @@ class PathComposerScreen(Screen):
|
||||
if kind == "action" and (i == 0 or rows[i - 1][0] != "action"):
|
||||
entries.append((None, "")) # a spacer sets the action group apart
|
||||
is_sel = i == self._index
|
||||
text = Text("❯ " if is_sel else " ", style="brand" if is_sel else "")
|
||||
text = Text("❯ " if is_sel else " ", style="cursor" if is_sel else "")
|
||||
text.append_text(self._row_text(kind, payload))
|
||||
if is_sel:
|
||||
text.style = "brand"
|
||||
text.style = "cursor"
|
||||
text.no_wrap = True
|
||||
# A suggestion row names a node in the route's own vocabulary, so it is cut
|
||||
# like one: a chip that runs off the dialog cracks, prose keeps the ellipsis.
|
||||
|
||||
@@ -187,7 +187,7 @@ class PathHop:
|
||||
allowed) or theme name — for context colourings that outrank identity.
|
||||
Plain mode uses it as the label style; powerline as the chip fill.
|
||||
cursor: This hop is an editor's insertion slot rather than a node — the
|
||||
:data:`CURSOR_GLYPH` in the app's brand accent, the same colour the list
|
||||
:data:`CURSOR_GLYPH` in the app's ``cursor`` white, the same colour the list
|
||||
cursor (``❯``) below it wears, so the two halves of one gesture (the row
|
||||
you pick, the slot it lands in) read as one thing.
|
||||
gap: This hop is a mark standing *between* two nodes rather than being one — the
|
||||
@@ -894,15 +894,16 @@ class PathLine:
|
||||
"""A chip's fill: cursor accent, override, dim slate, our grey, hue, keyless grey.
|
||||
|
||||
The insertion slot outranks everything — it is the one chip that isn't a node,
|
||||
and it wears the brand accent so it reads as chrome among identities rather than
|
||||
as a hop with an unlucky hue. The fade comes next, outranking identity including
|
||||
and it wears the ``cursor`` white so it reads as chrome among identities rather
|
||||
than as a hop with an unlucky hue (white sits outside the node spectrum, and the
|
||||
chip ink is already picked to stay readable on it). The fade comes next, outranking identity including
|
||||
our own: a dimmed hop is one nobody composed (an automatic landing back home, a
|
||||
mirrored return leg), and our end must recede with the rest of that automatic
|
||||
half rather than keep its yellow among the greys. Plain mode says the same thing
|
||||
by fading the name.
|
||||
"""
|
||||
if hop.cursor:
|
||||
return _style_hex("brand") or _KEYLESS_BG
|
||||
return _style_hex("cursor") or _KEYLESS_BG
|
||||
if hop.style:
|
||||
resolved = _style_hex(hop.style)
|
||||
if resolved:
|
||||
|
||||
@@ -471,7 +471,7 @@ class RecordDialog(Screen):
|
||||
if key == "back":
|
||||
lines.append("")
|
||||
selected = i == self._index
|
||||
row = Text("❯ " if selected else " ", style="brand" if selected else "")
|
||||
row = Text("❯ " if selected else " ", style="cursor" if selected else "")
|
||||
if key == "trace":
|
||||
row.append_text(marked_label(
|
||||
"👣", "Trace this path — reopen in Trace path", "accent"
|
||||
@@ -481,7 +481,7 @@ class RecordDialog(Screen):
|
||||
else:
|
||||
row.append("Back")
|
||||
if selected:
|
||||
row.style = "brand"
|
||||
row.style = "cursor"
|
||||
self._cursor = len(lines)
|
||||
row.no_wrap = True
|
||||
row.truncate(width, overflow="ellipsis")
|
||||
|
||||
@@ -32,6 +32,18 @@ MESH_THEME = Theme(
|
||||
# theme name with an attribute (e.g. "reverse brand" renders as plain text), so the
|
||||
# reverse is baked into the definition here rather than tacked on at the call site.
|
||||
"selected": "reverse bold #5eead4",
|
||||
# THE cursor row — the one row the ❯ points at, in every select list and in every
|
||||
# screen that draws its own rows (feed, routes, records, walk, composer). White,
|
||||
# and deliberately *not* ``brand``: the highlight used to borrow the wordmark's
|
||||
# teal, which put the app's identity ink and "the row you're on" on the same hue,
|
||||
# and worse, teal/cyan is itself a node hue — a cyan-keyed node's name vanished
|
||||
# into its own highlight. White is outside the per-node spectrum (see node_style)
|
||||
# so it can never collide with an identity. It does share ink with ``you``, which
|
||||
# is the accepted cost: spans that set their own colour keep it over the base, so
|
||||
# only *unstyled* text goes white, and only on the row already under the reader's
|
||||
# eye. Bold like ``brand`` was, so the dim-slot ``not bold`` pins that protect a
|
||||
# span inside a highlighted row (see MESH_THEME_16) go on meaning what they meant.
|
||||
"cursor": "bold #ffffff",
|
||||
# Reversed error (the text-editor cursor sitting on an over-budget character). Baked
|
||||
# in for the same reason as ``selected`` — "reverse err" would render as plain text.
|
||||
"err.reverse": "reverse bold #f87171",
|
||||
@@ -246,6 +258,10 @@ MESH_THEME_16 = Theme(
|
||||
"brand": "bold color(14)",
|
||||
"accent": "bold color(12)",
|
||||
"selected": "reverse bold color(14)",
|
||||
# Slot 15, the top of the bright bank — so the row's bold cannot promote it
|
||||
# further, and every dim-slot span inside it behaves exactly as it did under the
|
||||
# old bold slot-14 highlight.
|
||||
"cursor": "bold color(15)",
|
||||
"err.reverse": "reverse bold color(9)",
|
||||
"you": "bold color(15)",
|
||||
"device.known": "bold color(15)",
|
||||
|
||||
@@ -890,7 +890,7 @@ class TraceScreen(Screen):
|
||||
|
||||
def _action_text(self, key: str, selected: bool) -> Text:
|
||||
"""One action row: pointer, glyph, and label (current value inlined)."""
|
||||
text = Text("❯ " if selected else " ", style="brand" if selected else "")
|
||||
text = Text("❯ " if selected else " ", style="cursor" if selected else "")
|
||||
if key == "compose":
|
||||
_icon(text, "✎", "brand")
|
||||
text.append("Compose path")
|
||||
@@ -924,7 +924,7 @@ class TraceScreen(Screen):
|
||||
else:
|
||||
text.append("Back")
|
||||
if selected:
|
||||
text.style = "brand"
|
||||
text.style = "cursor"
|
||||
return text
|
||||
|
||||
def _route_value(self, current: Optional[TraceResult], width: int) -> list[Text]:
|
||||
|
||||
@@ -806,7 +806,7 @@ class AutocompleteScreen(_KeylessDialog):
|
||||
self._sugg = max(0, min(self._sugg, len(suggestions) - 1)) if suggestions else 0
|
||||
for i, sug in enumerate(suggestions):
|
||||
is_sel = i == self._sugg
|
||||
row = Text(("❯ " if is_sel else " ") + sug, style="brand" if is_sel else "muted")
|
||||
row = Text(("❯ " if is_sel else " ") + sug, style="cursor" if is_sel else "muted")
|
||||
row.truncate(width)
|
||||
parts.append(row)
|
||||
if self._error:
|
||||
|
||||
@@ -631,7 +631,7 @@ class SelectScreen(Screen):
|
||||
else:
|
||||
label = item.text(max(1, width - 2))
|
||||
pointer = "❯ " if is_sel else " "
|
||||
style = "brand" if is_sel else ""
|
||||
style = "cursor" if is_sel else ""
|
||||
# A Text label carries its own spans (e.g. a red badge); keep them and lay the
|
||||
# row's base style underneath, so the highlight tints the row while the badge
|
||||
# keeps its colour. A plain string is styled uniformly as before.
|
||||
@@ -876,9 +876,9 @@ class ReorderScreen(Screen):
|
||||
for pos, orig in enumerate(self._order):
|
||||
is_cursor = pos == self._index
|
||||
if is_cursor and self._grabbed:
|
||||
pointer, style = "▸ ", "brand"
|
||||
pointer, style = "▸ ", "cursor"
|
||||
elif is_cursor:
|
||||
pointer, style = "❯ ", "brand"
|
||||
pointer, style = "❯ ", "cursor"
|
||||
else:
|
||||
pointer, style = " ", ""
|
||||
text = Text(pointer + self._labels[orig], style=style, no_wrap=True,
|
||||
@@ -888,9 +888,9 @@ class ReorderScreen(Screen):
|
||||
lines.append("")
|
||||
for i, (_key, label) in enumerate(self._actions()):
|
||||
if n + i == self._index:
|
||||
# The cursor row goes full-brand like the list rows above it,
|
||||
# The cursor row takes the highlight like the list rows above it,
|
||||
# trading the ✓/✗ tint for the highlight.
|
||||
text = Text("❯ " + label.plain, style="brand", no_wrap=True)
|
||||
text = Text("❯ " + label.plain, style="cursor", no_wrap=True)
|
||||
else:
|
||||
text = Text(" ", no_wrap=True)
|
||||
text.append_text(label)
|
||||
|
||||
@@ -400,7 +400,7 @@ class TxSweepScreen(Screen):
|
||||
|
||||
def _action_text(self, key: str, selected: bool) -> Text:
|
||||
"""One action row: pointer, glyph, and label (current value inlined)."""
|
||||
text = Text("❯ " if selected else " ", style="brand" if selected else "")
|
||||
text = Text("❯ " if selected else " ", style="cursor" if selected else "")
|
||||
if key == "route":
|
||||
_icon(text, "✎", "brand")
|
||||
if self.route_hops:
|
||||
@@ -430,7 +430,7 @@ class TxSweepScreen(Screen):
|
||||
else:
|
||||
text.append("Back")
|
||||
if selected:
|
||||
text.style = "brand"
|
||||
text.style = "cursor"
|
||||
return text
|
||||
|
||||
def _header_lines(self, width: int) -> list[str]:
|
||||
|
||||
@@ -1230,7 +1230,7 @@ class WalkScreen(Screen):
|
||||
"""One neighbour row: glyph, name, hash, SNR + bar, evidence, onward count."""
|
||||
glyph, glyph_style = self._glyph(other)
|
||||
row = Text()
|
||||
row.append("❯ " if selected else " ", style="brand" if selected else "")
|
||||
row.append("❯ " if selected else " ", style="cursor" if selected else "")
|
||||
row.append(glyph, style=glyph_style)
|
||||
row.append(" ")
|
||||
name_style_ = self._list_name_style(other)
|
||||
@@ -1258,7 +1258,7 @@ class WalkScreen(Screen):
|
||||
if onward:
|
||||
row.append(f" ⋯ {onward}", style="faint")
|
||||
if selected:
|
||||
row.style = "brand"
|
||||
row.style = "cursor"
|
||||
return row
|
||||
|
||||
def _match_row(
|
||||
@@ -1267,7 +1267,7 @@ class WalkScreen(Screen):
|
||||
"""One find match: glyph, name, hash, and how far out it sits."""
|
||||
glyph, glyph_style = self._glyph(node)
|
||||
row = Text()
|
||||
row.append("❯ " if selected else " ", style="brand" if selected else "")
|
||||
row.append("❯ " if selected else " ", style="cursor" if selected else "")
|
||||
row.append(glyph, style=glyph_style)
|
||||
row.append(" ")
|
||||
row.append(fit_cells(self._label(node), name_w), style=self._list_name_style(node))
|
||||
@@ -1283,7 +1283,7 @@ class WalkScreen(Screen):
|
||||
ring = depths[node]
|
||||
row.append(f"{ring} hop{'s' if ring != 1 else ''} out", style="muted")
|
||||
if selected:
|
||||
row.style = "brand"
|
||||
row.style = "cursor"
|
||||
return row
|
||||
|
||||
def _list_name_style(self, node: str) -> str:
|
||||
|
||||
@@ -278,14 +278,14 @@ def test_livefeed_column_header_is_pinned_and_carries_no_sort_cue() -> None:
|
||||
|
||||
|
||||
def test_livefeed_highlight_uses_the_app_wide_cursor() -> None:
|
||||
"""The feed marks its row like every other list: a ``❯`` pointer over a brand row."""
|
||||
"""The feed marks its row like every other list: ``❯`` over a ``cursor``-white row."""
|
||||
screen = _screen(seed=[_obs(node="n0", age_s=1), _obs(node="n1", age_s=0)])
|
||||
screen.handle("down") # off the pin, onto the newest packet normally selected
|
||||
rows = _rows(screen, 100)
|
||||
assert rows[0].startswith("❯ ") and rows[1].startswith(" ")
|
||||
assert "▸" not in "\n".join(rows) # the old odd-one-out mark is gone
|
||||
raw = screen.render_body(100)[2]
|
||||
assert raw.startswith("\x1b[") # the pointer carries the brand style, not bare text
|
||||
assert raw.startswith("\x1b[") # the pointer carries the cursor style, not bare text
|
||||
|
||||
|
||||
def test_livefeed_opens_pinned_and_the_pin_rides_the_newest_packet() -> None:
|
||||
|
||||
@@ -113,7 +113,7 @@ def test_paths_screen_shows_unknown_relay_as_grey_mode_width_hash() -> None:
|
||||
row = next(ln for ln in lines if "e839f2" in _plain([ln]))
|
||||
assert "(e8)" not in _plain([row]) # the mode-width identity stands alone
|
||||
assert "38;2;148;163;184" in row # muted grey over the hash
|
||||
assert "38;2;94;234;212" not in row # never the brand highlight
|
||||
assert not _plain([row]).startswith("❯") # unselected, so no cursor highlight over it
|
||||
graph = _plain(lines).split("origin →")[0]
|
||||
assert "e8" in graph # the row's byte still cross-references the graph label
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ def test_the_cursor_is_a_hop_of_its_own_in_either_mode() -> None:
|
||||
chips = PathLine(hops, mode="powerline").text()
|
||||
assert chips.plain == f" a {POWERLINE_SEP} {CURSOR_GLYPH} {POWERLINE_SEP} b {POWERLINE_SEP}"
|
||||
slot = next(s for s in chips.spans if chips.plain[s.start : s.end] == CURSOR_GLYPH)
|
||||
assert str(slot.style).endswith(f"on {_style_hex('brand')}") # the brand accent fill
|
||||
assert str(slot.style).endswith(f"on {_style_hex('cursor')}") # the cursor-white fill
|
||||
|
||||
|
||||
def test_ellipsized_elides_the_middle_and_keeps_both_endpoints() -> None:
|
||||
|
||||
@@ -102,7 +102,7 @@ def test_unknown_node_grey_survives_a_selected_row() -> None:
|
||||
theme=MESH_THEME_16, width=20, file=StringIO(),
|
||||
force_terminal=True, color_system="standard", highlight=False,
|
||||
)
|
||||
for base in (None, "brand"): # unselected row, then the bold cursor row
|
||||
for base in (None, "cursor"): # unselected row, then the bold cursor row
|
||||
row = Text(" ")
|
||||
row.append("3d", style="node.unknown")
|
||||
if base:
|
||||
|
||||
Reference in new issue
Block a user