From fae342c2bd0480062800625bc3f4964da7a8af14 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Tue, 25 Aug 2026 01:47:52 -0400 Subject: [PATCH] Updated splash screen (ANSI art, CP437) --- meshterm/assets/logo_53.ans | Bin 2095 -> 2026 bytes meshterm/ui/logo.py | 46 ++++++++++++++++++++++++++++++++++-- tests/test_theme16.py | 33 ++++++++++++++++---------- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/meshterm/assets/logo_53.ans b/meshterm/assets/logo_53.ans index 7b2207b802a117507acfe4d9a1301ea3827707a7..3714c13c9fbc1fec326c1b3e1d8d0c48f9452c89 100644 GIT binary patch delta 213 zcmZ24@QQze#Kd`=6P4^I&f}e!uQzd?9f98EcTvBVloG_;bbf39w5!bZ=QSqzI3#)LGDQ)X`VazF|)yB z5tg*c)hw!$7qS>nE@Ty+{DP$&$QGI0#wN@HRHHC?6|33ghpY#sZc9fSS{s|@-nj!Z v!rH_jch`xtd!(Zcawnf-6Px^$&6N+V!XOtWY{h<_J(Hb*ff49j0SuO%`Xgn;gPuGr6D9dh$s|TV{h?g~{(2 z6(@HyDNi{1J2`+=Wb#QC{>jT&1c1CiR$(Bo9W1WRFCA@QZETpUARTRJZET)9xti5% z@@!Vl$vathI!H$w8(NzHodIMRSeuyU-Uh2O&AoF6B4Uuc>%`eTKqGP$6d)!T list[str]: return rows +def _state_intensity(row: str) -> str: + """Rewrite the row's colour changes so every one says whether it is bright. + + An art editor spells brightness the DOS way — ``1m`` lifts the bank and each span after + it inherits that — which reads correctly only while the escapes stay one unbroken + stream. They don't here: a row is handed to Rich on its own, and the console draws bold + *as* the bright bank, so a span that never mentions intensity is read against whatever + happened to be set. Saying it outright changes no colour; it just stops one drifting. + """ + out: list[str] = [] + bright = False + at = 0 + while at < len(row): + found = _SGR.match(row, at) + if not found: + out.append(row[at]) + at += 1 + continue + params = found.group()[2:-1] + parts = params.split(";") if params else [""] + for part in parts: # what this sequence leaves the intensity set to + if part in ("", "0", "22"): + bright = False + elif part == "1": + bright = True + if any(_DIM_FG.fullmatch(p) for p in parts) and not any(p in _SAYS_INTENSITY for p in parts): + out.append("\x1b[" + ";".join(["1" if bright else "22"] + parts) + "m") + else: + out.append(found.group()) + at = found.end() + return "".join(out) + + def _rows(name: str) -> list[str]: """The named mark's rows, or ``[]`` when it can't be read.""" try: @@ -133,8 +175,8 @@ def _rows(name: str) -> list[str]: if lines and lines[-1] == "": # drop the trailing newline's empty row lines.pop() if width: - return [row for line in lines for row in _rewrap(line, width)] - return lines + lines = [row for line in lines for row in _rewrap(line, width)] + return [_state_intensity(row) for row in lines] def logo_width(rows: list[str]) -> int: diff --git a/tests/test_theme16.py b/tests/test_theme16.py index 059504b..44c1e46 100644 --- a/tests/test_theme16.py +++ b/tests/test_theme16.py @@ -375,14 +375,16 @@ def test_specimen_renders_clean_on_picocalc() -> None: assert ord(ch) in FONT_CODEPOINTS, f"line {i} char {ch!r} outside the font" -def test_narrow_wordmark_keeps_its_dim_row_off_the_bright_bank() -> None: - """Every span of the wordmark's dim-slot row states its intensity. +def test_narrow_wordmark_keeps_its_dim_rows_off_the_bright_bank() -> None: + """Every dim-bank span of the wordmark states its own intensity. - The mark alternates letter blocks with slate bevels, so a row painted on the dim bank - is a run of ``3N`` spans each following a ``90``. Bare, they inherit the console's - intensity bit and half the row renders a bank too bright — the narrow mark's fourth - row came out part red (slot 1), part light red (slot 9), split at every span that - followed a bevel. + An art editor spells brightness the DOS way — a ``1m`` lifts the bank and every span + after it inherits that — which only reads correctly while the escapes stay one unbroken + stream. A row reaches the console on its own, and bold *is* the bright bank there, so a + span that never mentions intensity is read against whatever happened to be set: the + narrow mark's letter row came out part red (slot 1), part light red (slot 9), splitting + at every span that followed a bevel. The art is redrawn from time to time, so this + pins the rule rather than the picture — no row index, no particular colour. """ from meshterm.ui.logo import load_logo from meshterm.ui.tui.frame import _banner_lines @@ -390,12 +392,17 @@ def test_narrow_wordmark_keeps_its_dim_row_off_the_bright_bank() -> None: set_platform(PICOCALC) rows = _banner_lines(load_logo(53), 53) assert rows, "the 53-column mark should fit a 53-column console" - for i, row in enumerate(rows): - for sgr in re.findall(r"\x1b\[([0-9;]*)m", row): - assert not re.fullmatch(r"3[0-7]", sgr), f"bare dim-bank SGR on row {i}: {row!r}" - # The fourth row is the mark's only dim-slot row, and it is one colour throughout. - reds = set(re.findall(r"\x1b\[([0-9;]+)m(?=█)", rows[3])) - assert reds == {"22;31"}, reds + dim = [ + sgr + for row in rows + for sgr in re.findall(r"\x1b\[([0-9;]*)m", row) + if any(re.fullmatch(r"3[0-7]", part) for part in sgr.split(";")) + ] + # Without this the loop below would pass on a mark that never touches the dim bank. + assert dim, "the mark paints on the dim bank somewhere, or this check says nothing" + for sgr in dim: + parts = sgr.split(";") + assert any(p in {"0", "1", "2", "22"} for p in parts), f"unstated intensity: {sgr!r}" # -- relocated marks stay importable from their old homes -----------------------------