feat(config-settings): replace the ANSI renderer with a curses front-end
config-settings is now a launcher for scripts/config-settings-tui.py, drawn with Python's stdlib curses. The seven fish files that hand-rolled the ANSI renderer are gone, along with the golden harness that had to pin their byte-exact output. The TUI is a child process, so it can neither read the session's global variables nor write them. State goes in as a dump from the new __config_settings_state; the edits come back as a fish script that config-settings sources, which is what lets the Session page's `set -g` land in the caller's shell instead of in a child that is about to exit. Every edit is emitted as a call to __config_settings_apply or __config_settings_set_value, so list splitting, the SCROLLBACK_HISTORY_* export mirror and the shadow-warning suppression all stay in the fish layer that already owned them. The consequence, and the one behaviour change: edits are applied in one batch on exit rather than on each keypress. The status bar shows a pending count. New: `/` filters the current page, and on the Universal and Session pages it reaches into every category's sub-categories, listing hits as "Category › Sub" so a sub-category can be toggled without drilling into its parent first. Also a `?` help overlay, mouse selection, and a drill-down page that leads with the category's own toggle. Gone with the renderer: the four width tiers, the wrap-aware erase arithmetic, the stty/dd/od raw key reader, the panel-height bookkeeping and the hand-written redraw differ. curses owns all of it, and the alt screen plus absolute addressing makes the desync class behind608b022,4210f3b,93fc5e0and3c4f720unreachable. The sub-category taxonomy is NOT duplicated in Python: it travels in the state dump, still sourced from __config_settings_subcats. The category, Sponge and Paths row tables move into Python, consolidating the two copies the fish renderers kept. Dependency: python3 with curses. Stdlib on Arch, Fedora and a full Debian/Ubuntu python3; python3-minimal alone lacks _curses. The launcher checks for both and names what is missing. Called out in the README. Verified: 416/416 assertions, plus a live end-to-end in a sandbox HOME confirming the Universal page writes universal scope only (U1/G0) and the Session page global scope only (U0/G1).
This commit is contained in:
@@ -2,24 +2,34 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Gate for the curses config-settings PROTOTYPE (scripts/config-settings-tui.py).
|
||||
# Gate for the curses config-settings front-end (scripts/config-settings-tui.py).
|
||||
#
|
||||
# Runs isolated (no `# MODE:` marker). Two things are checked, and only two:
|
||||
# Runs isolated (no `# MODE:` marker). Three things are checked here:
|
||||
#
|
||||
# 1. python3 can import `curses`. On Arch, Fedora and a full Debian/Ubuntu
|
||||
# python3 this is stdlib and always true, but python3-minimal alone does
|
||||
# not carry _curses -- the one portability claim the prototype makes.
|
||||
# 2. The prototype's own --self-test passes. That covers the pure state
|
||||
# machine (value cycling, filtering, sub-category lookup, badge and
|
||||
# ellipsis rendering) with no TTY, which is all a test runner has.
|
||||
# not carry _curses -- the one portability claim config-settings makes,
|
||||
# and the reason the function checks the import rather than just `type -q`.
|
||||
# 2. The TUI's own --self-test passes. That covers the state-dump parser,
|
||||
# variable-name derivation, toggle cycling, the sub-category-aware filter,
|
||||
# fish quoting and command emission, with no TTY.
|
||||
# 3. config-settings still degrades cleanly with no terminal, rather than
|
||||
# leaving a half-initialised curses screen behind.
|
||||
#
|
||||
# The drawing code is deliberately NOT golden-tested. That is the whole
|
||||
# argument for the prototype: curses owns the cell arithmetic, so there is no
|
||||
# hand-tuned width/pad/dash math to pin down the way
|
||||
# test-config-settings-render.fish has to pin the fish renderer's.
|
||||
# The drawing code is deliberately NOT golden-tested, and the golden harness
|
||||
# the ANSI renderer needed is gone. That is the point of the rewrite: curses
|
||||
# owns the cell arithmetic, so there is no hand-tuned width/pad/dash maths left
|
||||
# to pin down. The seam that does need pinning -- dump in, fish script out --
|
||||
# is covered here and, for session scope, in tests/test-session.fish.
|
||||
|
||||
source (dirname (status filename))/lib.fish
|
||||
|
||||
# Isolated suites run under `fish --no-config`, which autoloads nothing from
|
||||
# this repo. The launcher cases below call config-settings for real, so put the
|
||||
# repo's functions on the autoload path -- and only that, so nothing in conf.d
|
||||
# runs and the guard variables stay unset.
|
||||
set -p fish_function_path $repo_root/functions
|
||||
|
||||
set -l tui $repo_root/scripts/config-settings-tui.py
|
||||
|
||||
section "config-settings-tui: prerequisites"
|
||||
@@ -30,4 +40,17 @@ check "python3 ships the curses module" 0 (python3 -c 'import curses' >/dev/null
|
||||
section "config-settings-tui: self-test"
|
||||
check "--self-test passes" 0 (python3 $tui --self-test >/dev/null 2>&1; echo $status)
|
||||
|
||||
section "config-settings: launcher"
|
||||
check "--help exits 0" 0 (config-settings --help >/dev/null 2>&1; echo $status)
|
||||
check "an unknown flag exits 1" 1 (config-settings --nope >/dev/null 2>&1; echo $status)
|
||||
|
||||
# stdout is a pipe here, so the isatty guard fires before curses ever starts.
|
||||
# Without it the TUI would fail deep inside setupterm and leave the terminal
|
||||
# in whatever state it got to.
|
||||
function test_no_tty_is_refused_cleanly
|
||||
set -l out (config-settings 2>&1 >/dev/null | string collect)
|
||||
string match -q '*needs a terminal*' -- $out
|
||||
end
|
||||
check "no TTY is refused with a message, not a curses crash" true (test_no_tty_is_refused_cleanly; and echo true; or echo false)
|
||||
|
||||
report
|
||||
|
||||
Reference in New Issue
Block a user