Files
Jean-Pierre MartineauandClaude Opus 5.5 981f4527e9 Docstrings and comments of the path line, theme, and font modules are in ASD-STE100
pathline.py, theme.py, termfont.py, fontset.py, widgets.py, and oklab.py.
These were done last, after the path chip work in them was committed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 21:36:49 -04:00

138 lines
8.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPDX-License-Identifier: Apache-2.0
"""The glyph inventories of the handhelds. They are the glyph contract.
The PicoCalc display draws through the kernel console with one 512-glyph PSF font
(``meshterm.psf.gz``, built by ``scripts/picocalc-lyra/calculinux-console-font-6x12.sh``).
The font has these parts: the stock Terminus 6×12 base (a table that covers Cyrillic,
which has **no accented Latin letters**), the full braille block, the marks of MeshTerm
that are drawn into donor slots, and a few aliases. The display shows a character that is
not in this set as a blank. Thus MeshTerm must never send a character that is not in the
set on the picocalc-lyra platform. The render boundary folds the text down to the set
(:func:`meshterm.ui.theme.fold_text`), and the dual-platform gallery test makes sure that
the fold held.
This table is the only source of truth for that contract. The fold at run time and the
tests share it. It copies the font that is installed on the handheld. The base inventory
was dumped from the Unicode table of the PSF on the handheld (2026-08-01). The table has
no donor codepoints that the build script now uses for other glyphs, and it has the marks
that the script draws in their place. If the ``MARKS``, ``DONORS``, or ``ALIASES`` of the
build script change, this table must change in the same commit. The reverse is also true.
The Cardputer Zero has its own contract, :data:`CARDPUTER_ZERO_CODEPOINTS`. It is what
the console host draws, and no kernel limits it. :data:`FONTS` names both contracts, for
``Platform.font``.
"""
from __future__ import annotations
#: Inclusive ``(first, last)`` codepoint ranges that are in the font. There are 519
#: codepoints for 512 glyphs, because aliases (the rounded corners onto the square ones,
#: ``⋯`` onto ``…``) and shared slots give a few glyphs more than one codepoint. We
#: checked this table against a dump of the table of the installed font (2026-08-01,
#: post-P3 build). On 2026-10-06, the two powerline chevrons of the path chips (U+E0B0,
#: U+E0B1) took the donor slots of U+2559 and U+255B. The same day, a dump of the font
#: that is installed on the Lyra was exactly the same as this table.
# fmt: off
FONT_RANGES: tuple[tuple[int, int], ...] = (
(0x0020, 0x007F), (0x00A0, 0x00A0), (0x00A7, 0x00A7), (0x00A9, 0x00A9),
(0x00B0, 0x00B0), (0x00B2, 0x00B2), (0x00B6, 0x00B7), (0x03C0, 0x03C0),
(0x0401, 0x0401),
(0x0404, 0x0404), (0x0406, 0x0407), (0x0410, 0x044F), (0x0451, 0x0451),
(0x0454, 0x0454), (0x0456, 0x0457), (0x0490, 0x0491), (0x2014, 0x2014),
(0x2022, 0x2022), (0x2026, 0x2026), (0x2190, 0x2195), (0x21A8, 0x21A8),
(0x21BB, 0x21BB), (0x21E7, 0x21E7), (0x221A, 0x221A), (0x221F, 0x221F),
(0x2248, 0x2248), (0x2264, 0x2265), (0x22EF, 0x22EF), (0x2302, 0x2302),
(0x2316, 0x2316), (0x232B, 0x232B), (0x2500, 0x2500), (0x2502, 0x2502),
(0x250C, 0x250C), (0x2510, 0x2510), (0x2514, 0x2514), (0x2518, 0x2518),
(0x251C, 0x251C), (0x2524, 0x2524), (0x252C, 0x252C), (0x2534, 0x2534),
(0x253C, 0x253C), (0x2550, 0x2551), (0x2554, 0x2554), (0x2557, 0x2557),
(0x255A, 0x255A),
(0x255D, 0x2561), (0x2563, 0x2563), (0x2566, 0x256A), (0x256C, 0x2570),
(0x2580, 0x2580), (0x2584, 0x2584), (0x2588, 0x2588), (0x258C, 0x258C),
(0x2590, 0x2593), (0x25A0, 0x25A0), (0x25AC, 0x25AC), (0x25B2, 0x25B2),
(0x25B6, 0x25B6), (0x25B8, 0x25B8), (0x25BA, 0x25BA), (0x25BC, 0x25BC),
(0x25C0, 0x25C0), (0x25C4, 0x25C4), (0x25C9, 0x25C9), (0x25CB, 0x25CB),
(0x25CF, 0x25CF), (0x25F7, 0x25F7), (0x2605, 0x2605), (0x263C, 0x263C),
(0x2699, 0x2699), (0x26A0, 0x26A0), (0x26BF, 0x26BF), (0x2713, 0x2713),
(0x2717, 0x2717), (0x276F, 0x276F), (0x2800, 0x28FF), (0xE0B0, 0xE0B1),
(0xFFFD, 0xFFFD),
)
# fmt: on
#: All the codepoints that the console font can draw, as one frozen set. MeshTerm builds
#: it one time, at import. It has 519 members, so it is small, and the membership test for
#: each character is a fast hash lookup.
FONT_CODEPOINTS: frozenset[int] = frozenset(
cp for first, last in FONT_RANGES for cp in range(first, last + 1)
)
def in_font(char: str) -> bool:
"""Check if the console font has a glyph for ``char``."""
return ord(char) in FONT_CODEPOINTS
#: The inventory of the Cardputer Zero. It is what its emulator draws
#: (:mod:`meshterm.emulator.font`): the 12-pixel face of Terminus 4.49 with all its 1,356
#: glyphs, with the marks of MeshTerm drawn over it, and ``⋯`` as an alias of the
#: ellipsis, as on the PicoCalc. There is no 512-glyph limit here, so braille, the
#: powerline chevrons, and accented Latin are all present. The table comes from
#: ``ter-u12n.bdf`` plus the ``MARKS`` and ``ALIASES`` of the host. If either of them
#: changes, this table must change in the same commit. ``tests/test_emulator.py`` checks
#: the marks, and it checks the font itself where the font is installed.
# fmt: off
CARDPUTER_RANGES: tuple[tuple[int, int], ...] = (
(0x0020, 0x007E), (0x00A0, 0x017F), (0x0186, 0x0186), (0x018E, 0x0190),
(0x0192, 0x0192), (0x019D, 0x019E), (0x01B5, 0x01B7), (0x01CD, 0x01D4),
(0x01E2, 0x01F0), (0x01F4, 0x01F5), (0x01FC, 0x01FF), (0x0218, 0x021B),
(0x0232, 0x0233), (0x0237, 0x0237), (0x0254, 0x0254), (0x0258, 0x0259),
(0x025B, 0x025B), (0x0272, 0x0272), (0x0292, 0x0292), (0x02BB, 0x02BD),
(0x02C6, 0x02C7), (0x02D8, 0x02D9), (0x02DB, 0x02DD), (0x0300, 0x0308),
(0x030A, 0x030C), (0x0329, 0x0329), (0x0384, 0x038A), (0x038C, 0x038C),
(0x038E, 0x03A1), (0x03A3, 0x03CE), (0x03D1, 0x03D1), (0x03D5, 0x03D5),
(0x03F0, 0x03F6), (0x0400, 0x045F), (0x0462, 0x0463), (0x046A, 0x046B),
(0x0490, 0x049D), (0x04A0, 0x04A5), (0x04AA, 0x04AB), (0x04AE, 0x04B3),
(0x04B6, 0x04BB), (0x04C0, 0x04C2), (0x04CF, 0x04DF), (0x04E2, 0x04F5),
(0x04F8, 0x04F9), (0x05D0, 0x05EA), (0x1E0C, 0x1E0D), (0x1E34, 0x1E37),
(0x1E40, 0x1E47), (0x1E6C, 0x1E6D), (0x1EB8, 0x1EB9), (0x1EBC, 0x1EBD),
(0x1ECA, 0x1ECD), (0x1EE4, 0x1EE5), (0x1EF8, 0x1EF9), (0x2000, 0x2022),
(0x2026, 0x2026), (0x2030, 0x2030), (0x2032, 0x2033), (0x2039, 0x203A),
(0x203C, 0x203C), (0x203E, 0x203E), (0x2070, 0x2071), (0x2074, 0x208E),
(0x2090, 0x2098), (0x209A, 0x209A), (0x20A7, 0x20A7), (0x20AA, 0x20AA),
(0x20AC, 0x20AC), (0x20AE, 0x20AE), (0x2102, 0x2102), (0x210E, 0x210F),
(0x2115, 0x2116), (0x211A, 0x211A), (0x211D, 0x211D), (0x2122, 0x2122),
(0x2124, 0x2124), (0x2126, 0x2126), (0x2135, 0x2135), (0x2190, 0x2195),
(0x21A4, 0x21A4), (0x21A6, 0x21A6), (0x21A8, 0x21A8), (0x21B2, 0x21B3),
(0x21B5, 0x21B5), (0x21BB, 0x21BB), (0x21CB, 0x21CC), (0x21D0, 0x21D5),
(0x21E7, 0x21E7), (0x2200, 0x2200), (0x2203, 0x220D), (0x2212, 0x2216),
(0x2219, 0x221A), (0x221E, 0x221F), (0x2225, 0x2225), (0x2227, 0x222A),
(0x2248, 0x2248), (0x2260, 0x2261), (0x2264, 0x2265), (0x226A, 0x226B),
(0x2282, 0x2283), (0x2286, 0x2287), (0x22A5, 0x22A5), (0x22C2, 0x22C3),
(0x22EF, 0x22EF), (0x2300, 0x2300), (0x2302, 0x2302), (0x2308, 0x230B),
(0x2310, 0x2310), (0x2316, 0x2316), (0x2319, 0x2319), (0x2320, 0x2321),
(0x232B, 0x232B), (0x239B, 0x23A9), (0x23AB, 0x23AF), (0x23BA, 0x23BD),
(0x23D0, 0x23D0), (0x2409, 0x240D), (0x2424, 0x2424), (0x2500, 0x2503),
(0x2508, 0x254B), (0x2550, 0x2593), (0x2596, 0x25A0), (0x25AC, 0x25AC),
(0x25AE, 0x25AE), (0x25B2, 0x25B2), (0x25B6, 0x25B6), (0x25B8, 0x25B8),
(0x25BA, 0x25BA), (0x25BC, 0x25BC), (0x25C0, 0x25C0), (0x25C4, 0x25C4),
(0x25C6, 0x25C6), (0x25C9, 0x25CB), (0x25CF, 0x25CF), (0x25D8, 0x25D9),
(0x25F7, 0x25F7), (0x2605, 0x2605), (0x263A, 0x263C), (0x2640, 0x2640),
(0x2642, 0x2642), (0x2660, 0x2660), (0x2663, 0x2663), (0x2665, 0x2666),
(0x266A, 0x266B), (0x2699, 0x2699), (0x26A0, 0x26A0), (0x26BF, 0x26BF),
(0x2713, 0x2714), (0x2717, 0x2718), (0x276F, 0x276F), (0x27E8, 0x27EB),
(0x2800, 0x28FF), (0x2E2C, 0x2E2C), (0xE0A0, 0xE0A2), (0xE0B0, 0xE0B3),
(0xF6BE, 0xF6BE), (0xFFFD, 0xFFFD),
)
# fmt: on
#: The inventory of the Cardputer as one frozen set.
CARDPUTER_ZERO_CODEPOINTS: frozenset[int] = frozenset(
cp for first, last in CARDPUTER_RANGES for cp in range(first, last + 1)
)
#: The glyph inventory of each handheld, by the name that ``Platform.font`` gives it.
FONTS: dict[str, frozenset[int]] = {
"picocalc-lyra": FONT_CODEPOINTS,
"cardputer-zero": CARDPUTER_ZERO_CODEPOINTS,
}