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.
This commit is contained in:
2026-09-07 20:00:59 -04:00
parent 574b235b6f
commit 2ac8e5c0d4
3 changed files with 263 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# __config_settings_frame width
# __config_settings_frame title <iw> <p> <segment>
# __config_settings_frame badge <value> [<on_word> <off_word>]
# __config_settings_frame cursor <row> <cur_row>
# __config_settings_frame row <iw> <p> <curs> <label> <label_w> <badge> <field> <fit>
#
# DESCRIPTION
# The pieces of the config-settings panel that every page draws identically:
# the width tier, the title border, the ON/OFF/DEFAULT badge, the cursor cell
# and one table row. __config_settings_draw, __config_settings_draw_subcat
# and __config_settings_draw_value each keep their own sequence of lines and
# their own per-tier text; only these shared computations live here.
#
# Deliberately owns no page height. Every verb prints exactly one line or one
# fragment, so how tall a page is remains a property of its caller's line
# sequence: __config_settings_draw and __config_settings_draw_value are a
# fixed 16 lines, __config_settings_draw_subcat is 7 + <sub-category count>,
# and config-settings.fish's wrap-aware erase (\e[<N>A\e[J, sized from
# panel_h) depends on that difference surviving exactly as it is.
#
# Row geometry. A row is
# │ + 2 spaces + cursor(2) + label(label_w) + " [ " + badge(7) + " ] "
# + field(field_w) + 3 spaces + │
# which totals 23 + label_w + field_w and must equal iw + 2. So
# field_w = iw - 21 - label_w
# and that single sum reproduces both hand-maintained constants: label_w 12
# gives iw-33 (the toggle and value pages), label_w 13 gives iw-34 (the
# sub-category page, whose description field absorbs its wider label).
#
# Title geometry. "┌─" + segment + dashes + "┐" totals iw + 2, so
# dashes = iw - visible(segment) - 1
# The segment arrives already coloured because the three pages place their
# set_color reset at different byte offsets around the same visible text
# (__config_settings_draw resets after the trailing space, the other two
# before it). That difference is invisible on screen and visible to cmp, so
# each page keeps its own bytes while sharing the arithmetic; --visible
# discounts the escapes.
#
# ARGUMENTS
# width No arguments. Prints the inner width for the current $COLUMNS:
# >= 90 -> 76, >= 86 -> 72, >= 82 -> 68, otherwise 50.
# title iw, the centering prefix, and the pre-coloured title segment.
# badge The stored value, then optionally the words this page uses for true
# and false (default on/off; the value pages store true/false).
# Anything else renders DEFAULT.
# cursor This row's index and the highlighted row's index.
# row iw, centering prefix, cursor cell, label, label field width,
# rendered badge, field text, and the fit policy:
# pad pad label and field, never shrink either
# cut truncate both to their field width, then pad
# shorten pad the label, ellipsise the field with string shorten
#
# EXIT STATUS
# 0 Verb recognised
# 1 Unknown verb
#
# RETURNS
# The requested panel line or fragment, printed to stdout
#
# NOTES
# `string pad` only ever grows a string, never shrinks it. That is the whole
# reason `cut` and `shorten` exist: a caller whose text can exceed its field
# must shrink it first, or the box stops being rectangular.
#
# `pad` is not "the default when you don't care". __config_settings_draw's
# descriptions are authored per width tier to fit their field exactly -- at
# every tier the longest is precisely the field width -- so applying `cut`
# there would be a byte-for-byte no-op that silently discards that property
# and passes the render golden. Which policy a page uses is a real decision,
# named at each call site. See tests/config-settings-render.fish.
#
# EXAMPLE
# set -l iw (__config_settings_frame width)
# __config_settings_frame row $iw $p (__config_settings_frame cursor 0 0) \
# Aliases 12 (__config_settings_frame badge on) "cmd shadows" pad
function __config_settings_frame
switch $argv[1]
# ── Width tier: 6-col buffer per side before stepping up ──────────
case width
if test "$COLUMNS" -ge 90
echo 76
else if test "$COLUMNS" -ge 86
echo 72
else if test "$COLUMNS" -ge 82
echo 68
else
echo 50
end
# ── Title border: ┌─<segment><dashes>┐ ────────────────────────────
case title
set -l iw $argv[2]
set -l vis (string length --visible -- "$argv[4]")
set -l dashes (math "max(0, $iw - $vis - 1)")
printf '%s┌─%s%s┐\n' $argv[3] "$argv[4]" (string repeat -n $dashes '─')
# ── Badge: 7 visible columns, coloured ────────────────────────────
# The truthy/falsy words are arguments rather than one merged
# vocabulary: merging would make a hand-set "on" in a true/false
# variable render as ON where it renders DEFAULT today.
case badge
set -l on_word on
set -l off_word off
if test (count $argv) -ge 4
set on_word $argv[3]
set off_word $argv[4]
end
switch "$argv[2]"
case $on_word
printf '%s ON%s' (set_color green) (set_color normal)
case $off_word
printf '%sOFF %s' (set_color red) (set_color normal)
case '*'
printf '%sDEFAULT%s' (set_color brblack) (set_color normal)
end
# ── Cursor cell: 2 visible columns ────────────────────────────────
case cursor
if test $argv[2] -eq $argv[3]
printf '%s▶%s ' (set_color --bold magenta) (set_color normal)
else
printf ' '
end
# ── One table row ─────────────────────────────────────────────────
case row
set -l iw $argv[2]
set -l p $argv[3]
set -l curs $argv[4]
set -l label "$argv[5]"
set -l label_w $argv[6]
set -l badge $argv[7]
set -l field "$argv[8]"
set -l fit $argv[9]
set -l field_w (math $iw - 21 - $label_w)
switch $fit
case cut
set label (string sub -l $label_w -- "$label")
set field (string sub -l $field_w -- "$field")
case shorten
set field (string shorten -m $field_w -- "$field")
end
printf '%s│ %s%s [ %s ] %s │\n' $p $curs \
(string pad -r -w $label_w -- "$label") $badge \
(string pad -r -w $field_w -- "$field")
case '*'
echo "__config_settings_frame: unknown verb '$argv[1]'" >&2
return 1
end
end
+54
View File
@@ -178,6 +178,17 @@ function _cs_render_case --argument-names label panel_h
command rm -f $t
end
# ── Frame-verb fragments ──────────────────────────────────────────────────
# The shared computations pinned directly, not only through the pages that use
# them. <END> marks the end of each fragment so trailing padding -- which is
# the entire point of a 7-column badge or a 2-column cursor cell -- shows up in
# a diff instead of being invisible whitespace.
function _cs_frame_case --argument-names label
printf '### frame %s\n' $label
$argv[2..]
printf '<END>\n'
end
# ── Cases ─────────────────────────────────────────────────────────────────
# 100 -> IW 76, 88 -> IW 72, 84 -> IW 68, 70 -> IW 50: one COLUMNS value per
# width tier, each a few columns above its threshold.
@@ -222,4 +233,47 @@ begin
_cs_render_case "edit page=paths row=2 buf=empty" 16 \
__config_settings_draw_value 2 paths edit ""
end
# Emitted last on purpose: everything above is page output, so the page
# section's byte offsets never move when this section grows.
for cols in 100 88 84 70
set -g COLUMNS $cols
_cs_frame_case "width cols=$cols" __config_settings_frame width
end
set -g COLUMNS 100
set -l head (set_color --bold cyan)
set -l rst (set_color normal)
set -l p_test (string repeat -n 11 ' ')
for v in on off DEFAULT ''
_cs_frame_case "badge onoff val=$v" __config_settings_frame badge $v
end
for v in true false DEFAULT
_cs_frame_case "badge boolean val=$v" __config_settings_frame badge $v true false
end
_cs_frame_case "cursor hit" __config_settings_frame cursor 3 3
_cs_frame_case "cursor miss" __config_settings_frame cursor 3 4
_cs_frame_case "title toggle-page" __config_settings_frame title 76 $p_test \
"$head Opinionated Settings $rst"
_cs_frame_case "title subcat-page" __config_settings_frame title 76 $p_test \
"$head Sub-categories: aliases (Universal)$rst "
_cs_frame_case "title value-page" __config_settings_frame title 76 $p_test \
"$head Sponge Settings$rst "
set -l badge_on (__config_settings_frame badge on)
_cs_frame_case "row pad lw=12" __config_settings_frame row 76 $p_test \
(__config_settings_frame cursor 0 0) Aliases 12 $badge_on "cmd shadows" pad
_cs_frame_case "row cut lw=13" __config_settings_frame row 76 $p_test \
(__config_settings_frame cursor 0 1) Notifications 13 $badge_on "done, WakaTime hook" cut
_cs_frame_case "row cut lw=13 overlong" __config_settings_frame row 50 $p_test \
(__config_settings_frame cursor 0 0) Notifications 13 $badge_on \
"ls, cat, cd, du, mkdir, rm, mv, zoxide" cut
_cs_frame_case "row shorten lw=12" __config_settings_frame row 76 $p_test \
(__config_settings_frame cursor 0 0) "Log dir" 12 $badge_on \
/home/tester/very/long/scrollback/history/directory shorten
_cs_frame_case "row shorten lw=12 empty" __config_settings_frame row 50 $p_test \
(__config_settings_frame cursor 1 0) "Log max" 12 $badge_on "" shorten
end >$CS_RENDER_OUT
+54
View File
@@ -4938,3 +4938,57 @@
│──────────────────────────────────────────────────│
 type value Enter save Esc cancel ⌫ delete │
└──────────────────────────────────────────────────┘
### frame width cols=100
76
<END>
### frame width cols=88
72
<END>
### frame width cols=84
68
<END>
### frame width cols=70
50
<END>
### frame badge onoff val=on
 ON<END>
### frame badge onoff val=off
OFF <END>
### frame badge onoff val=DEFAULT
DEFAULT<END>
### frame badge onoff val=
DEFAULT<END>
### frame badge boolean val=true
 ON<END>
### frame badge boolean val=false
OFF <END>
### frame badge boolean val=DEFAULT
DEFAULT<END>
### frame cursor hit
▶ <END>
### frame cursor miss
<END>
### frame title toggle-page
┌─ Opinionated Settings ─────────────────────────────────────────────────────┐
<END>
### frame title subcat-page
┌─ Sub-categories: aliases (Universal) ──────────────────────────────────────┐
<END>
### frame title value-page
┌─ Sponge Settings ──────────────────────────────────────────────────────────┐
<END>
### frame row pad lw=12
▶ Aliases [  ON ] cmd shadows │
<END>
### frame row cut lw=13
│ Notifications [  ON ] done, WakaTime hook │
<END>
### frame row cut lw=13 overlong
▶ Notifications [  ON ] ls, cat, cd, du, │
<END>
### frame row shorten lw=12
▶ Log dir [  ON ] /home/tester/very/long/scrollback/history/… │
<END>
### frame row shorten lw=12 empty
│ Log max [  ON ] │
<END>