refactor(config-settings): shared frame renderer + line-diff redraw #133

Merged
rootiest merged 13 commits from refactor/config-settings-renderer into main 2026-09-08 16:28:53 +00:00
13 Commits
Author SHA1 Message Date
rootiest afbc3e97d7 Merge remote-tracking branch 'origin/main' into refactor/config-settings-renderer
# Conflicts:
#	functions/__config_settings_draw.fish
#	functions/__config_settings_draw_subcat.fish
#	functions/__config_settings_draw_value.fish
#	tests/functional.fish
2026-09-08 12:19:31 -04:00
rootiest 3c4f720749 fix(config-settings): repair diff-redraw review findings
- Print the missing exit-repaint after the inline editor's
  __cs_dispatch_draw call (was silently changed to capture-only earlier
  in the branch; this call site was missed, blanking the panel on
  commit/cancel of an inline edit).
- Hoist (count $prev_edit_frame) out of a quoted math string in the
  inline editor's per-keystroke redraw -- fish doesn't expand a command
  substitution there, so math silently errored.
- Add a >= 52 column floor to both diff-path guards: below the
  narrowest tier's own 52-column box width, lines wrap and the diff
  path's one-physical-row-per-logical-line walk corrupts the display.
- Reword a stale test comment that described panel_h as mirroring a
  hand-set constant in __cs_dispatch_draw; it derives panel_h from real
  output now.
- Declare prev_edit_frame with -l alongside edit_frame instead of a
  bare set, matching the file's convention.
- Move prev_frame's declaration to its point of use instead of an
  empty top-level placeholder, matching old_h in the same block.
2026-09-08 04:37:27 -04:00
rootiest a0491b2bd1 feat(config-settings): diff redraw in the inline value editor 2026-09-08 04:21:07 -04:00
rootiest fae15b8d55 feat(config-settings): diff redraw in the main navigation loop 2026-09-08 04:17:32 -04:00
rootiest ab14837e39 refactor(config-settings): dispatch captures the frame instead of printing it 2026-09-08 04:13:52 -04:00
rootiest ece3e9dbfb feat(config-settings): add __config_settings_diff_redraw 2026-09-08 04:08:00 -04:00
rootiest 7b02348f64 test(config-settings): lock draw-function line counts to their panel heights 2026-09-08 03:57:26 -04:00
rootiest a3853a93d8 test: run the config-settings render golden in the test runner
A byte-identity gate CI never runs will rot, and a rotted gate is worse
than no gate. Adds the render harness as Phase 4, in the same shape as the
vault suite: its own process, its own sandbox, no loaded config needed.

Kept to one self-contained block so it can be dropped or re-applied by
hand if the runner is restructured. The functional suite's 317/317 count
is untouched; the render cases report separately.
2026-09-07 20:13:08 -04:00
rootiest a824005893 refactor(config-settings): draw the value pages through the frame
Width tier, title border, boolean badge, cursor cell and row line now come
from __config_settings_frame. The type badges (PATH/INT/LIST/STR) stay
here -- they are this page's own vocabulary, used nowhere else -- and so
does the STR default arm, which covers a user-settable value rather than
being dead code.

Introduces the `shorten` fit policy: these fields hold arbitrary user
values and want an ellipsis, unlike the toggle page's per-tier text. The
inline editor keeps `pad`, because its field is already length-constrained
and carries a reverse-video caret whose escapes string shorten miscounts.

The panel stays exactly 16 lines -- chrome(6) + nrows + blanks -- so
config-settings.fish's panel_h and its erase are untouched.

Rendering unchanged: 377/377 render cases byte-identical, golden untouched.
Code lines 123 -> 98 (-25).
2026-09-07 20:06:14 -04:00
rootiest ad9926861b refactor(config-settings): draw the sub-category page through the frame
Width tier, title border, badge, cursor cell and row line now come from
__config_settings_frame, and the hand-verified title dash count
(iw - L - S - 22) is derived from the segment's visible width instead.

Introduces the `cut` fit policy, which is this page's documented
divergence from the category list: its labels and descriptions are static
data from __config_settings_subcats rather than per-tier authored text,
and several exceed the narrower tiers' fields. `string pad` only ever
grows a string, so they are truncated before padding. That reason now
lives in two places -- the frame's NOTES and each call site -- and the
DESCRIPTION block stating it here is unchanged.

Drops label_w and desc_w, both left assigned and never read once the
frame derives the field width; the comment recording the 13-wide label
field and how the description field absorbs it stays.

Rendering unchanged: 377/377 render cases byte-identical, golden untouched.
Code lines 85 -> 49 (-36).
2026-09-07 20:04:44 -04:00
rootiest 889f8e0768 refactor(config-settings): draw the category list through the frame
Width tier, title border, badge, cursor cell and row line now come from
__config_settings_frame. The per-tier description sets stay here -- they
are this page's data, authored to fit each tier's field exactly -- and are
selected by width rather than by re-testing $COLUMNS.

Rows pass the `pad` fit policy explicitly. That is a decision, not a
default: `cut` would be a byte-for-byte no-op on these strings today and
would silently discard the property that they are tuned to their field.

Drops c_hi, which was assigned and never read.

Rendering unchanged: 377/377 render cases byte-identical, golden untouched.
Code lines 114 -> 80 (-34).
2026-09-07 20:02:48 -04:00
rootiest 2ac8e5c0d4 feat(config-settings): add __config_settings_frame shared renderer
The width tier, title-border arithmetic, ON/OFF/DEFAULT badge, cursor cell
and table row are currently hand-copied across the three draw functions.
This adds them once, with the two geometry identities derived rather than
hand-maintained: a row's chrome is a fixed 21 columns, so field_w is
iw - 21 - label_w (reproducing both iw-33 and iw-34), and a title border is
dashes = iw - visible(segment) - 1 (reproducing all three of iw-23,
iw-len-3 and iw-L-S-22).

The frame owns no page height. Every verb prints exactly one line or
fragment, so the fixed-16 category and value pages and the dynamic
7+n sub-category page keep their heights, and config-settings.fish's
erase is unaffected.

No caller yet, so rendering cannot move: the golden's existing page
section is byte-identical (verified with cmp -n over its previous size)
and the file only gains frame-verb cases appended after it.
2026-09-07 20:00:59 -04:00
rootiest 574b235b6f test(config-settings): add byte-exact golden-output render harness
The three config-settings draw functions are hand-tuned layout code whose
field widths, dash counts and pad targets are arithmetic on the width tier.
Any refactor of them has to be byte-identical, and nothing until now could
prove that.

Renders all 356 page/width/scope/cursor-row combinations -- every page at
COLUMNS 100/88/84/70, both scopes, cursor on every row, plus the inline
editor -- and byte-compares against a committed baseline.

The golden holds raw output: set_color escapes and box drawing exactly as
emitted, plus the wrap-aware \e[<N>A\e[J erase config-settings.fish would
emit for each panel, and per case the declared panel height against the
measured line count. Nothing is normalized; the gate is cmp(1) and a
one-space change anywhere fails it. Proven by four deliberate mutations,
one per draw function plus a panel-height change, each caught and reverted.

Runs entirely inside a throwaway HOME/XDG_CONFIG_HOME sandbox: the fixtures
must be real universal variables, and this repo doubles as a live
~/.config/fish. fish --no-config cannot be used, as -N silently degrades
set -U to global scope. Every utility is called through `command`, since
the config itself shadows rm, cat and mkdir and aliases cp -i.
2026-09-07 07:28:45 -04:00