diff --git a/CLAUDE.md b/CLAUDE.md index 47182cb..d34210b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -488,15 +488,16 @@ as a grouped list does. Filling a page in is editing its `.md`; no Python follow the star in the chip's dark ink: a yellow star measured under 3:1 on the light fill for 238 of 256 hues, and the star on the page right of the chip was tried and put back (JP, 2026-10-13). A **mention** of us is the turned-over chip with no star - (`mention_chip(you=True)`); the message carrying it gets **the two ends of our chip** - in the two cells left of its time instead — notch then point, no label, in our chip's - fill (`widgets.mention_mark` → `pathline.chip_ends`; `>>` in our hue in arrow mode; - it replaced a `★`, JP 2026-10-13). Every time sits two cells right to keep the column - (`❯`, a space, the mark, then `12:34 body`), and the Messages list puts the mark left - of the row's age. Arrow mode draws the chip as - a padded reverse-video block. The PicoCalc can't put a bright slot behind text, so - there the chip keeps the normal colours and the `★` alone marks us. With no name or key from the device, the bare `★` chip stays. Path lines - (delivery paths, the packet viewer, routes) keep `★`. + (`mention_chip(you=True)`); the message carrying it gets **the point of our chip** + alone, one cell in our chip's fill, left of its time instead (`widgets.mention_mark` → + `pathline.chip_point`; `>` in our hue in arrow mode). It replaced a `★`, and then the + notch-and-point pair, which read as ugly (JP, 2026-10-13). Every time sits two cells + right to keep the column (`❯`, a space, the mark, a space, then `12:34 body`), and the + Messages list puts the mark left of the row's age. Arrow mode draws the chip as a + padded reverse-video block. The PicoCalc can't put a bright slot behind text, so there + the chip keeps the normal colours and the `★` alone marks us. With no name or key from + the device, the bare `★` chip stays. Path lines (delivery paths, the packet viewer, + routes) keep `★`. - **The compose line draws a mention as its chip** (`ui/compose.py`, `MentionEditor`): the moment `]` completes an `@[Name]` token it renders as the same chip the transcript will show, and from then on it is an **atom** — ←/→ step over it, ^←/^→ never stop inside diff --git a/meshterm/tools/chat.py b/meshterm/tools/chat.py index 2771058..92f5c0b 100644 --- a/meshterm/tools/chat.py +++ b/meshterm/tools/chat.py @@ -986,15 +986,15 @@ def _title( text.append(" " * _BADGE_WIDTH) # The relative age lane (right-aligned) is between the badge and the message text. Thus # the ages are in one neat column, and all the previews start at the same position. A - # last message that names us has the ends of our chip at the left of its age, the same - # as the transcript has them at the left of the time (refer to ChatScreen._body_lines). + # last message that names us has the point of our chip at the left of its age, the same + # as the transcript has it at the left of the time (refer to ChatScreen._body_lines). age = _ago(last.created_at) if last is not None else "" lane = f" {age:>{_AGE_WIDTH}}" if age and last is not None and _names_us(last, us): - mark = len(lane) - len(age) - 2 # the two cells of the mark, then the age + mark = len(lane) - len(age) - 2 # the mark, a space, then the age text.append(lane[:mark]) text.append_text(mention_mark(us[1])) - text.append(age, style="muted") + text.append(lane[mark + 1 :], style="muted") else: text.append(lane, style="muted") text.append(" ") @@ -1057,7 +1057,7 @@ def _preview_text( - Our own messages start with our chip, ``★ Name`` turned over (refer to :func:`~meshterm.ui.widgets.self_chip`). A mention of our name has the chip that is - turned over, with no star. A message that names us has the ends of our chip at the + turned over, with no star. A message that names us has the point of our chip at the left of the age of the row (refer to :func:`_title`). - In a received channel message, the inline ``Name:`` sender is the author, in the hue that comes from its key (the node grey when no known node has the name). diff --git a/meshterm/ui/chat.py b/meshterm/ui/chat.py index 0595ca4..8c477ee 100644 --- a/meshterm/ui/chat.py +++ b/meshterm/ui/chat.py @@ -775,9 +775,9 @@ class ChatScreen(Screen): is marked as the reply target (the same as the ``❯`` pointer and the highlight of the select screen). - A message that mentions our name has a mark at the left of its time: the two ends - of our chip, in its colour, with no label (refer to - :func:`~meshterm.ui.widgets.mention_mark`, JP, 2026-10-13). The chip of the mention + A message that mentions our name has a mark at the left of its time: the point of + our chip, in its colour (refer to :func:`~meshterm.ui.widgets.mention_mark`, JP, + 2026-10-13). The chip of the mention in the body is turned over, but it has no star (refer to :func:`~meshterm.ui.widgets.mention_hop`). Thus the mark of a message that names us is in one column, where the eye finds it when it goes down the transcript. Each time @@ -799,6 +799,7 @@ class ChatScreen(Screen): prefix.append("❯ " if selected else " ", style="cursor" if selected else None) if self._names_us(body): prefix.append_text(mention_mark(self._self_key)) + prefix.append(" ") else: prefix.append(" ") prefix.append(f"{stamp:%H:%M} ", style="cursor" if selected else "muted") @@ -855,7 +856,7 @@ class ChatScreen(Screen): Thus the user sees that a mention belongs to the node that it names. The text around the mentions keeps the base style of the line (``cursor`` when the message is the selected reply target, or else no style). A mention of our own name has our - chip, turned over, and the line has the ends of our chip at the left of its time + chip, turned over, and the line has the point of our chip at the left of its time (refer to :meth:`_body_lines`). Thus a message that names us is easy to see. The chip opens on the notch, because the node that a mention names is the diff --git a/meshterm/ui/pathline.py b/meshterm/ui/pathline.py index 4bdd8b7..4fc3b8d 100644 --- a/meshterm/ui/pathline.py +++ b/meshterm/ui/pathline.py @@ -1294,12 +1294,11 @@ def _bind_chips(platform: Platform) -> None: _colours_of, _WEIGHT, _FLAT = _slot_colours, "not bold ", "not bold " -def chip_ends(hop: PathHop) -> Text: - """The two ends of the chip of ``hop`` with no label between them: the notch, then the point. +def chip_point(hop: PathHop) -> Text: + """The point of the chip of ``hop`` alone: one cell in the fill of the chip. - It is two cells in the fill of the chip, the same two cells that open and close a chip - of a destination (refer to :meth:`PathLine._notch`). A chat puts it at the left of the - time of a message that names us, in the fill of our chip (refer to + It is the same cell that closes a chip whose route goes on. A chat puts it at the left + of the time of a message that names us, in the fill of our chip (refer to :func:`~meshterm.ui.widgets.mention_mark`). The colours come from the palette of the platform, so the PicoCalc draws it in the fill that the chip has there. @@ -1307,12 +1306,9 @@ def chip_ends(hop: PathHop) -> Text: hop: The hop whose chip gives the fill. Returns: - The two styled cells. + The one styled cell. """ - fill = _colours_of(hop).fill - text = PathLine._notch(fill) - text.append(POWERLINE_SEP, style=f"{_FLAT}{fill}") - return text + return Text(POWERLINE_SEP, style=f"{_FLAT}{_colours_of(hop).fill}") def _shorten(value: str, hash_bytes: int | None) -> str: diff --git a/meshterm/ui/widgets.py b/meshterm/ui/widgets.py index 77408d9..d73adc7 100644 --- a/meshterm/ui/widgets.py +++ b/meshterm/ui/widgets.py @@ -57,7 +57,7 @@ from .marks import ( LabelRgbOf, parse_hex, ) -from .pathline import SELF_GLYPH, PathHop, PathLine, chip_ends, path_line +from .pathline import SELF_GLYPH, PathHop, PathLine, chip_point, path_line from .termfont import powerline_enabled from .theme import glyph, mark_rgb, name_style, node_style, snr_style @@ -698,8 +698,8 @@ def self_chip(name: str | None, key: str | None, *, role: str | None = None) -> :attr:`~meshterm.ui.pathline.PathHop.inverse`). A mention of our name is a different mark (refer to :func:`mention_chip`). The chip is - turned over, but it has no star. The message that names us has the ends of our chip at - the left of its time (refer to :func:`mention_mark`). + turned over, but it has no star. The message that names us has the point of our chip + at the left of its time (refer to :func:`mention_mark`). Our node with no name or no key (the device did not report them) keeps the bare ``★`` chip of a route. @@ -718,26 +718,26 @@ def self_chip(name: str | None, key: str | None, *, role: str | None = None) -> def mention_mark(key: str | None) -> Text: - """The mark of a message that names us: the two ends of our chip, with no label. + """The mark of a message that names us: the point of our chip, alone. - The notch, then the point, in the fill of our chip (refer to - :func:`~meshterm.ui.pathline.chip_ends`). The chat puts it in the two cells at the left - of the time of each message that mentions our name, and the Messages list puts it at - the left of the age of a row whose last message does (JP, 2026-10-13). It replaced a - ``★``. The mark has the colour of the chip that the mention has in the body, so the eye - joins the two. Where the terminal draws no chips, it is ``>>`` in our hue, the colour - that our chip has there. + One cell in the fill of our chip (refer to :func:`~meshterm.ui.pathline.chip_point`). + The chat puts it at the left of the time of each message that mentions our name, and + the Messages list puts it at the left of the age of a row whose last message does (JP, + 2026-10-13). It replaced a ``★``, and then the notch and the point together, which JP + found too heavy. The mark has the colour of the chip that the mention has in the body, + so the eye joins the two. Where the terminal draws no chips, it is ``>`` in our hue, + the colour that our chip has there. Args: key: Our public key, which gives the hue. With ``None``, the mark has the keyless grey, the same as the chip of the mention. Returns: - The mark, two cells wide. + The mark, one cell wide. The caller puts a space after it. """ if powerline_enabled(): - return chip_ends(PathHop("", key=key or None, inverse=bool(key))) - return Text(">>", style=node_style(key) if key else "node.unknown") + return chip_point(PathHop("", key=key or None, inverse=bool(key))) + return Text(">", style=node_style(key) if key else "node.unknown") def mention_hop(name: str, key: str | None, *, you: bool = False) -> PathHop: diff --git a/tests/test_chat.py b/tests/test_chat.py index af6fecd..ac9daea 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -1624,7 +1624,7 @@ def test_a_mention_of_our_name_takes_our_chip_with_no_star(powerline) -> None: def test_a_message_that_names_us_has_the_mark_left_of_its_time() -> None: """The mark goes in the two cells before the time, and each time moves two cells right. - The suite draws no chips, so the mark is ``>>`` in our hue (refer to the widget tests + The suite draws no chips, so the mark is ``>`` in our hue (refer to the widget tests for the two ends of the chip). """ from datetime import datetime, timezone @@ -1637,12 +1637,12 @@ def test_a_message_that_names_us_has_the_mark_left_of_its_time() -> None: ] screen = _channel_screen(messages, self_name="Me", self_key=_OUR_KEY) rows = _strip_ansi("\n".join(screen._render_grouped(72))).splitlines() - assert any(row.startswith(f" >>{stamp} hi") for row in rows) + assert any(row.startswith(f" > {stamp} hi") for row in rows) assert any(row.startswith(f" {stamp} hi") for row in rows) # the other message screen.handle("up") screen.handle("up") # the first message: the pointer, then the mark rows = _strip_ansi("\n".join(screen._render_grouped(72))).splitlines() - assert any(row.startswith(f"❯ >>{stamp} hi") for row in rows) + assert any(row.startswith(f"❯ > {stamp} hi") for row in rows) def _channel_screen( @@ -1766,7 +1766,7 @@ def test_a_row_whose_last_message_names_us_has_the_mark_left_of_its_age( lanes = _lanes([conv]) marked = _title(ctx, conv, {"chan:c0": named}, _NO_KEYS, lanes, us=us).plain plain = _title(ctx, conv, {"chan:c0": other}, _NO_KEYS, lanes, us=us).plain - assert ">>now " in marked and ">>" not in plain + assert "> now " in marked and ">" not in plain assert marked.index("now") == plain.index("now") # the mark takes the cells of the gap diff --git a/tests/test_widgets.py b/tests/test_widgets.py index 3e83b50..b38c7eb 100644 --- a/tests/test_widgets.py +++ b/tests/test_widgets.py @@ -399,23 +399,22 @@ def test_a_mention_of_us_is_turned_over_with_no_star(powerline) -> None: assert not mention_hop("Me", None, you=True).inverse # no key: no hue to turn over -def test_the_mark_of_a_message_that_names_us_is_the_ends_of_our_chip(powerline) -> None: - """The notch, then the point, in the fill of our chip, and no label between them.""" +def test_the_mark_of_a_message_that_names_us_is_the_point_of_our_chip(powerline) -> None: + """One cell: the point, in the fill of our chip.""" powerline(True) mark = mention_mark("5e7f") fill = _span_style(mention_chip("Me", "5e7f", you=True), "Me").bgcolor.name - assert mark.plain == POWERLINE_SEP * 2 - notch, point = (Style.parse(str(span.style)) for span in mark.spans) - assert notch.reverse and notch.color.name == fill # cut out of the fill - assert not point.reverse and point.color.name == fill # the point of the fill + assert mark.plain == POWERLINE_SEP + point = Style.parse(str(mark.style)) + assert not point.reverse and point.color.name == fill -def test_the_mark_without_chips_is_two_arrows_in_our_hue(powerline) -> None: - """With no chips, the mark is ``>>``, in the hue that our chip has in arrow mode.""" +def test_the_mark_without_chips_is_an_arrow_in_our_hue(powerline) -> None: + """With no chips, the mark is ``>``, in the hue that our chip has in arrow mode.""" powerline(False) mark = mention_mark("5e7f") - assert mark.plain == ">>" and str(mark.style) == node_style("5e7f") + assert mark.plain == ">" and str(mark.style) == node_style("5e7f") assert str(mention_mark(None).style) == "node.unknown"