In a chat, our sender chip has its star inside again

Our messages go under "★ Name" on the turned-over chip, as before the last
change. A mention of us keeps its chip without a star, and its message
keeps the star at the left of the time.

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-13 22:28:47 -04:00
1 parent 8043881d3c
commit 427bee836b
8 files changed
+51 -67

No files matched your search

+7 -7
View File
@@ -12,13 +12,13 @@ can change how things behave. It does not only add new things.
### Changed
- **In a chat, your messages show your name.** A channel, a direct chat, and a room put
your messages under your node's name, with a `★` after it, and the Messages list shows
them in the same way. Your name has the colour of your key, but in reverse: dark text on
a light fill, where each other sender has light text on a dark fill. A mention of your
name has the same reversed colours, and the message that has it gets a `★` at the left
of its time. Thus the messages that name you are easy to find down the left side of the
chat. On the PicoCalc, the console cannot draw a light fill, so there the `★` alone
marks you. Before, your messages showed only the `★`.
your messages under `★` and your node's name, and the Messages list shows them in the
same way. Your name has the colour of your key, but in reverse: dark text on a light
fill, where each other sender has light text on a dark fill. A mention of your name has
the same reversed colours, and the message that has it gets a `★` at the left of its
time. Thus the messages that name you are easy to find down the left side of the chat.
On the PicoCalc, the console cannot draw a light fill, so there the `★` alone marks you.
Before, your messages showed only the `★`.
- **A mention has no `@` in front of it.** The coloured box around the name already says
that it is a mention. On a terminal that cannot draw the boxes, a mention keeps its `@`.
- **The line where you write a message shows each mention as a box.** When you type the
+9 -10
View File
@@ -484,16 +484,15 @@ as a grouped list does. Filling a page in is editing its `.md`; no Python follow
but a chat is a conversation between names, so our sender chip and every mention of our
name wear our name on the chip of *our key's hue, turned over* — dark ink on a light
fill of the hue (`PathHop.inverse`, the same pair as any chip in the other order), the
one light chip among the senders. **The `★` never sits inside that chip** (a yellow star
measured under 3:1 on the light fill for 238 of 256 hues, and in the chip's dark ink it
read as part of the name; JP, 2026-10-13): our sender chip is `Name ★`, the map's
yellow star on the page one cell right of the chip (`widgets.self_chip`); a mention of
us is the turned-over chip alone (`mention_chip(you=True)`), and the message carrying
it gets the `★` in the two cells left of its time (`❯ ★ 12:34 body` — every time sits
two cells right to keep the column; the Messages list puts it 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
one light chip among the senders. Our **sender** chip is `★ Name` (`widgets.self_chip`),
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 `★` in the two cells left
of its time instead (`❯ ★ 12:34 body` — every time sits two cells right to keep the
column; the Messages list puts it 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
+4 -4
View File
@@ -1055,10 +1055,10 @@ def _preview_text(
It is the same as the live transcript:
- Our own messages start with our name on a chip that is turned over, with the ``★``
after it (refer to :func:`~meshterm.ui.widgets.self_chip`). A mention of our name
has the chip that is turned over, with no star. The star of a message that names us
is at the left of the age of the row (refer to :func:`_title`).
- 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. The star of a message that names us is 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).
- A room post starts with its author, named by key in the same way as the room screen
+3 -4
View File
@@ -729,10 +729,9 @@ class ChatScreen(Screen):
chip of a path line (refer to :func:`~meshterm.ui.widgets.name_chip`). Thus a
sender looks exactly like that node as a hop in a route.
Our messages are the exception. They go under our name, on a chip that is turned
over, with the ``★`` to the right of the chip (refer to
:func:`~meshterm.ui.widgets.self_chip`). A route shows our end as the bare ``★``,
but a chat is a conversation between names.
Our messages are the exception. They go under our name, as ``★ Name`` on a chip
that is turned over (refer to :func:`~meshterm.ui.widgets.self_chip`). A route
shows our end as the bare ``★``, but a chat is a conversation between names.
Our chip comes from the direction of the message (``outbound``), not from the
``"you"`` label. Thus a remote sender with the name ``you`` still gets the hue of
its key, and does not look like our node.
+3 -3
View File
@@ -146,9 +146,9 @@ def specimen_lines() -> list[RenderableType]:
# notch, because the node that it names is where the message goes, and it has no ``@``.
# The path line's own segment draws them, so this row is also a one-hop sample of the
# route language: the hue in the fill and the keyless grey for a node that nobody can
# identify. Our own messages go under ``me``, on the one chip that is turned over (dark
# on a light fill of our hue), with the ``★`` after it. The console of the PicoCalc has
# no light background, so there only the star marks it.
# identify. Our own messages go under ``★ me``, on the one chip that is turned over
# (dark on a light fill of our hue). The console of the PicoCalc has no light
# background, so there only the star marks it.
chips = Text("chips ")
for name, key in _DEMO_NAMES[:2]:
chips.append_text(name_chip(name, key, role=ORIGIN))
+9 -13
View File
@@ -684,17 +684,17 @@ def name_chip(
def self_chip(name: str | None, key: str | None, *, role: str | None = None) -> Text:
"""Our node as the sender in a chat: ``Name ★``, a chip that is turned over, then the star.
"""Our node as the sender in a chat: ``★ Name``, on the chip of our key, turned over.
A chat (a channel, a direct chat, a room) names each sender, and our node too. A route
shows our end as the bare ``★``, because the user never has to be told who that is. A
chat is a conversation between names, so our messages go under our name (JP,
2026-10-13). Two things make it different from the name of each other node. The chip
is turned over: the other senders are a light hue on a dark fill, and ours is dark on a
light fill of our hue. Also, the ``★`` of the app is on the page to the right of the
chip, in the yellow of the map (JP, 2026-10-13). In the chip, the star had the dark
ink of the chip. The console of the PicoCalc cannot draw a light background, so there
the chip keeps the colours of each other chip and the star alone marks us (refer to
2026-10-13). Two things make it different from the name of each other node. The ``★``
of the app comes first, in the dark ink of the chip. Also, the chip is turned over: the
other senders are a light hue on a dark fill, and ours is dark on a light fill of our
hue. A star on the page to the right of the chip was tried, and JP put it back in the
chip (2026-10-13). The console of the PicoCalc cannot draw a light background, so
there the chip keeps the colours of each other chip and the ``★`` marks us (refer to
:attr:`~meshterm.ui.pathline.PathHop.inverse`).
A mention of our name is a different mark (refer to :func:`mention_chip`). The chip is
@@ -710,15 +710,11 @@ def self_chip(name: str | None, key: str | None, *, role: str | None = None) ->
role: :data:`ORIGIN`, :data:`DESTINATION`, or ``None``, as for :func:`name_chip`.
Returns:
The chip and the star as a one-line :class:`Text`.
The chip as a one-line :class:`Text`.
"""
if not name or not key:
return name_chip("", you=True, role=role)
line = Text()
line.append_text(hop_chip(PathHop(name, key=key, inverse=True), role=role))
line.append(" ")
line.append(SELF_MARK[0], style="type.you")
return line
return hop_chip(PathHop(f"{SELF_GLYPH} {name}", key=key, inverse=True), role=role)
def mention_hop(name: str, key: str | None, *, you: bool = False) -> PathHop:
+11 -12
View File
@@ -448,9 +448,8 @@ def test_preview_prefixes_own_messages_only() -> None:
assert _preview_text(dm_in, _NO_KEYS).plain == "hey"
mine = ChatMessage(text="yo", outbound=True, is_channel=True, channel_idx=0)
assert _preview_text(mine, _NO_KEYS).plain == "you: yo" # our node with no name
# With our name, the preview shows our chat chip (a padded block in reverse video),
# then the star.
assert _preview_text(mine, _NO_KEYS, us=("Me", _OUR_KEY)).plain == " Me ★ yo"
# With our name, the preview shows our chat chip: a padded block in reverse video.
assert _preview_text(mine, _NO_KEYS, us=("Me", _OUR_KEY)).plain == " ★ Me yo"
def test_preview_colours_channel_sender_and_mentions() -> None:
@@ -475,9 +474,9 @@ def test_preview_draws_the_author_and_the_mentions_as_the_transcript_does(powerl
"""With chips, the author closes on the point and a mention opens on the notch.
The point says what the colon said, so the chip has no colon, and a mention chip has
no ``@``. Our own author is our name and then the ``★``, as the sender chip of our
messages in the transcript. A mention of our name has no star. With no name for our
node, the bare ``★`` stays.
no ``@``. Our own author is ``★ Name``, as the sender chip of our messages in the
transcript. A mention of our name has no star. With no name for our node, the bare
``★`` stays.
"""
from meshterm.ui.pathline import POWERLINE_ROUND_CLOSE, POWERLINE_ROUND_OPEN, POWERLINE_SEP
@@ -489,7 +488,7 @@ def test_preview_draws_the_author_and_the_mentions_as_the_transcript_does(powerl
mine = ChatMessage(text="yo", outbound=True, is_channel=True, channel_idx=0)
assert _preview_text(mine, _NO_KEYS).plain == f"{POWERLINE_ROUND_OPEN} ★ {POWERLINE_SEP} yo"
us = ("Me", _OUR_KEY)
ours = f"{POWERLINE_ROUND_OPEN} Me {POWERLINE_SEP} ★ yo"
ours = f"{POWERLINE_ROUND_OPEN} ★ Me {POWERLINE_SEP} yo"
assert _preview_text(mine, _NO_KEYS, us=us).plain == ours
named = ChatMessage(text="Bob: hi @[Me]", is_channel=True, channel_idx=0)
me = POWERLINE_SEP + " Me " + POWERLINE_ROUND_CLOSE
@@ -1222,8 +1221,8 @@ def test_channel_transcript_groups_by_sender() -> None:
rendered = _strip_ansi("\n".join(screen._render_grouped(80)))
assert rendered.count("Alice") == 1 # the two Alice messages share one header
# The header of our group is our name, then the ★ (JP, 2026-10-13), not the bare ★.
assert "Bob" in rendered and " Me ★" in rendered
# The header of our group is our name after the ★ (JP, 2026-10-13), not the bare ★.
assert "Bob" in rendered and "★ Me" in rendered
assert "hi" in rendered and "again" in rendered # the bodies are there, without the prefix
assert "Alice: hi" not in rendered # the raw name prefix moved into the header
# Each message keeps its own timestamp on its line, also when grouped under one sender.
@@ -1529,7 +1528,7 @@ def test_channel_self_style_keyed_on_concept_not_label() -> None:
theirs = ChatMessage(text="you: hi", is_channel=True, channel_idx=0)
mine = _channel_screen([], self_name="Me", self_key=_OUR_KEY)
turned = f"{node_style(_OUR_KEY)} reverse"
assert _ink(mine._group_header("you", ours), " Me ") == turned # our name, turned over
assert _ink(mine._group_header("you", ours), " ★ Me ") == turned # our name, turned over
screen = _channel_screen([])
assert _ink(screen._group_header("you", ours), "★") == "you" # no name: the white star
assert _ink(screen._group_header("you", theirs), "you") == "node.unknown" # no key: grey
@@ -1550,8 +1549,8 @@ def test_channel_own_messages_do_not_merge_with_remote_namesake() -> None:
screen = _channel_screen(messages, self_name="Me", self_key=_OUR_KEY)
rendered = _strip_ansi("\n".join(screen._render_grouped(80)))
# Two headers, and they are not only apart: theirs is the name that they sent, ours is
# our name, then the ★.
assert rendered.count("you") == 1 and rendered.count(" Me ★") == 1
# our name after the ★.
assert rendered.count("you") == 1 and rendered.count("★ Me") == 1
def test_a_blank_line_closes_each_author_where_the_rows_allow(
+5 -14
View File
@@ -352,7 +352,7 @@ def test_name_chip_draws_us_as_the_star_never_as_our_name(powerline) -> None:
def test_self_chip_is_the_chip_of_our_key_turned_over(powerline) -> None:
"""In a chat, our messages go under our name, dark on a light fill of our hue.
"""In a chat, our messages go under ``★ Name``, dark on a light fill of our hue.
The two colours are those of the chip of our key, in the other order. Thus the contrast
stays the same, and it is the one light chip among the senders (JP, 2026-10-13).
@@ -361,27 +361,18 @@ def test_self_chip_is_the_chip_of_our_key_turned_over(powerline) -> None:
ours = self_chip("Me", "5e7f", role=ORIGIN)
theirs = name_chip("Me", "5e7f", role=ORIGIN)
ink, normal = _span_style(ours, "Me"), _span_style(theirs, "Me")
assert "★ Me" in ours.plain # the star in the chip, in its dark ink
ink, normal = _span_style(ours, "★ Me"), _span_style(theirs, "Me")
assert (ink.color.name, ink.bgcolor.name) == (normal.bgcolor.name, normal.color.name)
def test_self_chip_puts_the_star_on_the_page_after_the_chip(powerline) -> None:
"""The ``★`` is to the right of our chip, in the yellow of the map (JP, 2026-10-13)."""
powerline(True)
ours = self_chip("Me", "5e7f", role=ORIGIN)
assert ours.plain == name_chip("Me", "5e7f", role=ORIGIN).plain + " ★"
star = next(s for s in ours.spans if ours.plain[s.start : s.end] == "★")
assert str(star.style) == "type.you" # the yellow of the map, on the page
def test_self_chip_is_a_block_in_reverse_video_without_powerline(powerline) -> None:
"""With no chips, our name is still dark on the hue of our key, padded as a chip is."""
powerline(False)
chip = self_chip("Me", "5e7f")
assert chip.plain == " Me ★"
style = _span_style(chip, " Me ")
assert chip.plain == " ★ Me "
style = _span_style(chip, " ★ Me ")
assert style.reverse and style.color.name == node_style("5e7f").removeprefix("bold ")