From 72fc0665c5ee0f8cb164859c667b67d729925194 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Sat, 12 Sep 2026 13:38:40 -0400 Subject: [PATCH] A record's header reads as a sentence, and the bar says only Record MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "🛣 Longest distance — 5th place: 112.0 km": the discipline written the way its board heading writes it — discipline_label, the mark padded to the measured lane so a one-cell 🛣 and a two-cell 🎯 start their titles in the same cell — then the standing and the metric. The bare mark-and-number it replaces was dry, and it had to lean on the title bar for the discipline; now the header names the record and the bar names the kind of page. Co-Authored-By: Claude Fable 5.1 --- meshterm/ui/records_screen.py | 29 +++++++++++++++++--------- tests/test_records_screen.py | 38 +++++++++++++++++++++++------------ 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/meshterm/ui/records_screen.py b/meshterm/ui/records_screen.py index fa0fd12..b54cd86 100644 --- a/meshterm/ui/records_screen.py +++ b/meshterm/ui/records_screen.py @@ -150,6 +150,12 @@ def discipline_lane() -> int: return max(cell_len(glyph(category.icon)) for category in CATEGORIES) +def _ordinal(n: int) -> str: + """``1 → "1st"``, ``2 → "2nd"``, ``11 → "11th"``, … for a record's standing.""" + suffix = {1: "st", 2: "nd", 3: "rd"}.get(n if n < 20 else n % 10, "th") + return f"{n}{suffix}" + + def record_score(category: Category, record: DiscoveredPath) -> str: """A record's score in its discipline's unit, bounded where the walk was partial. @@ -278,7 +284,10 @@ class RecordScreen(Screen): (``▲`` repeater, …) on the graph; ``None`` falls back to generic dots. """ super().__init__() - self.title = f"Record — {category.title} #{rank}" + # The bar says what kind of page this is; the header line under it names the + # record — its discipline, its standing, its metric. + self.title = "Record" + self._rank = rank self._record = record self._category = category self._resolve = resolve @@ -403,16 +412,18 @@ class RecordScreen(Screen): return self._cursor if self._follow else None def _header(self) -> Text: - """The one-line identity above the strip: the discipline's mark, then the metric. + """The one-line identity above the strip: the discipline, the standing, the metric. - The record page's counterpart to the node page's identity header. The mark is the - discipline's own (the same one its board heading wears), the metric is the score in - the discipline's unit (:func:`record_score`), and that is the whole line: the - title bar already names the discipline and the standing, so the header spends its - cells on the one thing the record *is* — its number. + The record page's counterpart to the node page's identity header, read as one + sentence — ``🛣 Longest distance — 5th place: 112.0 km``. The discipline is written + the way its board heading writes it (:func:`discipline_label`, the mark padded to + the measured lane so ``🛣`` and ``🎯`` start their titles in the same cell), the + standing is the record's rank on that board, and the metric is the score in the + discipline's unit (:func:`record_score`). The title bar says only ``Record``: this + line is where the record is named. """ - line = Text(glyph(self._category.icon)) - line.append(" ") + line = Text(discipline_label(self._category, discipline_lane())) + line.append(f" — {_ordinal(self._rank)} place: ", style="muted") line.append(record_score(self._category, self._record), style="accent bold") return line diff --git a/tests/test_records_screen.py b/tests/test_records_screen.py index 4c11ad2..3bf690e 100644 --- a/tests/test_records_screen.py +++ b/tests/test_records_screen.py @@ -189,8 +189,12 @@ def test_record_graph_collapses_a_revisited_route_to_distinct_nodes() -> None: def test_record_dialog_title_names_the_discipline_and_rank() -> None: - """The title uses the plain discipline name and the board standing.""" - assert _dialog(_record(), rank=3).title == "Record — Most nodes #3" + """The bar says only what kind of page this is; the header line names the record.""" + screen = _dialog(_record(), rank=3) + assert screen.title == "Record" + assert ( + _plain(screen.render_body(60)).splitlines()[0].endswith("Most nodes — 3rd place: 2 nodes") + ) def test_record_dialog_marks_incomplete_distance_as_a_lower_bound() -> None: @@ -340,31 +344,39 @@ def test_record_opens_on_info_with_route_and_area_tabs_beside_it() -> None: assert "Far" in "\n".join(body) # the far-point name is a stat, not a drawing label -def test_record_header_is_the_disciplines_mark_and_the_metric_above_the_strip() -> None: - """One line above the tabs: the discipline's own mark, then the score in its unit. +def test_record_header_names_the_discipline_the_standing_and_the_metric() -> None: + """One line above the tabs: `` — place: ``. - The node page's identity header, for a record: the title bar names the discipline - and the standing, so the header spends its cells on the number the record *is* — - and the score lane that used to repeat it on Info is gone. + The node page's identity header, for a record. The discipline is written the way its + board heading writes it — the mark padded to the measured lane, so a one-cell ``🛣`` + and a two-cell ``🎯`` start their titles in the same cell — and the score lane that + used to repeat the metric on Info is gone. """ - from meshterm.ui.theme import glyph + from meshterm.ui.records_screen import discipline_label, discipline_lane screen = _dialog(_record(), shape=_loop_shape()) lines = _plain(screen.render_body(58)).splitlines() - mark = glyph(CATEGORY_BY_ID["grand_tour"].icon) - assert lines[0] == f"{mark} 2 nodes" # the very first row, before the strip's air + grand_tour = CATEGORY_BY_ID["grand_tour"] + expected = f"{discipline_label(grand_tour, discipline_lane())} — 1st place: 2 nodes" + assert lines[0] == expected # the very first row, before the strip's air assert "score" not in _plain(screen.render_body(58)) for _ in range(3): # the header stays put whichever tab is up screen.handle("tab") - assert _plain(screen.render_body(58)).splitlines()[0] == f"{mark} 2 nodes" + assert _plain(screen.render_body(58)).splitlines()[0] == expected partial = _record( category="long_haul", score=8.4, stats={"km_travelled": 8.4, "km_complete": False, "hop_count": 3, "distinct_nodes": 3}, ) - head = _plain(_dialog(partial).render_body(58)).splitlines()[0] - assert head.endswith("≥ 8.4 km") # the board's bounded spelling, and no other + head = _plain(_dialog(partial, rank=5).render_body(58)).splitlines()[0] + assert head.endswith("Longest distance — 5th place: ≥ 8.4 km") # the board's bounded spelling + + # The mark lane is the board heading's: the two marks' titles start in one cell. + long_haul = CATEGORY_BY_ID["long_haul"] + assert cell_len(discipline_label(long_haul, discipline_lane()).split("Longest")[0]) == cell_len( + discipline_label(grand_tour, discipline_lane()).split("Most")[0] + ) def test_record_route_tab_draws_the_walk_and_enter_traces_it() -> None: