diff --git a/README.md b/README.md index 22fdf30..e9e29fe 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,8 @@ Then open a new Fish shell — Fisher will be installed automatically on first l A [chezmoi](https://www.chezmoi.io/) dotfile manager is also configured — secrets are kept in a private overlay directory (see [Personalization](#personalization)) and excluded from version control. +**External requirements.** Everything degrades gracefully if a tool is missing, with two exceptions worth calling out. `python3` is required by the documentation pipeline and by `config-settings`, whose TUI is drawn with the stdlib `curses` module. That module ships with CPython on Arch, Fedora and a full Debian/Ubuntu `python3`; `python3-minimal` alone does **not** carry `_curses`, so install the complete `python3` package there. `config-settings` checks for both and tells you which is missing rather than failing inside the renderer. + > [!IMPORTANT] > `config.fish` ends with a `return` sentinel guard. Any lines appended **after** it by a tool's setup command will silently have no effect. Many tools (starship, zoxide, mise, etc.) offer a setup command that appends an `init | source` line to your `config.fish` — all integrations are managed through `conf.d/` files instead. If you add a new tool and its shell integration appears to do nothing, check whether its setup command appended an init line to the bottom of `config.fish` and create a `conf.d/.fish` file for it instead. @@ -288,7 +290,7 @@ To opt out, set `__fish_user_dots_symlink` to a falsy value (or toggle **Dots li Everything opinionated in this config — command shadows, startup side-effects, key and environment overrides, terminal integrations, and the first-run greeting — is active by default but can be switched off. Logging (C5) is the exception: it is **opt-in**, off until you explicitly enable it. -> **The easy way — `config-settings`:** Run `config-settings` for an interactive TUI that manages settings across four pages — **Universal** and **Session** (the opinionated category toggles below, persistent or per-shell), **Sponge** (history-scrubbing: delay, exit codes, purge-on-exit, and extra sensitive variable names), and **Paths** (scrollback log dir, max files, and the user-dots path) — without typing a single variable name. Navigate with the arrow keys (or `h`/`j`/`k`/`l`); toggle rows step OFF ← DEFAULT → ON, value rows edit inline with `Enter` and clear with `←`. `Tab`/`Shift-Tab` cycle pages and `q` quits. Changes apply instantly. The panel auto-sizes to your terminal width (four tiers from 52- to 78-wide with a 6-column margin), centers itself horizontally, and redraws within ~0.3 s of a resize. +> **The easy way — `config-settings`:** Run `config-settings` for an interactive TUI that manages settings across four pages — **Universal** and **Session** (the opinionated category toggles below, persistent or per-shell), **Sponge** (history-scrubbing: delay, exit codes, purge-on-exit, and extra sensitive variable names), and **Paths** (scrollback log dir, max files, and the user-dots path) — without typing a single variable name. Navigate with the arrow keys (or `h`/`j`/`k`/`l`); toggle rows step OFF ← DEFAULT → ON, value rows edit inline with `Enter` and reset with `←`. `Enter` on a category opens its sub-categories, `/` filters the page — reaching into sub-categories too, listed as `Category › Sub` — `?` opens a help overlay, `Tab`/`Shift-Tab` cycle pages, and `q` applies your edits and quits. Edits are collected as you make them and written in one batch on exit; the status bar shows the pending count. The panel is drawn with Python's stdlib `curses`, so it resizes with the terminal and never flickers — see [Installation](#installation) for the `python3` requirement. If you'd rather set them by hand, each category is controlled by a universal variable. Six category toggles and one master switch are available: @@ -329,8 +331,10 @@ Each category further sub-divides into two to six sub-categories with their own `__fish_config_op__` toggles (e.g. `__fish_config_op_aliases_filesystem`), following the exact same truthy/falsy/unset cascade one level deeper. Run `config-settings` and -press Enter on a category row to browse and toggle its sub-categories, or -see the [Components Reference](https://fish.rootiest.fyi/08-components-reference/) +press Enter on a category row to browse and toggle its sub-categories — +or press `/` and type, which searches sub-categories across every +category at once and lists the hits as `Category › Sub`. Or see the +[Components Reference](https://fish.rootiest.fyi/08-components-reference/) for the full sub-category list per category. --- diff --git a/functions/__config_settings_diff_redraw.fish b/functions/__config_settings_diff_redraw.fish deleted file mode 100644 index f5d9621..0000000 --- a/functions/__config_settings_diff_redraw.fish +++ /dev/null @@ -1,47 +0,0 @@ -# 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 deleted file mode 100644 index f4d975b..0000000 --- a/functions/__config_settings_draw.fish +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright (C) 2026 Rootiest -# SPDX-License-Identifier: AGPL-3.0-or-later - -# SYNOPSIS -# __config_settings_draw ... -# -# DESCRIPTION -# Renders the 16-line config-settings TUI panel to stdout. Panel width and -# horizontal position are chosen automatically from $COLUMNS each call, -# so a terminal resize takes effect on the next keypress without any -# extra bookkeeping. Four width tiers with a 6-col buffer per side: -# -# COLUMNS ≥ 90 → 78-wide (IW=76, desc=43 chars) -# COLUMNS ≥ 86 → 74-wide (IW=72, desc=39 chars) -# COLUMNS ≥ 82 → 70-wide (IW=68, desc=35 chars) -# COLUMNS < 82 → 52-wide (IW=50, desc=17 chars) ← default -# -# The box is horizontally centered via a left-padding prefix on every -# output line. \e[16A\e[J erases by line count so the horizontal offset -# does not interfere with the redraw loop. -# -# ARGUMENTS -# cur_row 0–6, the currently highlighted row -# cur_scope "universal" or "session" -# var1–var7 Variable names for rows 0–6 (6 categories + master) -# -# EXIT STATUS -# 0 Always -# -# EXAMPLE -# __config_settings_draw 0 universal \ -# __fish_config_op_aliases __fish_config_op_autoexec \ -# __fish_config_op_overrides __fish_config_op_integrations \ -# __fish_config_op_logging __fish_config_op_greeting \ -# __fish_config_opinionated -function __config_settings_draw - set -l cur_row $argv[1] - set -l cur_scope $argv[2] - set -l vars $argv[3..] - - __fish_palette - - set -l labels Aliases Auto-exec Overrides Integrations Logging Greeting Master - - # ── 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. - # 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 \ - "keys/env/prompt" \ - "terminal coupling" \ - scrollback \ - fish_greeting \ - "disable all" - - 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 '─') - - # ── Center padding ──────────────────────────────────────────────────── - # ponytail: floor division — left margin may be 1 col less than right if gap is odd - set -l p (string repeat -n (math --scale=0 "max(0, ($COLUMNS - ($iw + 2)) / 2)") ' ') - - # ── Top border ──────────────────────────────────────────────────────── - # ┌─ Opinionated Settings (iw-23)×─ ┐ total = iw+2 - __config_settings_frame title $iw $p "$c_head Opinionated Settings $c_reset" - - # ── Page-tab header ─────────────────────────────────────────────────── - set -l active_idx 0 - if test $cur_scope = session - set active_idx 1 - end - printf '%s│%s│\n' $p (__config_settings_pagetab $active_idx $iw) - - # ── Top divider ─────────────────────────────────────────────────────── - 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 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 ─────────────────────────────────────────── - printf '%s│ %s │\n' $p (string repeat -n (math $iw - 6) '─') - - # ── Master row (index 6) ────────────────────────────────────────────── - set -l val (__config_settings_get_val $vars[7] $cur_scope) - __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 \ - "$c_dim→ Tab for Sponge & Path settings$c_reset" \ - (string repeat -n (math $iw - 34) ' ') - printf '%s│%s│\n' $p (string repeat -n $iw ' ') - - # ── Bottom divider ──────────────────────────────────────────────────── - printf '%s│%s│\n' $p $HBR - - # ── Keybind hint ────────────────────────────────────────────────────── - # string pad is width-aware (arrows count as 1 column) - set -l hint " ↑↓/kj move ←→/hl set Enter sub-cats Tab pg q quit" - printf '%s│%s%s%s│\n' $p $c_dim (string pad -r -w $iw -- $hint) $c_reset - - # ── Bottom border ───────────────────────────────────────────────────── - printf '%s└%s┘\n' $p $HBR -end diff --git a/functions/__config_settings_draw_subcat.fish b/functions/__config_settings_draw_subcat.fish deleted file mode 100644 index 6920ece..0000000 --- a/functions/__config_settings_draw_subcat.fish +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (C) 2026 Rootiest -# SPDX-License-Identifier: AGPL-3.0-or-later - -# SYNOPSIS -# __config_settings_draw_subcat -# -# DESCRIPTION -# Renders the sub-category drill-down page for one C1-C6 category: -# the category's own toggle at the top (still meaningful as the cascade -# default for its sub-categories), then one row per sub-category from -# __config_settings_subcats, sized dynamically instead of the fixed -# 6-row layout __config_settings_draw uses for the category list. -# Follows the same width-tier and center-padding conventions as -# __config_settings_draw so the panel doesn't visibly jump between the -# two pages. -# -# Label and description fields are defensively truncated to their field -# width before padding (string pad only ever grows a string, never -# shrinks it) -- sub-category labels/descriptions are static data from -# __config_settings_subcats, not authored per width-tier the way -# __config_settings_draw's own category descriptions are, so a couple of -# them are longer than the narrower tiers' fields (e.g. "Notifications" -# is 13 chars against a 12-char label field; several descriptions run -# well past the 17-char field at the narrowest tier). Truncating keeps -# the box perfectly rectangular in every case instead of only in the -# cases the static text happens to fit. -# -# ARGUMENTS -# cur_row 0-based highlighted row (0 = the category's own toggle; -# 1..N = sub-category rows) -# cur_scope "universal" or "session" -# category_var One of the six __fish_config_op_ names -# -# EXIT STATUS -# 0 Always -# -# EXAMPLE -# __config_settings_draw_subcat 1 universal __fish_config_op_aliases -function __config_settings_draw_subcat - set -l cur_row $argv[1] - set -l cur_scope $argv[2] - set -l category_var $argv[3] - - __fish_palette - - set -l rows (__config_settings_subcats $category_var) - set -l n (count $rows) - - # ── Width tier: matches __config_settings_draw's 6-col-per-side steps ── - 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. 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, - # persistent) or -g (Session, this-shell-only) -- the title must say - # which, since it isn't otherwise visible anywhere on the page. - set -l scope_label Universal - test "$cur_scope" = session; and set scope_label Session - # Title layout is "┌─ Sub-categories: