diff --git a/functions/__config_settings_diff_redraw.fish b/functions/__config_settings_diff_redraw.fish new file mode 100644 index 0000000..f5d9621 --- /dev/null +++ b/functions/__config_settings_diff_redraw.fish @@ -0,0 +1,47 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# SYNOPSIS +# __config_settings_diff_redraw +# +# DESCRIPTION +# Rewrites an on-screen panel frame in place, touching only the lines +# that changed. Assumes the cursor is already positioned at the top-left +# of the frame (the caller moves it there with a plain \e[A -- no +# \e[J -- before calling this). Line count in old_joined and new_joined +# must be equal; a caller facing a height or width change should use the +# existing full erase+redraw path instead of calling this. +# +# Unchanged lines advance the cursor with a bare newline, leaving +# whatever is already on screen untouched. Changed lines clear just that +# line (\e[2K), return to its start (\r), print the new content, and +# advance (\n). This is what removes the erase-then-redraw flicker: the +# screen is never blanked, only the handful of lines that actually +# differ are ever touched, and each of those is cleared and rewritten in +# the same breath rather than blanked-then-paused-then-filled. +# +# ARGUMENTS +# old_joined Previous frame, lines joined with \n +# new_joined New frame, lines joined with \n (same line count as old) +# +# EXIT STATUS +# 0 Always +# +# RETURNS +# The ANSI sequence needed to turn the old frame into the new one, +# printed to stdout +# +# EXAMPLE +# __config_settings_diff_redraw (string join \n -- $prev_frame) \ +# (string join \n -- $new_frame) +function __config_settings_diff_redraw + set -l old (string split \n -- $argv[1]) + set -l new (string split \n -- $argv[2]) + for i in (seq (count $new)) + if test "$old[$i]" = "$new[$i]" + printf '\n' + else + printf '\e[2K\r%s\n' $new[$i] + end + end +end diff --git a/functions/__config_settings_draw.fish b/functions/__config_settings_draw.fish index 6518ddd..f4d975b 100644 --- a/functions/__config_settings_draw.fish +++ b/functions/__config_settings_draw.fish @@ -42,10 +42,15 @@ function __config_settings_draw set -l labels Aliases Auto-exec Overrides Integrations Logging Greeting Master - # ── Width tier: 6-col buffer per side before stepping up ────────────── + # ── Width tier ──────────────────────────────────────────────────────── + # The tier thresholds live in __config_settings_frame; this file only + # chooses which hand-authored description set goes with the width. # IW = inner width (chars between │ │); desc field = IW - 33. # All four layouts are exactly 16 lines tall — panel_h in caller stays 16. - set -l iw 50 + # Descriptions are authored to fit their field exactly at every tier + # (43/43, 39/39, 35/35, 17/17), which is why the rows below pass `pad` + # and not `cut` -- see the NOTES in __config_settings_frame. + set -l iw (__config_settings_frame width) set -l descs \ "cmd shadows" \ startup \ @@ -55,36 +60,34 @@ function __config_settings_draw fish_greeting \ "disable all" - if test "$COLUMNS" -ge 90 - set iw 76 - set descs \ - "shadows: ls→eza, cat→bat, cd→z, rm→trash" \ - "Fisher bootstrap, themes, py-venv activate" \ - "vi-mode, bang-bang, PAGER, CDPATH, starship" \ - "Kitty/WezTerm tab/split fns, notifications" \ - "scrollback capture & paru/yay AUR wrappers" \ - "fish_greeting & first-run welcome banner" \ - "master off-switch: overrides all categories" - else if test "$COLUMNS" -ge 86 - set iw 72 - set descs \ - "ls→eza, cat→bat, cd→zoxide, rm→trash" \ - "Fisher bootstrap, themes, py-venv auto" \ - "vi-mode, bang-bang, PAGER, starship" \ - "Kitty/WezTerm fns, done notifications" \ - "scrollback capture & paru/yay wrappers" \ - "fish_greeting: first-run welcome banner" \ - "master off-switch for all categories" - else if test "$COLUMNS" -ge 82 - set iw 68 - set descs \ - "ls→eza, cat→bat, cd→z, rm→trash" \ - "Fisher, themes, py-venv activate" \ - "vi-mode, bang-bang, PAGER, starship" \ - "Kitty/WezTerm, done notifications" \ - "scrollback & paru/yay log wrappers" \ - "fish_greeting & first-run banner" \ - "master disable for all categories" + switch $iw + case 76 + set descs \ + "shadows: ls→eza, cat→bat, cd→z, rm→trash" \ + "Fisher bootstrap, themes, py-venv activate" \ + "vi-mode, bang-bang, PAGER, CDPATH, starship" \ + "Kitty/WezTerm tab/split fns, notifications" \ + "scrollback capture & paru/yay AUR wrappers" \ + "fish_greeting & first-run welcome banner" \ + "master off-switch: overrides all categories" + case 72 + set descs \ + "ls→eza, cat→bat, cd→zoxide, rm→trash" \ + "Fisher bootstrap, themes, py-venv auto" \ + "vi-mode, bang-bang, PAGER, starship" \ + "Kitty/WezTerm fns, done notifications" \ + "scrollback capture & paru/yay wrappers" \ + "fish_greeting: first-run welcome banner" \ + "master off-switch for all categories" + case 68 + set descs \ + "ls→eza, cat→bat, cd→z, rm→trash" \ + "Fisher, themes, py-venv activate" \ + "vi-mode, bang-bang, PAGER, starship" \ + "Kitty/WezTerm, done notifications" \ + "scrollback & paru/yay log wrappers" \ + "fish_greeting & first-run banner" \ + "master disable for all categories" end set -l HBR (string repeat -n $iw '─') @@ -95,8 +98,7 @@ function __config_settings_draw # ── Top border ──────────────────────────────────────────────────────── # ┌─ Opinionated Settings (iw-23)×─ ┐ total = iw+2 - printf '%s┌─%s Opinionated Settings %s┐\n' \ - $p $c_head $c_reset(string repeat -n (math $iw - 23) '─') + __config_settings_frame title $iw $p "$c_head Opinionated Settings $c_reset" # ── Page-tab header ─────────────────────────────────────────────────── set -l active_idx 0 @@ -109,36 +111,18 @@ function __config_settings_draw printf '%s│%s│\n' $p $HBR # ── Category rows 0–5 ───────────────────────────────────────────────── + # Label field 12 wide; the description field falls out of it inside the + # frame (field_w = iw - 21 - label_w = iw - 33). `pad`, not `cut`: these + # descriptions are authored per tier to fit exactly, so truncating them + # would be a silent no-op that discards that property. for i in (seq 0 5) - set -l idx (math $i + 1) - set -l var $vars[$idx] - set -l label $labels[$idx] - set -l desc $descs[$idx] - - set -l val (__config_settings_get_val $var $cur_scope) - - # Badge: 7 visible chars, coloured - set -l badge - switch $val - case on - set badge "$c_ok"" ON$c_reset" - case off - set badge "$c_err""OFF $c_reset" - case '*' - set badge "$c_dim""DEFAULT$c_reset" - end - - # Cursor: 2 visible chars - set -l curs " " - if test $i -eq $cur_row - set curs "$c_sel▶$c_reset " - end - - # Label padded to 12, desc padded to (iw-33), right margin 3 - set -l lpad (string pad -r -w 12 -- $label) - set -l dpad (string pad -r -w (math $iw - 33) -- $desc) - - printf '%s│ %s%s [ %s ] %s │\n' $p $curs $lpad $badge $dpad + set -l idx (math $i + 1) + set -l val (__config_settings_get_val $vars[$idx] $cur_scope) + __config_settings_frame row $iw $p \ + (__config_settings_frame cursor $i $cur_row) \ + $labels[$idx] 12 \ + (__config_settings_frame badge $val) \ + $descs[$idx] pad end # ── Separator before Master ─────────────────────────────────────────── @@ -146,24 +130,11 @@ function __config_settings_draw # ── Master row (index 6) ────────────────────────────────────────────── set -l val (__config_settings_get_val $vars[7] $cur_scope) - set -l badge - switch $val - case on - set badge "$c_ok"" ON$c_reset" - case off - set badge "$c_err""OFF $c_reset" - case '*' - set badge "$c_dim""DEFAULT$c_reset" - end - set -l curs " " - if test $cur_row -eq 6 - set curs "$c_sel▶$c_reset " - end - printf '%s│ %s%s [ %s ] %s │\n' \ - $p $curs \ - (string pad -r -w 12 -- Master) \ - $badge \ - (string pad -r -w (math $iw - 33) -- $descs[7]) + __config_settings_frame row $iw $p \ + (__config_settings_frame cursor 6 $cur_row) \ + Master 12 \ + (__config_settings_frame badge $val) \ + $descs[7] pad # ── Filler (Dots Path moved to the Paths page) ──────────────────────── printf '%s│ %s%s│\n' $p \ diff --git a/functions/__config_settings_draw_subcat.fish b/functions/__config_settings_draw_subcat.fish index e9ef166..6920ece 100644 --- a/functions/__config_settings_draw_subcat.fish +++ b/functions/__config_settings_draw_subcat.fish @@ -47,23 +47,14 @@ function __config_settings_draw_subcat set -l n (count $rows) # ── Width tier: matches __config_settings_draw's 6-col-per-side steps ── - set -l iw 50 - if test "$COLUMNS" -ge 90 - set iw 76 - else if test "$COLUMNS" -ge 86 - set iw 72 - else if test "$COLUMNS" -ge 82 - set iw 68 - end + set -l iw (__config_settings_frame width) set -l HBR (string repeat -n $iw '─') set -l p (string repeat -n (math --scale=0 "max(0, ($COLUMNS - ($iw + 2)) / 2)") ' ') # Label field is 13 wide (one wider than __config_settings_draw's 12) -- - # the longest real sub-category label ("Notifications") is 13 chars. - # Description field absorbs the difference so every row still totals - # iw+2, matching the surrounding box lines exactly. - set -l label_w 13 - set -l desc_w (math $iw - 34) + # the longest real sub-category label ("Notifications") is 13 chars. The + # description field absorbs the difference inside the frame + # (field_w = iw - 21 - label_w = iw - 34), so every row still totals iw+2. set -l cat_label (string replace -r '^__fish_config_op_' '' -- $category_var) # Scope indicator: toggling a row on this page writes -U (Universal, @@ -72,32 +63,18 @@ function __config_settings_draw_subcat set -l scope_label Universal test "$cur_scope" = session; and set scope_label Session # Title layout is "┌─ Sub-categories: