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>
138 lines
8.2 KiB
Python
138 lines
8.2 KiB
Python
# 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,
|
||
}
|