Picking a console font is its own preview, and a discard puts the saved one back
The Preferences page loads the font the moment its value is picked, rather than after Apply: a VT has one font for the whole screen, so the only honest way to show what the 6x8 build looks like is to load it, and the page is the preview, repainting at the new row count on the kernel's SIGWINCH. The page tracks what the console is drawn in right now; staging the saved value again reloads it at once, Apply keeps whatever is showing (the tool's re-apply after the write then finds nothing to change), and leaving with a discard reloads the saved font. Off the handheld the service says no once at page open and is asked nothing more. Four tests drive the page through each path with the service stubbed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
3b67c6813e
commit
646a0b7b7c
4 files changed
+96
-6
No files matched your search
+5
-3
@@ -22,9 +22,11 @@ allowed to change behaviour, not just add to it.
|
||||
- **The PicoCalc picks its console font, and MeshTerm hands the console back.** A *Console
|
||||
font* row under Display on the Preferences page offers `6x12 (53x26)` — the font the
|
||||
device boots in — and `6x8 (53x40)`, fourteen more rows of the same glyph inventory in a
|
||||
shorter cell. Choosing one loads it there and then; the kernel raises SIGWINCH on a font
|
||||
change, so the frame repaints at the new height without a relaunch. The 6×8 base has no
|
||||
Cyrillic, so a node named in Cyrillic draws as boxes on it.
|
||||
shorter cell. Picking one is the preview: the console loads it there and then, and the
|
||||
page repaints at the new height (the kernel raises SIGWINCH on a font change), so the
|
||||
choice is looked at before it is kept. Apply keeps it; leaving and discarding puts the
|
||||
saved font back. The 6×8 base has no Cyrillic, so a node named in Cyrillic draws as
|
||||
boxes on it.
|
||||
|
||||
A virtual terminal has one font for the whole console, so switching MeshTerm's switches
|
||||
the shell's. It saves whatever font was loaded before the first paint and reloads it on
|
||||
|
||||
+4
-3
@@ -211,9 +211,10 @@ and nothing more: the default is installed either way.
|
||||
**Choosing between them is a preference, not a command.** *Display → Console font* on the
|
||||
Preferences page offers `6x12 (53x26)` and `6x8 (53x40)`, and it is drawn on the PicoCalc
|
||||
only — it is a row about hardware no desktop has, though the value round-trips through
|
||||
`preferences.yaml` on any machine. Picking one loads it immediately: the kernel raises
|
||||
SIGWINCH on a font change, so the whole frame repaints at the new row count without a
|
||||
relaunch.
|
||||
`preferences.yaml` on any machine. Picking one is the preview: the console loads it
|
||||
immediately and the page repaints at the new row count (the kernel raises SIGWINCH on a
|
||||
font change), so you look at the choice before you keep it. *Apply* keeps it; leaving the
|
||||
page and discarding puts the saved font back.
|
||||
|
||||
MeshTerm puts the font back when it exits. Before the first paint it saves the console's
|
||||
current font with `setfont -O ~/.meshterm/console-font-before.psf` — whatever the *shell*
|
||||
|
||||
@@ -44,6 +44,7 @@ from ..core.preferences import (
|
||||
range_hint,
|
||||
)
|
||||
from ..platforms import get_platform
|
||||
from ..services import consolefont
|
||||
from .menus import (
|
||||
confirm_discard,
|
||||
exit_rows,
|
||||
@@ -84,6 +85,22 @@ async def edit_preferences(ctx: AppContext) -> dict[str, Any] | None:
|
||||
prefs = ctx.preferences
|
||||
pending: dict[str, Any] = {} # preference key -> staged new value
|
||||
|
||||
# The console font previews. A VT loads one font for the whole screen, so the only
|
||||
# honest way to show what the 6x8 build looks like is to load it — and this page is
|
||||
# the preview: it repaints at the new row count the moment the value is picked.
|
||||
# ``shown`` is what the console is drawn in right now; a discard puts the saved value
|
||||
# back, and Apply's own re-apply after the write finds nothing to change.
|
||||
previewing = consolefont.applies()
|
||||
shown = prefs.get(consolefont.PREFERENCE_KEY)
|
||||
|
||||
def preview() -> None:
|
||||
nonlocal shown
|
||||
if not previewing:
|
||||
return
|
||||
want = _effective(prefs, consolefont.PREFERENCE_KEY, pending)
|
||||
if want != shown and consolefont.apply(want):
|
||||
shown = want
|
||||
|
||||
# The rows *are* the data — each carries its own staged ``current → new`` value and
|
||||
# the title counts what is staged — so they refresh in place after every round
|
||||
# (``replace_items``) rather than being rebuilt as a new screen. One screen for the
|
||||
@@ -103,6 +120,8 @@ async def edit_preferences(ctx: AppContext) -> dict[str, Any] | None:
|
||||
if choice in (None, _CANCEL):
|
||||
if pending and not await confirm_discard(ctx, len(pending), verb="saving"):
|
||||
continue # keep editing — the same list, the same place in it
|
||||
if previewing and shown != prefs.get(consolefont.PREFERENCE_KEY):
|
||||
consolefont.apply(prefs.get(consolefont.PREFERENCE_KEY))
|
||||
return None
|
||||
if choice == _APPLY:
|
||||
return dict(pending) or None
|
||||
@@ -110,6 +129,7 @@ async def edit_preferences(ctx: AppContext) -> dict[str, Any] | None:
|
||||
await _stage_reset(ctx, prefs, pending)
|
||||
else: # a preference key
|
||||
await _stage_preference(ctx, prefs, choice, pending)
|
||||
preview()
|
||||
title, items = _menu_items(prefs, pending)
|
||||
menu.replace_items(items, title=title)
|
||||
|
||||
|
||||
@@ -491,6 +491,73 @@ async def test_leaving_with_unsaved_changes_is_gated(ctx: AppContext) -> None:
|
||||
assert await edit_preferences(ctx) == {"history_days": 30}
|
||||
|
||||
|
||||
def _preview_console(monkeypatch: pytest.MonkeyPatch, *, on_device: bool) -> list[str]:
|
||||
"""Stand in for the console-font service: record every font the page loads."""
|
||||
from meshterm.ui import preferences as page
|
||||
|
||||
loaded: list[str] = []
|
||||
monkeypatch.setattr(page.consolefont, "applies", lambda: on_device)
|
||||
monkeypatch.setattr(page.consolefont, "apply", lambda choice: loaded.append(choice) or True)
|
||||
return loaded
|
||||
|
||||
|
||||
async def test_picking_a_console_font_previews_it_and_apply_keeps_it(
|
||||
ctx: AppContext, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""The console loads the font the moment it is picked; Apply hands it over to save."""
|
||||
loaded = _preview_console(monkeypatch, on_device=True)
|
||||
_install(ctx, [("select", "console_font"), ("select", "6x8"), ("select", "__apply__")])
|
||||
assert await edit_preferences(ctx) == {"console_font": "6x8"}
|
||||
assert loaded == ["6x8"] # previewed once, and nothing put back on the way out
|
||||
|
||||
|
||||
async def test_discarding_a_previewed_console_font_puts_the_saved_one_back(
|
||||
ctx: AppContext, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""A preview that is not kept is undone: the saved font comes back on discard."""
|
||||
loaded = _preview_console(monkeypatch, on_device=True)
|
||||
_install(
|
||||
ctx,
|
||||
[
|
||||
("select", "console_font"),
|
||||
("select", "6x8"),
|
||||
("select", None), # Esc
|
||||
("dialog", "discard"),
|
||||
],
|
||||
)
|
||||
assert await edit_preferences(ctx) is None
|
||||
assert loaded == ["6x8", "6x12"]
|
||||
|
||||
|
||||
async def test_setting_the_console_font_back_reloads_it_at_once(
|
||||
ctx: AppContext, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""Staging the value in force again is a clean row — and the console follows it."""
|
||||
loaded = _preview_console(monkeypatch, on_device=True)
|
||||
_install(
|
||||
ctx,
|
||||
[
|
||||
("select", "console_font"),
|
||||
("select", "6x8"),
|
||||
("select", "console_font"),
|
||||
("select", "6x12"), # back to what is saved: nothing staged, Esc leaves quietly
|
||||
("select", None),
|
||||
],
|
||||
)
|
||||
assert await edit_preferences(ctx) is None
|
||||
assert loaded == ["6x8", "6x12"]
|
||||
|
||||
|
||||
async def test_a_desktop_page_never_touches_a_console_font(
|
||||
ctx: AppContext, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""Off the handheld the service says no once, and the page asks it nothing more."""
|
||||
loaded = _preview_console(monkeypatch, on_device=False)
|
||||
_install(ctx, [("select", "console_font"), ("select", "6x8"), ("select", "__apply__")])
|
||||
assert await edit_preferences(ctx) == {"console_font": "6x8"}
|
||||
assert loaded == []
|
||||
|
||||
|
||||
async def test_discarding_at_the_gate_drops_the_changes(ctx: AppContext) -> None:
|
||||
"""Confirming the discard leaves with nothing, staged values and all."""
|
||||
_install(
|
||||
|
||||
Reference in new issue
Block a user