Merge pull request 'feat(config): add sub-category granularity to opinionated components' (#107) from worktree-opinionated-subcategories into main
Generate documentation / build-docs (push) Failing after 43s
Generate documentation / build-docs (push) Failing after 43s
This commit was merged in pull request #107.
This commit is contained in:
@@ -11,6 +11,8 @@ on:
|
||||
- "docs/verify-manual.py"
|
||||
- "docs/site/**"
|
||||
- "functions/**"
|
||||
- "conf.d/**"
|
||||
- "config.fish"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -76,7 +78,7 @@ jobs:
|
||||
run: |
|
||||
git config user.name "Gitea Actions"
|
||||
git config user.email "actions@gitea"
|
||||
git add docs/fish-config.md docs/fish-config.1
|
||||
git add docs/fish-config.md docs/fish-config.1 conf.d/__fish_config_op_registry.fish
|
||||
git diff --cached --quiet && echo "No changes to commit" && exit 0
|
||||
git commit -m "chore(docs): regenerate manual and man page"
|
||||
git commit -m "chore(docs): regenerate manual, man page, and component registry"
|
||||
git push
|
||||
|
||||
@@ -320,6 +320,14 @@ set -Ue __fish_config_op_greeting
|
||||
|
||||
Command shadows react immediately; bindings, prompt, and abbreviations take effect in new shells. With aliases disabled, `rm` deletes permanently again instead of trashing. See `help config opinionated` for the full component list.
|
||||
|
||||
Each category further sub-divides into two to six sub-categories with
|
||||
their own `__fish_config_op_<category>_<subcategory>` 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/)
|
||||
for the full sub-category list per category.
|
||||
|
||||
---
|
||||
|
||||
## Attribution
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# GENERATED FILE --- do not edit by hand.
|
||||
# Regenerate with __fish_config_op_registry_rebuild after editing a
|
||||
# # COMPONENT header, or automatically via docs/build-manual.py.
|
||||
# Source: docs/generate_component_registry.py
|
||||
#
|
||||
# This file must be sourced before any other conf.d/*.fish file that
|
||||
# calls the opinionated guard. That currently holds only because fish's
|
||||
# glob-based conf.d loading happens to sort this filename first
|
||||
# alphabetically among the guard-calling files -- do not rename it
|
||||
# without preserving that ordering.
|
||||
|
||||
set -g __fish_config_op_registry_keys \
|
||||
"__auto_source_fallback_venv:" \
|
||||
"__fish_config_sync_logging:" \
|
||||
"__fish_user_dots_link:" \
|
||||
"_zellij_dump_log:" \
|
||||
"abbr:abbr-integrations" \
|
||||
"abbr:abbr-overrides" \
|
||||
"agy:" \
|
||||
"auto-pull:" \
|
||||
"autopair:" \
|
||||
"bash:" \
|
||||
"bash_expands:" \
|
||||
"cat:" \
|
||||
"claude:" \
|
||||
"config:cachyos-strip-aliases" \
|
||||
"config:cachyos-strip-overrides" \
|
||||
"config:cachyos-tricks" \
|
||||
"config:cdpath" \
|
||||
"config:exit-wiring" \
|
||||
"config:greeting-stamp" \
|
||||
"config:pager-editor-gpg" \
|
||||
"config:path-setup" \
|
||||
"config:vi-mode" \
|
||||
"done:" \
|
||||
"du:" \
|
||||
"edit:" \
|
||||
"first_run:first-run-bootstrap" \
|
||||
"first_run:first-run-greeting" \
|
||||
"fish_right_prompt:" \
|
||||
"help:" \
|
||||
"hist:" \
|
||||
"key_bindings:" \
|
||||
"kitty-logging:" \
|
||||
"kitty-watcher-reminder:" \
|
||||
"less:" \
|
||||
"logs:" \
|
||||
"ls:" \
|
||||
"mkdir:" \
|
||||
"mv:" \
|
||||
"paru-wrapper:paru-autoexec" \
|
||||
"paru-wrapper:paru-logging" \
|
||||
"ping:" \
|
||||
"puffer:" \
|
||||
"rg:" \
|
||||
"rm:" \
|
||||
"smart_exit:exit-plain" \
|
||||
"smart_exit:logging-guard" \
|
||||
"split:" \
|
||||
"spwin:" \
|
||||
"ssh:" \
|
||||
"starship:" \
|
||||
"tab:" \
|
||||
"theme:" \
|
||||
"tmux-logging:" \
|
||||
"top:" \
|
||||
"tricks:aliases-tricks" \
|
||||
"tricks:tricks-bang" \
|
||||
"tricks:tricks-manpager" \
|
||||
"upgrade:" \
|
||||
"wakatime:wakatime-autoexec" \
|
||||
"wakatime:wakatime-hook" \
|
||||
"yay-wrapper:yay-autoexec" \
|
||||
"yay-wrapper:yay-logging" \
|
||||
"yt-dlp:" \
|
||||
"zoxide:"
|
||||
|
||||
set -g __fish_config_op_registry_values \
|
||||
"autoexec/venv" \
|
||||
"logging/terminal-capture" \
|
||||
"autoexec/sync" \
|
||||
"logging/multiplexer-capture" \
|
||||
"integrations/terminal-abbrs" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/dev-tools" \
|
||||
"autoexec/sync" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/shell-tools" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/dev-tools" \
|
||||
"aliases/filesystem" \
|
||||
"overrides/key-bindings" \
|
||||
"overrides/environment" \
|
||||
"overrides/environment" \
|
||||
"overrides/key-bindings" \
|
||||
"greeting/greeting-message" \
|
||||
"overrides/environment" \
|
||||
"overrides/environment" \
|
||||
"overrides/key-bindings" \
|
||||
"integrations/notifications" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/dev-tools" \
|
||||
"autoexec/plugin-management" \
|
||||
"greeting/first-run" \
|
||||
"overrides/prompt" \
|
||||
"aliases/shell-tools" \
|
||||
"integrations/history-logs" \
|
||||
"overrides/key-bindings" \
|
||||
"logging/terminal-capture" \
|
||||
"logging/terminal-capture" \
|
||||
"aliases/shell-tools" \
|
||||
"integrations/history-logs" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/filesystem" \
|
||||
"aliases/filesystem" \
|
||||
"autoexec/pkg-wrappers" \
|
||||
"logging/pkg-logs" \
|
||||
"aliases/network" \
|
||||
"overrides/key-bindings" \
|
||||
"aliases/search" \
|
||||
"aliases/filesystem" \
|
||||
"overrides/key-bindings" \
|
||||
"logging/terminal-capture" \
|
||||
"integrations/window-mgmt" \
|
||||
"integrations/window-mgmt" \
|
||||
"aliases/network" \
|
||||
"overrides/prompt" \
|
||||
"integrations/window-mgmt" \
|
||||
"overrides/prompt" \
|
||||
"logging/multiplexer-capture" \
|
||||
"aliases/monitor" \
|
||||
"aliases/filesystem" \
|
||||
"overrides/key-bindings" \
|
||||
"overrides/environment" \
|
||||
"integrations/pkg-upgrade" \
|
||||
"autoexec/telemetry" \
|
||||
"integrations/notifications" \
|
||||
"autoexec/pkg-wrappers" \
|
||||
"logging/pkg-logs" \
|
||||
"aliases/network" \
|
||||
"aliases/filesystem"
|
||||
|
||||
+7
-3
@@ -8,6 +8,10 @@
|
||||
# This file contains all the abbreviations for the terminal.
|
||||
# It is sourced by Fish on startup.
|
||||
|
||||
# COMPONENT
|
||||
# site abbr-integrations: integrations/terminal-abbrs
|
||||
# site abbr-overrides: overrides/key-bindings
|
||||
|
||||
# Neovim
|
||||
# @category Editors
|
||||
# @desc nvim
|
||||
@@ -155,7 +159,7 @@ abbr -a ag. agy .
|
||||
# @desc exit
|
||||
abbr -a /exit exit
|
||||
# Window-management abbreviations are opinionated (C4 integrations)
|
||||
if __fish_config_op_enabled __fish_config_op_integrations
|
||||
if __fish_config_op_enabled (status basename) abbr-integrations
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
# @desc Close current pane/window
|
||||
@@ -208,7 +212,7 @@ abbr -a speedtest-fast fast-cli
|
||||
|
||||
# Kitty/WezTerm window-management abbreviations are opinionated (C4
|
||||
# integrations): they assume an active Kitty or WezTerm session.
|
||||
if __fish_config_op_enabled __fish_config_op_integrations
|
||||
if __fish_config_op_enabled (status basename) abbr-integrations
|
||||
# Window Creation (OS Windows)
|
||||
if test "$TERM" = xterm-kitty
|
||||
# @category Terminal Windows, Tabs, and Panes
|
||||
@@ -666,7 +670,7 @@ abbr -a url-open open-url
|
||||
### History Expansions and Substitutions ###
|
||||
# Bash-style history expansion is opinionated (C3 overrides), gated atomically
|
||||
# with conf.d/tricks.fish, conf.d/puffer.fish, and functions/expand_*.fish.
|
||||
if __fish_config_op_enabled __fish_config_op_overrides
|
||||
if __fish_config_op_enabled (status basename) abbr-overrides
|
||||
# @category History Expansion
|
||||
# @name !^
|
||||
# @desc Expand to the first argument of the previous command
|
||||
|
||||
@@ -14,8 +14,11 @@
|
||||
# Manage the registry with: auto-pull add / remove / list / status
|
||||
|
||||
# C2 guard: when auto-execution is disabled, do not register the handler.
|
||||
__fish_config_op_enabled __fish_config_op_autoexec; or exit
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
|
||||
# COMPONENT
|
||||
# autoexec/sync
|
||||
#
|
||||
# SYNOPSIS
|
||||
# __auto_pull_on_pwd (event handler, --on-variable PWD)
|
||||
#
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
status is-interactive || exit
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). Bracket
|
||||
# auto-pairing intercepts single-character input, classified as C3 overrides.
|
||||
__fish_config_op_enabled __fish_config_op_overrides || exit
|
||||
__fish_config_op_enabled (status basename) || exit
|
||||
|
||||
set --global autopair_left "(" "[" "{" '"' "'"
|
||||
set --global autopair_right ")" "]" "}" '"' "'"
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# Provides bash-style history expansion functions for abbreviations.
|
||||
# These functions are gated by the C3 overrides switch.
|
||||
|
||||
# Execute expand_bang_all
|
||||
function expand_bang_all --description 'Execute expand_bang_all'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return 1
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
set -l token $argv[1]
|
||||
if test -z "$token"; set token (commandline -t); end
|
||||
@@ -23,7 +26,7 @@ end
|
||||
# Execute expand_bang_caret
|
||||
function expand_bang_caret --description 'Execute expand_bang_caret'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return 1
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
# Split the last history item into a list
|
||||
set -l tokens (string split -n ' ' -- $history[1])
|
||||
@@ -36,7 +39,7 @@ end
|
||||
# Execute expand_bang_minus_n
|
||||
function expand_bang_minus_n --description 'Execute expand_bang_minus_n'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return 1
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
set -l token $argv[1]
|
||||
if test -z "$token"; set token (commandline -t); end
|
||||
@@ -58,7 +61,7 @@ end
|
||||
# Execute expand_bang_search
|
||||
function expand_bang_search --description 'Execute expand_bang_search'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return 1
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
set -l token $argv[1]
|
||||
if test -z "$token"
|
||||
@@ -84,7 +87,7 @@ end
|
||||
# Execute expand_bang_string
|
||||
function expand_bang_string --description 'Execute expand_bang_string'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return 1
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
# Fish 4.x passes the matched token as argv[1]
|
||||
set -l token $argv[1]
|
||||
@@ -112,7 +115,7 @@ end
|
||||
# Execute expand_typo_sub
|
||||
function expand_typo_sub --description 'Execute expand_typo_sub'
|
||||
# Opinionated guard (C3): no expansion when overrides are disabled.
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return 1
|
||||
__fish_config_op_enabled (status basename); or return 1
|
||||
|
||||
# In newer Fish, the matched token is often passed as $argv[1]
|
||||
# if the abbr is set up correctly. We'll fallback to commandline just in case.
|
||||
|
||||
+4
-1
@@ -19,6 +19,9 @@
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/notifications
|
||||
|
||||
if not status is-interactive
|
||||
exit
|
||||
@@ -26,7 +29,7 @@ end
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). Desktop
|
||||
# notifications assume a graphical session, classified as C4 integrations.
|
||||
__fish_config_op_enabled __fish_config_op_integrations; or exit
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
|
||||
set -g __done_version 1.19.1
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#
|
||||
# Runs exactly once on the first interactive fish session after install.
|
||||
# To reset for testing, run: set -Ue __fish_config_first_run_complete
|
||||
#
|
||||
# COMPONENT
|
||||
# site first-run-greeting: greeting/first-run
|
||||
# site first-run-bootstrap: autoexec/plugin-management
|
||||
|
||||
# Exit early in non-interactive shells (scripts, completions, subshells)
|
||||
if not status is-interactive
|
||||
@@ -36,7 +40,7 @@ end
|
||||
# Printing a first-run welcome banner is opinionated (C6 greeting). The
|
||||
# first-run state variable is already set unconditionally above, so
|
||||
# disabling the greeting never re-triggers this file.
|
||||
if __fish_config_op_enabled __fish_config_op_greeting
|
||||
if __fish_config_op_enabled (status basename) first-run-greeting
|
||||
echo ""
|
||||
echo " Welcome to your fish shell configuration!"
|
||||
echo " Run 'help config' for offline documentation."
|
||||
@@ -48,7 +52,7 @@ end
|
||||
# Startup side-effects below (Fisher curl, fisher update, theme apply) are
|
||||
# opinionated (C2 auto-execution). The first-run state variable is already
|
||||
# set above either way, so disabling auto-exec never re-triggers this file.
|
||||
if not __fish_config_op_enabled __fish_config_op_autoexec
|
||||
if not __fish_config_op_enabled (status basename) first-run-bootstrap
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
+4
-1
@@ -5,6 +5,9 @@
|
||||
# │ help config wrapper │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/shell-tools
|
||||
#
|
||||
# SYNOPSIS
|
||||
# help [topic] [sub-topic...]
|
||||
# help config [section] [-w|--html] [-m|--man] [-h|--help]
|
||||
@@ -50,7 +53,7 @@ end
|
||||
# --- Wrapper Definition ---
|
||||
function help --wraps help --description "Custom wrapper to intercept 'help config'"
|
||||
# Opinionated guard (C1): fall back to the native fish help when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
__original_help $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
# This file defines custom key bindings for the Fish shell.
|
||||
# It is sourced by Fish on startup.
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# ────────────────── Bind Prewious Path Head to Ctrl+G ─────────────────
|
||||
# Bindings to insert the previous path head into the command line
|
||||
# Behaves like `!$:h` does in bash
|
||||
@@ -48,7 +51,11 @@ function fish_user_key_bindings
|
||||
|
||||
# Custom key chords are opinionated (C3 overrides); skip them entirely
|
||||
# when overrides are disabled so stock bindings remain untouched.
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return
|
||||
# NOTE: (status basename), not (status current-function) -- this guard
|
||||
# lives inside fish's own reserved fish_user_key_bindings function, whose
|
||||
# name is not this file's identity; the registry key is this file's
|
||||
# bare basename, key_bindings.
|
||||
__fish_config_op_enabled (status basename); or return
|
||||
|
||||
# ───────────────────────────── Set Bindings ─────────────────────────────
|
||||
#
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# logging/terminal-capture
|
||||
|
||||
#
|
||||
# C5 — Logging & Capture: a non-blocking, per-session reminder shown inside Kitty
|
||||
# when the fish-config scrollback watcher is not yet set up. It never blocks the
|
||||
@@ -10,7 +14,7 @@
|
||||
status is-interactive; or exit
|
||||
type -q kitty; or exit
|
||||
set -q KITTY_WINDOW_ID; or exit
|
||||
__fish_config_op_enabled __fish_config_op_logging; or exit
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
__fish_variable_check __fish_config_kitty_watcher_dismissed; and exit
|
||||
__kitty_logging_has_watcher; and exit
|
||||
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
# bars are preserved, renders the captured animation to a clean static log
|
||||
# (via scripts/clean_progress_log.py), and prunes old logs.
|
||||
|
||||
# COMPONENT
|
||||
# site paru-autoexec: autoexec/pkg-wrappers
|
||||
# site paru-logging: logging/pkg-logs
|
||||
|
||||
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
|
||||
# Wrapper generation is also gated by C5 (Logging & Capture).
|
||||
__fish_config_op_enabled __fish_config_op_autoexec; or return
|
||||
__fish_config_op_enabled (status basename) paru-autoexec; or return
|
||||
|
||||
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
|
||||
if not __fish_config_op_enabled __fish_config_op_logging
|
||||
if not __fish_config_op_enabled (status basename) paru-logging
|
||||
if test -f "$HOME/.local/bin/paru"
|
||||
and grep -q "# paru-wrapper-version:" "$HOME/.local/bin/paru" 2>/dev/null
|
||||
rm -f "$HOME/.local/bin/paru"
|
||||
|
||||
+4
-1
@@ -1,9 +1,12 @@
|
||||
status is-interactive || exit
|
||||
|
||||
# COMPONENT
|
||||
# overrides/key-bindings
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). Puffer's key
|
||||
# intercepts are part of the bang-bang system, gated atomically under C3
|
||||
# overrides with conf.d/tricks.fish, conf.d/abbr.fish, and expand_*.fish.
|
||||
__fish_config_op_enabled __fish_config_op_overrides || exit
|
||||
__fish_config_op_enabled (status basename) || exit
|
||||
|
||||
function _puffer_fish_key_bindings --on-variable fish_key_bindings
|
||||
set -l modes
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# overrides/prompt
|
||||
|
||||
#
|
||||
# Defines fish_prompt only when starship is installed.
|
||||
# Without starship, fish's built-in prompt already emits OSC 133;A
|
||||
# on the prompt line itself, so no wrapper is needed.
|
||||
|
||||
# Replacing the prompt is opinionated (C3 overrides)
|
||||
__fish_config_op_enabled __fish_config_op_overrides; or return
|
||||
__fish_config_op_enabled (status basename); or return
|
||||
|
||||
type -q starship; or return
|
||||
|
||||
|
||||
+5
-1
@@ -1,5 +1,9 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# overrides/prompt
|
||||
|
||||
#
|
||||
# ╭──────────────────────────────────────────────────────────╮
|
||||
# │ Fish Theme │
|
||||
@@ -9,7 +13,7 @@
|
||||
# Forcing theme colors and $FZF_DEFAULT_OPTS is opinionated (C3 overrides).
|
||||
# The FZF variable is universal, so clean up our Catppuccin value if it
|
||||
# lingers from a session where overrides were still enabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_overrides
|
||||
if not __fish_config_op_enabled (status basename)
|
||||
if set -q FZF_DEFAULT_OPTS; and string match -q '*#1E1E2E*' -- "$FZF_DEFAULT_OPTS"
|
||||
set --erase FZF_DEFAULT_OPTS
|
||||
end
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# logging/multiplexer-capture
|
||||
|
||||
#
|
||||
# C5 — Logging & Capture: starts a pipe-pane log for the current tmux pane
|
||||
# when fish launches inside a tmux session. Each fish shell gets its own
|
||||
# timestamped log file in SCROLLBACK_HISTORY_DIR (default: ~/.terminal_history).
|
||||
# Naming: tmux_<session>-w<window>-p<pane>_YYYY-MM-DD_HH-MM-SS.log
|
||||
|
||||
__fish_config_op_enabled __fish_config_op_logging; or exit
|
||||
__fish_config_op_enabled (status basename); or exit
|
||||
status is-interactive; or exit
|
||||
type -q tmux; or exit
|
||||
set -q TMUX; or exit
|
||||
|
||||
+9
-4
@@ -7,6 +7,11 @@
|
||||
# │ system aliases, and history/backup utilities │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
|
||||
# COMPONENT
|
||||
# site aliases-tricks: aliases/filesystem
|
||||
# site tricks-manpager: overrides/environment
|
||||
# site tricks-bang: overrides/key-bindings
|
||||
|
||||
## Environment setup
|
||||
# Apply .profile: use this to put fish compatible .profile stuff in
|
||||
if test -f ~/.fish_profile
|
||||
@@ -24,7 +29,7 @@ end
|
||||
|
||||
# Format man pages using bat (only if bat is installed)
|
||||
# Overriding $MANPAGER is opinionated (C3 overrides)
|
||||
if type -q bat; and __fish_config_op_enabled __fish_config_op_overrides
|
||||
if type -q bat; and __fish_config_op_enabled (status basename) tricks-manpager
|
||||
set -gx MANROFFOPT -c
|
||||
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
|
||||
end
|
||||
@@ -37,7 +42,7 @@ set -gx __done_notification_urgency_level low
|
||||
# Functions needed for !! and !$ https://github.com/oh-my-fish/plugin-bang-bang
|
||||
# The bang-bang system is opinionated (C3 overrides) and is gated atomically
|
||||
# here, in conf.d/abbr.fish, conf.d/puffer.fish, and functions/expand_*.fish.
|
||||
if __fish_config_op_enabled __fish_config_op_overrides
|
||||
if __fish_config_op_enabled (status basename) tricks-bang
|
||||
function __history_previous_command
|
||||
switch (commandline -t)
|
||||
case "!"
|
||||
@@ -83,7 +88,7 @@ end
|
||||
# Fish command history override to show timestamps
|
||||
# Shadowing the history command is opinionated (C1 aliasing); when disabled,
|
||||
# the function is never defined and fish's stock history behavior applies.
|
||||
if __fish_config_op_enabled __fish_config_op_aliases
|
||||
if __fish_config_op_enabled (status basename) aliases-tricks
|
||||
function history
|
||||
builtin history --show-time='%F %T '
|
||||
end
|
||||
@@ -123,7 +128,7 @@ alias .....='cd ../../../..'
|
||||
alias ......='cd ../../../../..'
|
||||
|
||||
# Silent flag injection into POSIX tools is opinionated (C1 aliasing)
|
||||
if __fish_config_op_enabled __fish_config_op_aliases
|
||||
if __fish_config_op_enabled (status basename) aliases-tricks
|
||||
# Tools & Core command color overrides
|
||||
# @category Shell Aliases
|
||||
# @desc dir --color=auto
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
# see: https://github.com/ik11235/wakatime.fish
|
||||
###
|
||||
|
||||
# COMPONENT
|
||||
# site wakatime-autoexec: autoexec/telemetry
|
||||
# site wakatime-hook: integrations/notifications
|
||||
|
||||
# Local modification: opinionated guard (AGENTS.md Task #3). WakaTime
|
||||
# reporting is classified under both C2 auto-execution and C4 integrations;
|
||||
# disabling either category skips registering the hook.
|
||||
__fish_config_op_enabled __fish_config_op_autoexec; or exit
|
||||
__fish_config_op_enabled __fish_config_op_integrations; or exit
|
||||
__fish_config_op_enabled (status basename) wakatime-autoexec; or exit
|
||||
__fish_config_op_enabled (status basename) wakatime-hook; or exit
|
||||
|
||||
function __register_wakatime_fish_before_exec -e fish_postexec
|
||||
if set -q FISH_WAKATIME_DISABLED
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
# bars are preserved, renders the captured animation to a clean static log
|
||||
# (via scripts/clean_progress_log.py), and prunes old logs.
|
||||
|
||||
# COMPONENT
|
||||
# site yay-autoexec: autoexec/pkg-wrappers
|
||||
# site yay-logging: logging/pkg-logs
|
||||
|
||||
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
|
||||
# Wrapper generation is also gated by C5 (Logging & Capture).
|
||||
__fish_config_op_enabled __fish_config_op_autoexec; or return
|
||||
__fish_config_op_enabled (status basename) yay-autoexec; or return
|
||||
|
||||
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
|
||||
if not __fish_config_op_enabled __fish_config_op_logging
|
||||
if not __fish_config_op_enabled (status basename) yay-logging
|
||||
if test -f "$HOME/.local/bin/yay"
|
||||
and grep -q "# yay-wrapper-version:" "$HOME/.local/bin/yay" 2>/dev/null
|
||||
rm -f "$HOME/.local/bin/yay"
|
||||
|
||||
+4
-1
@@ -3,6 +3,9 @@
|
||||
# Adapted from icezyclon/zoxide.fish (MIT)
|
||||
# Heavily customized for Fish 4.x compatibility and performance
|
||||
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
|
||||
if status is-interactive
|
||||
|
||||
if type -q zoxide
|
||||
@@ -65,7 +68,7 @@ if status is-interactive
|
||||
|
||||
# Shadowing cd with zoxide is opinionated (C1 aliasing); z and zi
|
||||
# remain available either way.
|
||||
if __fish_config_op_enabled __fish_config_op_aliases
|
||||
if __fish_config_op_enabled (status basename)
|
||||
alias cd=z
|
||||
end
|
||||
|
||||
|
||||
+21
-10
@@ -7,7 +7,7 @@
|
||||
|
||||
# ───────────────────── Opinionated component guards ─────────────────────
|
||||
# Opinionated components (AGENTS.md Task #3) are wrapped in
|
||||
# __fish_config_op_enabled <category> guards throughout this file and conf.d/.
|
||||
# __fish_config_op_enabled <identity> [<site>] guards throughout this file and conf.d/.
|
||||
# The helper always evaluates the master switch __fish_config_opinionated
|
||||
# first (falsy disables everything), then the per-category opt-out variable:
|
||||
# __fish_config_op_aliases C1 — command shadows / flag injection
|
||||
@@ -21,12 +21,23 @@
|
||||
# C5 is the one exception: it defaults to disabled and needs an explicit
|
||||
# truthy value — set -U __fish_config_op_logging on
|
||||
|
||||
# COMPONENT
|
||||
# site cachyos-tricks: overrides/environment
|
||||
# site cachyos-strip-aliases: aliases/filesystem
|
||||
# site cachyos-strip-overrides: overrides/key-bindings
|
||||
# site pager-editor-gpg: overrides/environment
|
||||
# site exit-wiring: overrides/key-bindings
|
||||
# site path-setup: overrides/environment
|
||||
# site cdpath: overrides/environment
|
||||
# site vi-mode: overrides/key-bindings
|
||||
# site greeting-stamp: greeting/greeting-message
|
||||
|
||||
# ──────────────────────── Source CachyOS configs ────────────────────────
|
||||
if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
|
||||
source /usr/share/cachyos-fish-config/cachyos-config.fish
|
||||
# Surgically overriding the distro config is opinionated (C3 overrides):
|
||||
# skip it entirely when overrides are disabled, keeping CachyOS defaults.
|
||||
if __fish_config_op_enabled __fish_config_op_overrides
|
||||
if __fish_config_op_enabled (status basename) cachyos-tricks
|
||||
# Source our tricks over the cachyOS config
|
||||
test -f "$__fish_config_dir/conf.d/tricks.fish"
|
||||
and source "$__fish_config_dir/conf.d/tricks.fish"
|
||||
@@ -41,7 +52,7 @@ if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
|
||||
# The distro config ships opinionated pieces of its own (it is the origin
|
||||
# of tricks.fish); strip them when the matching category is disabled so
|
||||
# the guards hold on CachyOS systems too.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status basename) cachyos-strip-aliases
|
||||
for _fname in grep fgrep egrep dir vdir wget
|
||||
functions -q $_fname; and functions --erase $_fname
|
||||
end
|
||||
@@ -53,7 +64,7 @@ if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
|
||||
and source $__fish_data_dir/functions/$_fname.fish
|
||||
end
|
||||
end
|
||||
if not __fish_config_op_enabled __fish_config_op_overrides
|
||||
if not __fish_config_op_enabled (status basename) cachyos-strip-overrides
|
||||
for _fname in __history_previous_command __history_previous_command_arguments
|
||||
functions -q $_fname; and functions --erase $_fname
|
||||
end
|
||||
@@ -95,7 +106,7 @@ set -q WORDLIST; or set -gx WORDLIST "$XDG_CONFIG_HOME/hunspell_en_US"
|
||||
|
||||
# ─────────────────────────── Pager variables ────────────────────────────
|
||||
# Overriding $PAGER, $EDITOR, and $GPG_TTY is opinionated (C3 overrides)
|
||||
if __fish_config_op_enabled __fish_config_op_overrides
|
||||
if __fish_config_op_enabled (status basename) pager-editor-gpg
|
||||
if type -q ov
|
||||
set -gx PAGER ov
|
||||
else if type -q less
|
||||
@@ -136,7 +147,7 @@ and set -gx SCROLLBACK_HISTORY_MAX_FILES $__fish_scrollback_history_max_files
|
||||
# Wire up a clean exit function that won't fire on background subshells
|
||||
# Replacing the exit builtin is opinionated (C3 overrides); smart_exit also
|
||||
# guards itself so a live toggle takes effect without restarting the shell.
|
||||
if status is-interactive; and __fish_config_op_enabled __fish_config_op_overrides
|
||||
if status is-interactive; and __fish_config_op_enabled (status basename) exit-wiring
|
||||
function exit --description 'Safe interactive exit'
|
||||
# If the smart_exit file exists in our function path, invoke it explicitly
|
||||
if functions -q smart_exit
|
||||
@@ -153,7 +164,7 @@ end
|
||||
# the cargo bin directory is moved to the end of the PATH, which can help avoid conflicts
|
||||
# with system-installed Rust tools while still allowing user-installed cargo binaries to be found.
|
||||
# PATH setup is opinionated (C3 overrides)
|
||||
if __fish_config_op_enabled __fish_config_op_overrides
|
||||
if __fish_config_op_enabled (status basename) path-setup
|
||||
fish_add_path $HOME/.local/bin # Standard user-local executables (XDG spec)
|
||||
fish_add_path $HOME/.local/share/../bin # Alternative/legacy path for local user binaries
|
||||
fish_add_path $HOME/Applications # User-installed applications and standalone apps
|
||||
@@ -176,7 +187,7 @@ end
|
||||
# so if you have a directory named 'myproject' in the current directory,
|
||||
# running 'cd myproject' will take you there instead of $HOME/projects/myproject.
|
||||
# CDPATH injection is opinionated (C3 overrides)
|
||||
if __fish_config_op_enabled __fish_config_op_overrides
|
||||
if __fish_config_op_enabled (status basename) cdpath
|
||||
set -gx CDPATH . $HOME/projects $HOME
|
||||
end
|
||||
|
||||
@@ -191,7 +202,7 @@ if status is-interactive
|
||||
# This is optional but can improve the user experience for those who prefer Vi-style key bindings.
|
||||
# Global Vi mode is opinionated (C3 overrides); without it fish keeps its
|
||||
# default Emacs-style bindings.
|
||||
if __fish_config_op_enabled __fish_config_op_overrides
|
||||
if __fish_config_op_enabled (status basename) vi-mode
|
||||
set -g fish_key_bindings fish_vi_key_bindings
|
||||
end
|
||||
|
||||
@@ -251,7 +262,7 @@ if status is-interactive
|
||||
# function that distro configs set (e.g., CachyOS defines it as fastfetch).
|
||||
# This runs last inside the interactive block so our empty definition wins
|
||||
# over whatever cachyos-config.fish or vendor conf.d installed.
|
||||
if not __fish_config_op_enabled __fish_config_op_greeting
|
||||
if not __fish_config_op_enabled (status basename) greeting-stamp
|
||||
function fish_greeting
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,6 +15,7 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
import manualtools as mt
|
||||
import generate_component_registry
|
||||
|
||||
DOCS = Path(__file__).parent
|
||||
MANUAL = DOCS / "manual"
|
||||
@@ -840,6 +841,8 @@ def main() -> int:
|
||||
if not (args.concat or args.site):
|
||||
ap.error("nothing to do: pass --concat and/or --site")
|
||||
|
||||
generate_component_registry.main()
|
||||
|
||||
if args.site:
|
||||
src = DOCS / "site" / "src"
|
||||
out = src / "content" / "docs"
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Generate the committed opinionated-component registry.
|
||||
|
||||
Walks every `# COMPONENT` header in functions/*.fish, conf.d/*.fish, and
|
||||
config.fish and writes conf.d/__fish_config_op_registry.fish, the fish
|
||||
data file __fish_config_op_registry_lookup reads at shell startup.
|
||||
|
||||
Run manually (via __fish_config_op_registry_rebuild) after editing a
|
||||
# COMPONENT header, and automatically as a pre-step in build-manual.py
|
||||
before the manual is built.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import manualtools as mt
|
||||
|
||||
DOCS = Path(__file__).parent
|
||||
REPO = DOCS.parent
|
||||
OUTPUT = REPO / "conf.d" / "__fish_config_op_registry.fish"
|
||||
|
||||
|
||||
def collect_components() -> dict[str, list[str]]:
|
||||
"""Gather every `# COMPONENT` header across the whole repo.
|
||||
|
||||
Concatenates raw component lines when the same identity appears in
|
||||
more than one source (e.g. functions/auto-pull.fish and
|
||||
conf.d/auto-pull.fish both self-identify as "auto-pull" at runtime,
|
||||
since the guard can only ever look up the bare status
|
||||
current-function/basename string) rather than letting one silently
|
||||
overwrite the other.
|
||||
"""
|
||||
out: dict[str, list[str]] = {}
|
||||
for source in (
|
||||
mt.parse_components(REPO / "functions"),
|
||||
mt.parse_components(REPO / "conf.d"),
|
||||
mt.parse_component_file(REPO / "config.fish"),
|
||||
):
|
||||
for identity, lines in source.items():
|
||||
out.setdefault(identity, []).extend(lines)
|
||||
return out
|
||||
|
||||
|
||||
def build_registry(components: dict[str, list[str]]) -> tuple[dict[str, list[str]], list[str]]:
|
||||
"""Turn {identity: [raw COMPONENT lines]} into ({"identity:site": [tags]}, warnings).
|
||||
|
||||
A site with both always/on and always/off tagged is a contradiction:
|
||||
both are stripped and a warning is emitted, but generation continues
|
||||
-- any other real tag on that same site survives. A site whose
|
||||
effective tag set is empty after stripping produces no registry entry
|
||||
at all, which __fish_config_op_enabled already treats as always/on
|
||||
(fail-open) at guard time -- see spec §4.5.
|
||||
"""
|
||||
registry: dict[str, list[str]] = {}
|
||||
warnings: list[str] = []
|
||||
for identity, raw_lines in components.items():
|
||||
by_site: dict[str, list[str]] = {}
|
||||
for site, tag in mt.parse_component_lines(raw_lines):
|
||||
by_site.setdefault(site, []).append(tag)
|
||||
for site, tags in by_site.items():
|
||||
if "always/on" in tags and "always/off" in tags:
|
||||
label = identity if not site else f"{identity}:{site}"
|
||||
warnings.append(
|
||||
f"{label}: both always/on and always/off tagged; ignoring both"
|
||||
)
|
||||
tags = [t for t in tags if t not in ("always/on", "always/off")]
|
||||
if tags:
|
||||
registry[f"{identity}:{site}"] = list(dict.fromkeys(tags))
|
||||
return registry, warnings
|
||||
|
||||
|
||||
def render(registry: dict[str, list[str]]) -> str:
|
||||
keys = sorted(registry)
|
||||
lines = [
|
||||
"# Copyright (C) 2026 Rootiest",
|
||||
"# SPDX-License-Identifier: AGPL-3.0-or-later",
|
||||
"#",
|
||||
"# GENERATED FILE --- do not edit by hand.",
|
||||
"# Regenerate with __fish_config_op_registry_rebuild after editing a",
|
||||
"# # COMPONENT header, or automatically via docs/build-manual.py.",
|
||||
"# Source: docs/generate_component_registry.py",
|
||||
"#",
|
||||
"# This file must be sourced before any other conf.d/*.fish file that",
|
||||
"# calls the opinionated guard. That currently holds only because fish's",
|
||||
"# glob-based conf.d loading happens to sort this filename first",
|
||||
"# alphabetically among the guard-calling files -- do not rename it",
|
||||
"# without preserving that ordering.",
|
||||
"",
|
||||
]
|
||||
if not keys:
|
||||
lines.append("set -g __fish_config_op_registry_keys")
|
||||
lines.append("set -g __fish_config_op_registry_values")
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
quoted_keys = [f'"{k}"' for k in keys]
|
||||
lines.append("set -g __fish_config_op_registry_keys \\")
|
||||
lines += [f" {k} \\" for k in quoted_keys[:-1]] + [f" {quoted_keys[-1]}"]
|
||||
lines.append("")
|
||||
|
||||
values = ['"' + " ".join(registry[k]) + '"' for k in keys]
|
||||
lines.append("set -g __fish_config_op_registry_values \\")
|
||||
lines += [f" {v} \\" for v in values[:-1]] + [f" {values[-1]}"]
|
||||
lines.append("")
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
components = collect_components()
|
||||
registry, warnings = build_registry(components)
|
||||
for w in warnings:
|
||||
print(f" WARN {w}", file=sys.stderr)
|
||||
OUTPUT.write_text(render(registry))
|
||||
print(f"wrote {OUTPUT} ({len(registry)} entries)", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
raise SystemExit(main())
|
||||
@@ -145,6 +145,19 @@ NOTE:
|
||||
- Disabled integration commands (spwin, tab, split, hist, logs, upgrade) print an error naming the variable that disabled them.
|
||||
- On CachyOS, the distro fish config's own aliases, history override, and bang-bang bindings are stripped per category as well.
|
||||
|
||||
### Sub-categories
|
||||
|
||||
Each of the six categories further sub-divides into two to six
|
||||
sub-categories, each with its own `__fish_config_op_<category>_<subcategory>`
|
||||
variable (e.g. `__fish_config_op_aliases_filesystem`). These follow the
|
||||
exact same truthy/falsy/unset cascade one level deeper: an explicit
|
||||
sub-category value overrides the master switch and the parent category's
|
||||
setting, and an unset sub-category inherits from its parent category (which
|
||||
in turn inherits from `__fish_config_opinionated`). Run config-settings and
|
||||
press Enter on a category row to browse and toggle its sub-categories
|
||||
interactively. See [Components Reference](/08-components-reference/) for the
|
||||
full sub-category breakdown of every category.
|
||||
|
||||
|
||||
## Prompt and Theme
|
||||
|
||||
|
||||
@@ -31,3 +31,35 @@ all of these commands.
|
||||
When C1 is disabled, `rm` uses bare `command rm` with no wrapper — files
|
||||
are permanently deleted, not trashed. There is no intermediate safety net.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_aliases` sub-divides into six sub-categories, each with
|
||||
its own `__fish_config_op_aliases_<slug>` toggle:
|
||||
|
||||
## filesystem
|
||||
|
||||
`ls`, `cat`, `cd`, `du`, `mkdir`, `rm`, `mv`, and `cd`/zoxide navigation --
|
||||
the everyday filesystem-inspection and -modification shadows.
|
||||
|
||||
## search
|
||||
|
||||
`rg`, with its Kitty hyperlink formatting.
|
||||
|
||||
## network
|
||||
|
||||
`ping`, `ssh`, and `yt-dlp` -- shadows that talk to the network.
|
||||
|
||||
## monitor
|
||||
|
||||
`top` -> `btop`.
|
||||
|
||||
## shell-tools
|
||||
|
||||
`bash` (XDG bashrc + `$SHELL` reset), `less` (`$PAGER` fallback chain),
|
||||
and the `help config` interception.
|
||||
|
||||
## dev-tools
|
||||
|
||||
`claude` (AGENTS.md/CLAUDE.md auto-linking) and `edit` (multi-editor
|
||||
launcher), plus `agy`.
|
||||
|
||||
|
||||
@@ -43,3 +43,28 @@ branches, or repos without a remote. The handler fires once per repo entry
|
||||
(not on every sub-directory `cd`). The registry is machine-local at
|
||||
`$__fish_user_dots_path/auto-pull.list` (defaults to `~/.config/.user-dots/fish/auto-pull.list`) and is never committed.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_autoexec` sub-divides into five sub-categories, each
|
||||
with its own `__fish_config_op_autoexec_<slug>` toggle:
|
||||
|
||||
## plugin-management
|
||||
|
||||
Fisher bootstrap on first run.
|
||||
|
||||
## pkg-wrappers
|
||||
|
||||
`paru`/`yay` wrapper generation.
|
||||
|
||||
## venv
|
||||
|
||||
Automatic Python virtualenv activation.
|
||||
|
||||
## telemetry
|
||||
|
||||
The WakaTime hook's startup bootstrap.
|
||||
|
||||
## sync
|
||||
|
||||
Auto-pull background fast-forward, and the user-dots convenience symlink.
|
||||
|
||||
|
||||
@@ -33,3 +33,23 @@ When C3 is disabled, `exit` falls back to `builtin exit` with no scrollback
|
||||
capture, no Kitty IPC, and no file I/O on exit. The scrollback capture block
|
||||
is independently controlled by C5 (see below).
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_overrides` sub-divides into three sub-categories, each
|
||||
with its own `__fish_config_op_overrides_<slug>` toggle:
|
||||
|
||||
## key-bindings
|
||||
|
||||
Vi mode, autopair, puffer key intercepts, bang-bang history expansion,
|
||||
and `smart_exit`'s plain-exit path.
|
||||
|
||||
## environment
|
||||
|
||||
`$PATH`, `$PAGER`/`$EDITOR`/`$GPG_TTY`, and `$CDPATH`.
|
||||
|
||||
## prompt
|
||||
|
||||
Starship, the right prompt, Catppuccin syntax/prompt colors, and FZF
|
||||
theming (`$FZF_DEFAULT_OPTS`) -- all driven by the same guard as a single
|
||||
unit, not independently toggleable from each other.
|
||||
|
||||
|
||||
@@ -22,3 +22,28 @@ Disabled integration commands (`spwin`, `tab`, `split`, `hist`, `logs`, `upgrade
|
||||
a colored error to stderr naming the variable that disabled them rather than
|
||||
silently failing.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_integrations` sub-divides into five sub-categories,
|
||||
each with its own `__fish_config_op_integrations_<slug>` toggle:
|
||||
|
||||
## terminal-abbrs
|
||||
|
||||
The Kitty/WezTerm abbreviation set.
|
||||
|
||||
## window-mgmt
|
||||
|
||||
`spwin`, `tab`, `split`.
|
||||
|
||||
## notifications
|
||||
|
||||
`done`'s completion notifications, and the WakaTime activity hook.
|
||||
|
||||
## history-logs
|
||||
|
||||
`hist`, `logs`.
|
||||
|
||||
## pkg-upgrade
|
||||
|
||||
`upgrade`.
|
||||
|
||||
|
||||
@@ -112,3 +112,22 @@ Note: C3 and C5 compose independently. C3 controls whether the smart_exit
|
||||
wrapper is active at all; C5 controls only the scrollback-capture block
|
||||
inside it. With C3 disabled, exit is plain builtin exit regardless of C5.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_logging` sub-divides into three sub-categories, each
|
||||
with its own `__fish_config_op_logging_<slug>` toggle (all still opt-in
|
||||
by default, inherited from C5's own opt-in behavior -- see §3 of the
|
||||
design spec):
|
||||
|
||||
## terminal-capture
|
||||
|
||||
Kitty watcher scrollback capture, and `smart_exit`'s logging-guard path.
|
||||
|
||||
## multiplexer-capture
|
||||
|
||||
tmux `pipe-pane` and zellij `dump-screen` capture.
|
||||
|
||||
## pkg-logs
|
||||
|
||||
`paru`/`yay` AUR log wrappers.
|
||||
|
||||
|
||||
@@ -13,3 +13,16 @@ When C6 is disabled, no greeting is printed by this config. Any greeting
|
||||
set by the distro or other configs runs normally — this config simply does
|
||||
not override it.
|
||||
|
||||
## Sub-categories
|
||||
|
||||
`__fish_config_op_greeting` sub-divides into two sub-categories, each
|
||||
with its own `__fish_config_op_greeting_<slug>` toggle:
|
||||
|
||||
## first-run
|
||||
|
||||
The first-run welcome banner.
|
||||
|
||||
## greeting-message
|
||||
|
||||
The per-session `fish_greeting` override.
|
||||
|
||||
|
||||
@@ -18,3 +18,18 @@ category variable.
|
||||
C4 [Integrations](/08-components-reference/04-c4-terminal-and-tool-integration/) — Kitty/Wezterm integrations, starship hooks, fzf theme
|
||||
C5 [Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) — Session logs, command duration
|
||||
C6 [Greeting & First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) — Custom startup banner
|
||||
|
||||
Each category further sub-divides into two to six sub-categories (24 in
|
||||
total) with their own `__fish_config_op_<category>_<subcategory>` toggles
|
||||
-- see that category's page for its sub-category list.
|
||||
|
||||
## Per-function overrides: `C0`/`always`
|
||||
|
||||
Every guarded function or file can also carry a reserved `always/on` or
|
||||
`always/off` tag in its `# COMPONENT` header, independent of every C1-C6
|
||||
category and sub-category toggle and invisible to `config-settings`. An
|
||||
`always/off` tag disables that function unconditionally; an `always/on`
|
||||
tag enables it unconditionally, ignoring the state of every other tagged
|
||||
sub-category. This is a per-function escape hatch for cases too granular
|
||||
or too idiosyncratic to justify a taxonomy entry -- edit the header
|
||||
directly and run `__fish_config_op_registry_rebuild` to apply the change.
|
||||
|
||||
@@ -237,6 +237,13 @@ Re-enable everything:
|
||||
|
||||
set -Ue __fish_config_opinionated
|
||||
|
||||
Each category also has two to six sub-categories (e.g.
|
||||
`__fish_config_op_aliases_filesystem`) that can be checked, disabled, or
|
||||
reset the same way — `set -U __fish_config_op_<category>_<subcategory> off`
|
||||
and `set -Ue __fish_config_op_<category>_<subcategory>` work identically to
|
||||
the category-level recipes above, just one level more granular. See
|
||||
[Components Reference](/08-components-reference/) for the full list.
|
||||
|
||||
For an interactive alternative to setting these variables by hand, run `config-settings`.
|
||||
|
||||
---
|
||||
|
||||
+72
-5
@@ -62,6 +62,7 @@ HEADER_LABEL = re.compile(r"^#\s+([A-Z][A-Z ]*[A-Z])\s*$")
|
||||
FUNC_DEF = re.compile(r"^\s*function\s+(\S+)")
|
||||
SECTIONS = (
|
||||
"CATEGORY",
|
||||
"COMPONENT",
|
||||
"DEPENDENCIES",
|
||||
"SYNOPSIS",
|
||||
"DESCRIPTION",
|
||||
@@ -109,6 +110,19 @@ def _trailing_blanks(lines: list[str]) -> int:
|
||||
return n
|
||||
|
||||
|
||||
def _block_identity(path: Path, lines: list[str], end: int, blocks_count: int) -> str:
|
||||
"""Resolve a header block's associated name.
|
||||
|
||||
A file carrying exactly one header is associated with its own stem, so
|
||||
a `function` nested inside a `type -q` guard still resolves. A file
|
||||
with several headers walks forward to the next `function` definition.
|
||||
"""
|
||||
if blocks_count == 1:
|
||||
return path.stem
|
||||
after = (m.group(1) for ln in lines[end:] if (m := FUNC_DEF.match(ln)))
|
||||
return next(after, path.stem)
|
||||
|
||||
|
||||
def parse_functions(root: Path) -> dict[str, dict[str, list[str]]]:
|
||||
"""Parse the comment header above every documented public function.
|
||||
|
||||
@@ -128,11 +142,7 @@ def parse_functions(root: Path) -> dict[str, dict[str, list[str]]]:
|
||||
lines = path.read_text(encoding="utf-8").split("\n")
|
||||
blocks = _header_blocks(lines)
|
||||
for end, sections in blocks:
|
||||
if len(blocks) == 1:
|
||||
name = path.stem
|
||||
else:
|
||||
after = (m.group(1) for ln in lines[end:] if (m := FUNC_DEF.match(ln)))
|
||||
name = next(after, path.stem)
|
||||
name = _block_identity(path, lines, end, len(blocks))
|
||||
if name.startswith("_") or "CATEGORY" not in sections:
|
||||
continue
|
||||
out[name] = {
|
||||
@@ -185,6 +195,63 @@ def parse_abbreviations(root: Path) -> dict[str, list[dict]]:
|
||||
return out
|
||||
|
||||
|
||||
SITE_LINE_RE = re.compile(r"^site\s+(\S+):\s*(\S+)$")
|
||||
|
||||
|
||||
def parse_component_lines(lines: list[str]) -> list[tuple[str, str]]:
|
||||
"""Parse raw `# COMPONENT` body lines into (site, tag) pairs.
|
||||
|
||||
A line of the form `site <slug>: <tag>` scopes <tag> to that site; a
|
||||
bare `<tag>` line belongs to the default (unnamed) site, keyed "".
|
||||
Blank lines are skipped.
|
||||
"""
|
||||
out: list[tuple[str, str]] = []
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
m = SITE_LINE_RE.match(line)
|
||||
if m:
|
||||
out.append((m.group(1), m.group(2)))
|
||||
else:
|
||||
out.append(("", line))
|
||||
return out
|
||||
|
||||
|
||||
def _parse_component_blocks(path: Path) -> dict[str, list[str]]:
|
||||
"""Parse every `# COMPONENT` header block in one file.
|
||||
|
||||
Unlike parse_functions, there is no `# CATEGORY` gate and no
|
||||
underscore exclusion: component classification applies to every
|
||||
function/script, public or private, documented in the manual or not
|
||||
-- the registry needs to see every guarded identity, not just the
|
||||
ones that appear in the public function reference.
|
||||
"""
|
||||
lines = path.read_text(encoding="utf-8").split("\n")
|
||||
blocks = _header_blocks(lines)
|
||||
out: dict[str, list[str]] = {}
|
||||
for end, sections in blocks:
|
||||
if "COMPONENT" not in sections:
|
||||
continue
|
||||
name = _block_identity(path, lines, end, len(blocks))
|
||||
body = sections["COMPONENT"]
|
||||
out[name] = body[: len(body) - _trailing_blanks(body)]
|
||||
return out
|
||||
|
||||
|
||||
def parse_component_file(path: Path) -> dict[str, list[str]]:
|
||||
"""Parse `# COMPONENT` header block(s) in one specific file (e.g. config.fish)."""
|
||||
return _parse_component_blocks(path)
|
||||
|
||||
|
||||
def parse_components(root: Path) -> dict[str, list[str]]:
|
||||
"""Parse `# COMPONENT` header blocks across every `*.fish` file under root."""
|
||||
out: dict[str, list[str]] = {}
|
||||
for path in sorted(root.glob("*.fish")):
|
||||
out.update(_parse_component_blocks(path))
|
||||
return out
|
||||
|
||||
|
||||
def _sort_key(entry: Path) -> tuple:
|
||||
"""Order by sidebar.order when present, else by filename. Stable."""
|
||||
target = entry / "index.md" if entry.is_dir() else entry
|
||||
|
||||
@@ -130,6 +130,38 @@ def _parsed_functions() -> dict[str, dict[str, list[str]]]:
|
||||
return mt.parse_functions(Path(__file__).parent.parent / "functions")
|
||||
|
||||
|
||||
def _parsed_components() -> dict[str, list[str]]:
|
||||
import generate_component_registry as gcr
|
||||
|
||||
return gcr.collect_components()
|
||||
|
||||
|
||||
_C0_TAGS = {"always/on", "always/off"}
|
||||
_TAXONOMY_FILES = {
|
||||
"aliases": "01-c1-command-shadows.md",
|
||||
"autoexec": "02-c2-startup-side-effects.md",
|
||||
"overrides": "03-c3-key-and-environment-overrides.md",
|
||||
"integrations": "04-c4-terminal-and-tool-integration.md",
|
||||
"logging": "05-c5-logging-and-capture.md",
|
||||
"greeting": "06-c6-greeting-and-first-run-ui.md",
|
||||
}
|
||||
|
||||
|
||||
def _load_taxonomy() -> dict[str, set[str]]:
|
||||
"""{category: {sub-category slugs}}, parsed from `## <slug>` headings
|
||||
in each category's docs/manual/08-components-reference/ file."""
|
||||
ref_root = Path(__file__).parent / "manual" / "08-components-reference"
|
||||
taxonomy: dict[str, set[str]] = {}
|
||||
for category, filename in _TAXONOMY_FILES.items():
|
||||
_, body = mt.parse(ref_root / filename)
|
||||
taxonomy[category] = {
|
||||
m.group(1)
|
||||
for ln in body.split("\n")
|
||||
if (m := re.match(r"^## ([a-z][a-z0-9-]*)$", ln))
|
||||
}
|
||||
return taxonomy
|
||||
|
||||
|
||||
def test_every_categorised_function_produces_one_entry():
|
||||
import build_manual
|
||||
|
||||
@@ -184,6 +216,36 @@ def test_dependencies_resolve():
|
||||
assert not dangling, "unresolvable # DEPENDENCIES:\n " + "\n ".join(dangling)
|
||||
|
||||
|
||||
def test_every_component_resolves_to_a_taxonomy_entry():
|
||||
"""Every non-C0 # COMPONENT tag must resolve to a documented sub-category."""
|
||||
taxonomy = _load_taxonomy()
|
||||
unknown = []
|
||||
for identity, raw_lines in _parsed_components().items():
|
||||
for site, tag in mt.parse_component_lines(raw_lines):
|
||||
if tag in _C0_TAGS:
|
||||
continue
|
||||
if "/" not in tag:
|
||||
unknown.append(f"{identity}: malformed tag {tag!r}")
|
||||
continue
|
||||
category, subcat = tag.split("/", 1)
|
||||
if category not in taxonomy or subcat not in taxonomy[category]:
|
||||
unknown.append(f"{identity}: {tag}")
|
||||
assert not unknown, "# COMPONENT tags with no taxonomy entry:\n " + "\n ".join(unknown)
|
||||
|
||||
|
||||
def warn_c0_tags_never_combine_with_contradiction():
|
||||
"""Warn -- never fail -- on always/on + always/off contradictions this
|
||||
repo's own generator would warn about -- this is a direct repo-content
|
||||
check, independent of running the generator, so CI surfaces them even
|
||||
if someone forgets to regenerate. Warnings are non-fatal (spec §4.5);
|
||||
this exists to print them prominently in CI output."""
|
||||
from generate_component_registry import build_registry
|
||||
|
||||
_, warnings = build_registry(_parsed_components())
|
||||
for w in warnings:
|
||||
print(f" WARN {w}")
|
||||
|
||||
|
||||
def warn_public_functions_without_category():
|
||||
"""Warn — never fail — on a public function carrying no `# CATEGORY`.
|
||||
|
||||
@@ -205,6 +267,63 @@ def warn_public_functions_without_category():
|
||||
print(" " + ", ".join(orphans))
|
||||
|
||||
|
||||
# The guard's own supporting infrastructure: these files' bodies (function
|
||||
# signature, SYNOPSIS/EXAMPLE prose) legitimately contain the literal text
|
||||
# "__fish_config_op_enabled" without being a *caller* of the guard, so they
|
||||
# are permanently exempt from warn_functions_without_component's substring
|
||||
# check below.
|
||||
_GUARD_INFRA_FILES = {
|
||||
"__fish_config_op_enabled.fish",
|
||||
"__fish_config_op_cascade.fish",
|
||||
"__fish_config_op_registry_lookup.fish",
|
||||
}
|
||||
|
||||
|
||||
def warn_functions_without_component():
|
||||
"""Warn -- never fail -- on a documented function calling the
|
||||
opinionated guard but carrying no `# COMPONENT` section.
|
||||
|
||||
Mirrors warn_public_functions_without_category: a function that never
|
||||
opted into the header convention at all (no # SYNOPSIS) is silently
|
||||
out of scope, matching spec §4.5's fail-open tiering.
|
||||
"""
|
||||
repo = Path(__file__).parent.parent
|
||||
components = _parsed_components()
|
||||
orphans = []
|
||||
for p in list((repo / "functions").glob("*.fish")) + list((repo / "conf.d").glob("*.fish")):
|
||||
if p.name in _GUARD_INFRA_FILES:
|
||||
continue
|
||||
text = p.read_text(encoding="utf-8")
|
||||
if "__fish_config_op_enabled" not in text or "# SYNOPSIS" not in text:
|
||||
continue
|
||||
if p.stem not in components:
|
||||
orphans.append(str(p.relative_to(repo)))
|
||||
if orphans:
|
||||
print(f" WARN {len(orphans)} function(s) call the opinionated guard but lack # COMPONENT:")
|
||||
print(" " + ", ".join(sorted(orphans)))
|
||||
|
||||
|
||||
def warn_unused_taxonomy_entries():
|
||||
"""Warn -- never fail -- on a documented sub-category with zero tagged functions."""
|
||||
taxonomy = _load_taxonomy()
|
||||
used: dict[str, set[str]] = {c: set() for c in taxonomy}
|
||||
for raw_lines in _parsed_components().values():
|
||||
for _site, tag in mt.parse_component_lines(raw_lines):
|
||||
if tag in _C0_TAGS or "/" not in tag:
|
||||
continue
|
||||
category, subcat = tag.split("/", 1)
|
||||
if category in used:
|
||||
used[category].add(subcat)
|
||||
unused = [
|
||||
f"{category}/{subcat}"
|
||||
for category, subcats in taxonomy.items()
|
||||
for subcat in sorted(subcats - used[category])
|
||||
]
|
||||
if unused:
|
||||
print(f" WARN {len(unused)} taxonomy entr{'y has' if len(unused) == 1 else 'ies have'} zero tagged functions:")
|
||||
print(" " + ", ".join(unused))
|
||||
|
||||
|
||||
def _without_section_5(text: str) -> str:
|
||||
"""Drop `# 5. FUNCTIONS REFERENCE` through the start of section 6.
|
||||
|
||||
@@ -827,6 +946,207 @@ def test_site_avoids_reserved_dir():
|
||||
)
|
||||
|
||||
|
||||
def test_parse_component_lines_default_and_named_sites():
|
||||
lines = [
|
||||
"aliases/filesystem",
|
||||
"site exit-plain: overrides/key-bindings",
|
||||
"site logging-guard: logging/terminal-capture",
|
||||
"",
|
||||
" ",
|
||||
]
|
||||
got = mt.parse_component_lines(lines)
|
||||
assert got == [
|
||||
("", "aliases/filesystem"),
|
||||
("exit-plain", "overrides/key-bindings"),
|
||||
("logging-guard", "logging/terminal-capture"),
|
||||
], f"unexpected parse: {got}"
|
||||
|
||||
|
||||
def test_parse_components_includes_underscore_prefixed_and_uncategorised():
|
||||
"""Unlike parse_functions, parse_components has no # CATEGORY gate and
|
||||
no underscore exclusion -- every guarded identity must be visible."""
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
root = Path(d)
|
||||
(root / "__private_helper.fish").write_text(
|
||||
"# COMPONENT\n"
|
||||
"# logging/terminal-capture\n"
|
||||
"function __private_helper\n"
|
||||
"end\n"
|
||||
)
|
||||
(root / "no_category.fish").write_text(
|
||||
"# COMPONENT\n"
|
||||
"# aliases/filesystem\n"
|
||||
"#\n"
|
||||
"# SYNOPSIS\n"
|
||||
"# no_category\n"
|
||||
"function no_category\n"
|
||||
"end\n"
|
||||
)
|
||||
got = mt.parse_components(root)
|
||||
assert got["__private_helper"] == ["logging/terminal-capture"]
|
||||
assert got["no_category"] == ["aliases/filesystem"]
|
||||
|
||||
|
||||
def test_parse_components_resolves_multi_header_file_to_function_name():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
root = Path(d)
|
||||
(root / "multi.fish").write_text(
|
||||
"# COMPONENT\n"
|
||||
"# aliases/filesystem\n"
|
||||
"function first_fn\n"
|
||||
"end\n"
|
||||
"\n"
|
||||
"# COMPONENT\n"
|
||||
"# aliases/network\n"
|
||||
"function second_fn\n"
|
||||
"end\n"
|
||||
)
|
||||
got = mt.parse_components(root)
|
||||
assert got == {
|
||||
"first_fn": ["aliases/filesystem"],
|
||||
"second_fn": ["aliases/network"],
|
||||
}, f"unexpected resolution: {got}"
|
||||
|
||||
|
||||
def test_parse_component_file_single_file():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
path = Path(d) / "config.fish"
|
||||
path.write_text(
|
||||
"# COMPONENT\n"
|
||||
"# site greeting-block: greeting/greeting-message\n"
|
||||
)
|
||||
got = mt.parse_component_file(path)
|
||||
assert got == {"config": ["site greeting-block: greeting/greeting-message"]}
|
||||
|
||||
|
||||
def test_build_registry_strips_on_off_contradiction_with_warning():
|
||||
import generate_component_registry as gcr
|
||||
|
||||
components = {"contradictory_fn": ["always/on", "always/off", "aliases/filesystem"]}
|
||||
registry, warnings = gcr.build_registry(components)
|
||||
assert registry["contradictory_fn:"] == ["aliases/filesystem"], (
|
||||
f"the non-contradictory tag should survive: {registry}"
|
||||
)
|
||||
assert len(warnings) == 1 and "contradictory_fn" in warnings[0]
|
||||
|
||||
|
||||
def test_build_registry_drops_empty_effective_tag_sets():
|
||||
import generate_component_registry as gcr
|
||||
|
||||
components = {"only_contradictory": ["always/on", "always/off"]}
|
||||
registry, warnings = gcr.build_registry(components)
|
||||
assert "only_contradictory:" not in registry, (
|
||||
"a site stripped down to nothing must produce no registry entry "
|
||||
"(fail-open: absence of an entry already means always/on at guard time)"
|
||||
)
|
||||
assert len(warnings) == 1
|
||||
|
||||
|
||||
def test_build_registry_keeps_sites_independent():
|
||||
import generate_component_registry as gcr
|
||||
|
||||
components = {
|
||||
"smart_exit": [
|
||||
"site exit-plain: overrides/key-bindings",
|
||||
"site logging-guard: logging/terminal-capture",
|
||||
]
|
||||
}
|
||||
registry, warnings = gcr.build_registry(components)
|
||||
assert registry["smart_exit:exit-plain"] == ["overrides/key-bindings"]
|
||||
assert registry["smart_exit:logging-guard"] == ["logging/terminal-capture"]
|
||||
assert not warnings
|
||||
|
||||
|
||||
def test_collect_components_merges_identity_collisions_across_sources():
|
||||
"""functions/auto-pull.fish and conf.d/auto-pull.fish both self-identify
|
||||
as "auto-pull" at runtime -- the guard only ever has the bare
|
||||
status current-function/basename string to look up with -- so
|
||||
collect_components must concatenate their raw COMPONENT lines
|
||||
rather than letting conf.d's entry silently overwrite functions'."""
|
||||
import generate_component_registry as gcr
|
||||
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
root = Path(d)
|
||||
(root / "functions").mkdir()
|
||||
(root / "conf.d").mkdir()
|
||||
(root / "functions" / "auto-pull.fish").write_text(
|
||||
"# COMPONENT\n"
|
||||
"# autoexec/sync\n"
|
||||
"function auto-pull\n"
|
||||
"end\n"
|
||||
)
|
||||
(root / "conf.d" / "auto-pull.fish").write_text(
|
||||
"# COMPONENT\n"
|
||||
"# autoexec/sync\n"
|
||||
)
|
||||
(root / "config.fish").write_text("")
|
||||
|
||||
orig_repo = gcr.REPO
|
||||
try:
|
||||
gcr.REPO = root
|
||||
got = gcr.collect_components()
|
||||
finally:
|
||||
gcr.REPO = orig_repo
|
||||
|
||||
assert got["auto-pull"] == ["autoexec/sync", "autoexec/sync"], (
|
||||
f"both sources' tags should survive the merge, not overwrite: {got}"
|
||||
)
|
||||
|
||||
|
||||
def test_render_registry_is_valid_fish_and_round_trips():
|
||||
"""Sourcing render()'s output must leave the two arrays in the exact
|
||||
shape __fish_config_op_registry_lookup expects -- checked via the real
|
||||
lookup helper (functions/__fish_config_op_registry_lookup.fish, Task
|
||||
2) rather than re-parsing the generated text by hand."""
|
||||
import subprocess
|
||||
|
||||
import generate_component_registry as gcr
|
||||
|
||||
registry = {
|
||||
"rm:": ["aliases/filesystem"],
|
||||
"smart_exit:exit-plain": ["overrides/key-bindings"],
|
||||
}
|
||||
text = gcr.render(registry)
|
||||
|
||||
repo = Path(__file__).parent.parent
|
||||
proc = subprocess.run(
|
||||
[
|
||||
"fish", "-c",
|
||||
f"source {repo}/functions/__fish_config_op_registry_lookup.fish; "
|
||||
"source /dev/stdin; "
|
||||
"__fish_config_op_registry_lookup rm ''; echo status=$status",
|
||||
],
|
||||
input=text,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert "aliases/filesystem" in proc.stdout, f"unexpected output: {proc.stdout!r} {proc.stderr!r}"
|
||||
assert "status=0" in proc.stdout, f"lookup did not report found: {proc.stdout!r}"
|
||||
|
||||
|
||||
def test_build_manual_regenerates_registry_before_building():
|
||||
"""docs/build-manual.py must regenerate the registry as a pre-step."""
|
||||
import build_manual
|
||||
|
||||
assert hasattr(build_manual, "generate_component_registry"), (
|
||||
"build-manual.py must import generate_component_registry so its "
|
||||
"main() can be called as a pre-step before --site/--concat run"
|
||||
)
|
||||
|
||||
|
||||
def test_committed_registry_matches_headers():
|
||||
"""The committed conf.d/__fish_config_op_registry.fish must match what
|
||||
generate_component_registry.py would produce right now from the current
|
||||
`# COMPONENT` headers -- otherwise CI has nothing catching drift."""
|
||||
import generate_component_registry as gcr
|
||||
|
||||
registry, _ = gcr.build_registry(gcr.collect_components())
|
||||
assert gcr.render(registry) == gcr.OUTPUT.read_text(), (
|
||||
"conf.d/__fish_config_op_registry.fish is stale — run "
|
||||
"__fish_config_op_registry_rebuild"
|
||||
)
|
||||
|
||||
|
||||
TESTS = [v for k, v in sorted(globals().items()) if k.startswith("test_")]
|
||||
|
||||
|
||||
@@ -840,6 +1160,9 @@ def main() -> int:
|
||||
print(f" FAIL {t.__name__}: {e}", file=sys.stderr)
|
||||
failed += 1
|
||||
warn_public_functions_without_category()
|
||||
warn_functions_without_component()
|
||||
warn_unused_taxonomy_entries()
|
||||
warn_c0_tags_never_combine_with_contradiction()
|
||||
print(f"\n{len(TESTS) - failed}/{len(TESTS)} passed")
|
||||
return 1 if failed else 0
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# autoexec/venv
|
||||
#
|
||||
# SYNOPSIS
|
||||
# __auto_source_fallback_venv
|
||||
#
|
||||
@@ -16,7 +19,7 @@ function __auto_source_fallback_venv --on-variable PWD
|
||||
status --is-command-substitution; and return
|
||||
|
||||
# Opinionated guard (C2): no automatic venv activation when disabled.
|
||||
__fish_config_op_enabled __fish_config_op_autoexec; or return
|
||||
__fish_config_op_enabled (status current-function); or return
|
||||
|
||||
# 1. Skip if direnv is already managing this directory
|
||||
if set -q DIRENV_DIR; or test -e ".envrc"
|
||||
|
||||
@@ -182,7 +182,7 @@ function __config_settings_draw
|
||||
|
||||
# ── Keybind hint ──────────────────────────────────────────────────────
|
||||
# string pad is width-aware (arrows count as 1 column)
|
||||
set -l hint " ↑↓/kj move ←→/hl set Tab page q quit"
|
||||
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 ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# __config_settings_draw_subcat <cur_row> <cur_scope> <category_var>
|
||||
#
|
||||
# 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_<category> 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]
|
||||
|
||||
set -l c_ok (set_color green)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_dim (set_color brblack)
|
||||
set -l c_sel (set_color --bold magenta)
|
||||
set -l c_head (set_color --bold cyan)
|
||||
set -l c_reset (set_color normal)
|
||||
|
||||
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 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 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)
|
||||
|
||||
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: <label> (<scope>) ───┐"; the
|
||||
# dash count must absorb every visible char added around cat_label so
|
||||
# the line still totals iw+2, matching the surrounding box exactly --
|
||||
# see the DESCRIPTION doc comment above for why this is hand-verified,
|
||||
# not eyeballed.
|
||||
set -l title_dashes (math $iw - (string length -- $cat_label) - (string length -- $scope_label) - 22)
|
||||
printf '%s┌─%s Sub-categories: %s (%s)%s %s┐\n' \
|
||||
$p $c_head "$cat_label" $scope_label "$c_reset" (string repeat -n (math "max(0, $title_dashes)") '─')
|
||||
|
||||
printf '%s│%s│\n' $p $HBR
|
||||
|
||||
# Row 0: the category's own toggle, still meaningful as the cascade
|
||||
# default any DEFAULT-valued sub-category below falls back to.
|
||||
set -l cat_val (__config_settings_get_val $category_var $cur_scope)
|
||||
set -l cat_badge
|
||||
switch $cat_val
|
||||
case on
|
||||
set cat_badge "$c_ok"" ON$c_reset"
|
||||
case off
|
||||
set cat_badge "$c_err""OFF $c_reset"
|
||||
case '*'
|
||||
set cat_badge "$c_dim""DEFAULT$c_reset"
|
||||
end
|
||||
set -l cat_curs " "
|
||||
if test $cur_row -eq 0
|
||||
set cat_curs "$c_sel▶$c_reset "
|
||||
end
|
||||
set -l cat_desc "cascade default"
|
||||
if test $iw -ge 68
|
||||
set cat_desc "default for all sub-cats below"
|
||||
end
|
||||
if test $iw -ge 72
|
||||
set cat_desc "default for all sub-categories below"
|
||||
end
|
||||
printf '%s│ %s%s [ %s ] %s │\n' $p $cat_curs \
|
||||
(string pad -r -w $label_w -- "(category)") $cat_badge \
|
||||
(string pad -r -w $desc_w -- (string sub -l $desc_w -- $cat_desc))
|
||||
|
||||
printf '%s│ %s │\n' $p (string repeat -n (math $iw - 6) '─')
|
||||
|
||||
for i in (seq 1 $n)
|
||||
set -l fields (string split -- \t $rows[$i])
|
||||
set -l slug $fields[1]
|
||||
set -l label $fields[2]
|
||||
set -l desc $fields[3]
|
||||
set -l subcat_var "$category_var"_(string replace -a -- '-' '_' $slug)
|
||||
|
||||
set -l val (__config_settings_get_val $subcat_var $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 $i -eq $cur_row
|
||||
set curs "$c_sel▶$c_reset "
|
||||
end
|
||||
|
||||
set -l lpad (string pad -r -w $label_w -- (string sub -l $label_w -- $label))
|
||||
set -l dpad (string pad -r -w $desc_w -- (string sub -l $desc_w -- $desc))
|
||||
printf '%s│ %s%s [ %s ] %s │\n' $p $curs $lpad $badge $dpad
|
||||
end
|
||||
|
||||
printf '%s│%s│\n' $p $HBR
|
||||
set -l hint " ↑↓/kj move ←→/hl set Esc back q quit"
|
||||
printf '%s│%s%s%s│\n' $p $c_dim (string pad -r -w $iw -- $hint) $c_reset
|
||||
printf '%s└%s┘\n' $p $HBR
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# __config_settings_subcats <category_variable>
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Prints the sub-category rows for one C1-C6 category, one per line as
|
||||
# "<slug>\t<label>\t<description>". This is a fish-native copy of the
|
||||
# taxonomy authored in docs/manual/08-components-reference/*.md (Task 9)
|
||||
# -- kept here as a static table rather than parsed from markdown at
|
||||
# draw time, since config-settings redraws on every keypress and every
|
||||
# terminal resize.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# category_variable One of the six __fish_config_op_<category> names
|
||||
#
|
||||
# EXIT STATUS
|
||||
# 0 Always
|
||||
#
|
||||
# RETURNS
|
||||
# Tab-separated "<slug>\t<label>\t<description>" rows, one per line
|
||||
#
|
||||
# EXAMPLE
|
||||
# __config_settings_subcats __fish_config_op_aliases
|
||||
function __config_settings_subcats --description 'List the sub-categories for one opinionated-component category'
|
||||
switch $argv[1]
|
||||
case __fish_config_op_aliases
|
||||
printf '%s\t%s\t%s\n' \
|
||||
filesystem Filesystem "ls, cat, cd, du, mkdir, rm, mv, zoxide" \
|
||||
search Search "rg" \
|
||||
network Network "ping, ssh, yt-dlp" \
|
||||
monitor Monitor "top" \
|
||||
shell-tools Shell-tools "bash, less, help" \
|
||||
dev-tools Dev-tools "claude, edit, agy"
|
||||
case __fish_config_op_autoexec
|
||||
printf '%s\t%s\t%s\n' \
|
||||
plugin-management Plugins "Fisher bootstrap" \
|
||||
pkg-wrappers Pkg-wrappers "paru/yay wrapper generation" \
|
||||
venv Venv "Python auto-activation" \
|
||||
telemetry Telemetry "WakaTime hook bootstrap" \
|
||||
sync Sync "auto-pull, user-dots symlink"
|
||||
case __fish_config_op_overrides
|
||||
printf '%s\t%s\t%s\n' \
|
||||
key-bindings Key-bindings "vi-mode, autopair, puffer, bang-bang" \
|
||||
environment Environment "PATH, PAGER, EDITOR, CDPATH" \
|
||||
prompt Prompt "Starship, right prompt, theme + FZF colors"
|
||||
case __fish_config_op_integrations
|
||||
printf '%s\t%s\t%s\n' \
|
||||
terminal-abbrs Term-abbrs "Kitty/WezTerm abbreviations" \
|
||||
window-mgmt Window-mgmt "spwin, tab, split" \
|
||||
notifications Notifications "done, WakaTime hook" \
|
||||
history-logs History-logs "hist, logs" \
|
||||
pkg-upgrade Pkg-upgrade "upgrade"
|
||||
case __fish_config_op_logging
|
||||
printf '%s\t%s\t%s\n' \
|
||||
terminal-capture Term-capture "Kitty watcher, smart_exit scrollback" \
|
||||
multiplexer-capture Multiplexer "tmux, zellij" \
|
||||
pkg-logs Pkg-logs "paru/yay AUR log wrappers"
|
||||
case __fish_config_op_greeting
|
||||
printf '%s\t%s\t%s\n' \
|
||||
first-run First-run "welcome banner" \
|
||||
greeting-message Greeting "fish_greeting override"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,63 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# __fish_config_op_cascade <category_variable> [<subcategory_variable>]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Evaluates the opt-out cascade for one C1-C6 classification: an
|
||||
# explicit truthy/falsy sub-category variable wins outright; otherwise
|
||||
# falls back to the category variable; otherwise falls back to the
|
||||
# master switch __fish_config_opinionated. A category in the opt-in
|
||||
# list (currently just __fish_config_op_logging, C5) defaults to
|
||||
# disabled when nothing in the chain is explicit, and the master switch
|
||||
# cannot enable it -- this is data-driven here instead of a hardcoded
|
||||
# string comparison, so any sub-category nested under an opt-in
|
||||
# category inherits "off unless explicit" for free through the cascade,
|
||||
# with no per-sub-category special-casing.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# category_variable Name (without $) of a C1-C6 category variable
|
||||
# subcategory_variable Optional name (without $) of a sub-category
|
||||
# variable nested under that category
|
||||
#
|
||||
# EXIT STATUS
|
||||
# 0 Enabled
|
||||
# 1 Disabled
|
||||
#
|
||||
# EXAMPLE
|
||||
# __fish_config_op_cascade __fish_config_op_aliases
|
||||
# __fish_config_op_cascade __fish_config_op_aliases __fish_config_op_aliases_filesystem
|
||||
function __fish_config_op_cascade --description 'Evaluate the sub-category -> category -> master opt-out cascade'
|
||||
set -l opt_in_categories __fish_config_op_logging
|
||||
|
||||
set -l chain $argv[1]
|
||||
if test (count $argv) -ge 2 -a -n "$argv[2]"
|
||||
set chain $argv[2] $argv[1]
|
||||
end
|
||||
|
||||
for var_name in $chain
|
||||
__fish_variable_check $var_name
|
||||
set -l s $status
|
||||
if test $s -eq 0
|
||||
return 0
|
||||
end
|
||||
if test $s -eq 1
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
# Every variable in the chain was unset/unrecognized. chain[-1] is
|
||||
# always the category variable (present whether or not a
|
||||
# sub-category was given) -- opt-in categories default to disabled
|
||||
# and the master switch cannot override that.
|
||||
if contains -- $chain[-1] $opt_in_categories
|
||||
return 1
|
||||
end
|
||||
|
||||
__fish_variable_check __fish_config_opinionated
|
||||
if test $status -eq 1
|
||||
return 1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
@@ -2,63 +2,68 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# __fish_config_op_enabled <category_variable>
|
||||
# __fish_config_op_enabled <identity> [<site>]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Guard predicate for opinionated components (AGENTS.md Task #3).
|
||||
# The category variable is evaluated first via __fish_variable_check:
|
||||
# an explicit truthy value (1/true/yes/on/y) enables the component
|
||||
# regardless of the master switch; an explicit falsy value
|
||||
# (0/false/no/off/n) disables it regardless of the master switch.
|
||||
# Only when the category variable is unset or unrecognized (status 2
|
||||
# or 3) does the master switch __fish_config_opinionated apply: a
|
||||
# falsy master disables every unset-category component at once.
|
||||
# Unset master with unset category → enabled (active by default).
|
||||
# Guard predicate for an opinionated component. <identity> is computed
|
||||
# by the caller, never hand-typed as a category name: (status
|
||||
# current-function) inside a function body, (status basename) at
|
||||
# top-level conf.d/*.fish or config.fish code (fish has no API for a
|
||||
# callee to introspect its own caller, so the caller must compute and
|
||||
# pass its own identity -- see the spec's "A note on self-identifying").
|
||||
# A trailing .fish is stripped so a status-basename identity and a
|
||||
# status-current-function identity land in the same key space.
|
||||
#
|
||||
# One exception: __fish_config_op_logging (C5) is opt-in, because it
|
||||
# writes terminal output to disk. Unset or unrecognized means disabled,
|
||||
# and the master switch cannot enable it — only an explicit truthy
|
||||
# value turns logging on.
|
||||
# Looks up "<identity>:<site>" (site defaults to the empty/unnamed site)
|
||||
# in the generated component registry. No registry entry (unclassified,
|
||||
# or a doc header with no # COMPONENT section) resolves to enabled --
|
||||
# the same fail-open default as an explicit `always/on` tag, so
|
||||
# user-authored and third-party functions that never call this guard in
|
||||
# the first place are unaffected, and one that somehow does is never
|
||||
# silently broken by a missing header. A found `always/off` tag
|
||||
# disables unconditionally; a found `always/on` tag enables
|
||||
# unconditionally, short-circuiting before any other tagged
|
||||
# sub-category is evaluated. Otherwise every tagged sub-category must
|
||||
# pass the cascade (AND semantics).
|
||||
#
|
||||
# ARGUMENTS
|
||||
# category_variable Name (without $) of the category opt-out variable:
|
||||
# __fish_config_op_aliases, __fish_config_op_autoexec,
|
||||
# __fish_config_op_overrides,
|
||||
# __fish_config_op_integrations,
|
||||
# __fish_config_op_logging, or
|
||||
# __fish_config_op_greeting
|
||||
# identity (status current-function) or (status basename)
|
||||
# site Optional site slug (see # COMPONENT header grammar);
|
||||
# omitted for the default/unnamed site
|
||||
#
|
||||
# EXIT STATUS
|
||||
# 0 Component enabled (category explicitly truthy; or category unset and master not falsy — except C5 logging, which requires an explicit truthy value)
|
||||
# 1 Component disabled (category explicitly falsy; or category unset and master falsy; or C5 logging unset; or no argument with falsy master)
|
||||
# 0 Component enabled
|
||||
# 1 Component disabled
|
||||
#
|
||||
# EXAMPLE
|
||||
# if __fish_config_op_enabled __fish_config_op_aliases
|
||||
# if not __fish_config_op_enabled (status current-function)
|
||||
# alias grep='grep --color=auto'
|
||||
# end
|
||||
function __fish_config_op_enabled --description 'Check whether an opinionated component category is enabled'
|
||||
__fish_variable_check $argv[1]
|
||||
set -l cat_status $status
|
||||
# if not __fish_config_op_enabled (status current-function) exit-plain
|
||||
# builtin exit
|
||||
# end
|
||||
function __fish_config_op_enabled --description 'Guard for an opinionated component, identified by its own caller'
|
||||
set -l identity (string replace -r '\.fish$' '' -- $argv[1])
|
||||
set -l site $argv[2]
|
||||
|
||||
if test $cat_status -eq 0
|
||||
set -l tags (__fish_config_op_registry_lookup $identity $site)
|
||||
if test $status -ne 0
|
||||
return 0
|
||||
end
|
||||
|
||||
if test $cat_status -eq 1
|
||||
if contains -- always/off $tags
|
||||
return 1
|
||||
end
|
||||
|
||||
# C5 logging is opt-in: it writes terminal output to disk, so an unset or
|
||||
# unrecognized value means off — the master switch cannot enable it.
|
||||
if test "$argv[1]" = __fish_config_op_logging
|
||||
return 1
|
||||
if contains -- always/on $tags
|
||||
return 0
|
||||
end
|
||||
|
||||
# Status 3 (garbage) defers to master — an unrecognized value is not an opt-out.
|
||||
__fish_variable_check __fish_config_opinionated
|
||||
if test $status -eq 1
|
||||
return 1
|
||||
for tag in $tags
|
||||
set -l parts (string split -m 1 -- / $tag)
|
||||
set -l category_var "__fish_config_op_$parts[1]"
|
||||
set -l subcat_var "__fish_config_op_$parts[1]_"(string replace -a -- '-' '_' $parts[2])
|
||||
__fish_config_op_cascade $category_var $subcat_var
|
||||
or return 1
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# __fish_config_op_registry_lookup <identity> <site>
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Looks up the "<identity>:<site>" key in the generated component
|
||||
# registry ($__fish_config_op_registry_keys /
|
||||
# $__fish_config_op_registry_values, sourced from
|
||||
# conf.d/__fish_config_op_registry.fish at shell startup) and prints its
|
||||
# tags, one per line. <site> is empty string for the default/unnamed
|
||||
# site.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# identity Function name (status current-function) or file basename
|
||||
# with any trailing .fish stripped (status basename)
|
||||
# site Site slug, or empty string for the default site
|
||||
#
|
||||
# EXIT STATUS
|
||||
# 0 Found: tags printed to stdout
|
||||
# 1 Not found: nothing printed
|
||||
#
|
||||
# RETURNS
|
||||
# Matching tags, one per line, printed to stdout
|
||||
#
|
||||
# EXAMPLE
|
||||
# set -l tags (__fish_config_op_registry_lookup rm "")
|
||||
# or return 0 # unclassified: caller treats this as always-on
|
||||
function __fish_config_op_registry_lookup --description 'Look up the COMPONENT tags for an identity:site pair'
|
||||
set -l key "$argv[1]:$argv[2]"
|
||||
set -l idx (contains -i -- $key $__fish_config_op_registry_keys)
|
||||
if test -z "$idx"
|
||||
return 1
|
||||
end
|
||||
string split ' ' -- $__fish_config_op_registry_values[$idx]
|
||||
return 0
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# __fish_config_op_registry_rebuild
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Regenerates conf.d/__fish_config_op_registry.fish from every
|
||||
# # COMPONENT header in functions/*.fish, conf.d/*.fish, and
|
||||
# config.fish, then re-sources it into the current session so the
|
||||
# change takes effect immediately. Run manually after editing a
|
||||
# # COMPONENT header; never run automatically at shell startup --
|
||||
# parsing every header on every new shell would be wasted work on
|
||||
# every session that isn't actively editing a header.
|
||||
#
|
||||
# EXIT STATUS
|
||||
# 0 Registry regenerated
|
||||
# 1 python3 is not available, or generation failed
|
||||
#
|
||||
# EXAMPLE
|
||||
# __fish_config_op_registry_rebuild
|
||||
function __fish_config_op_registry_rebuild --description 'Regenerate the opinionated-component registry from # COMPONENT headers'
|
||||
if not type -q python3
|
||||
echo "__fish_config_op_registry_rebuild: python3 not found" >&2
|
||||
return 1
|
||||
end
|
||||
python3 "$__fish_config_dir/docs/generate_component_registry.py"
|
||||
or return 1
|
||||
source "$__fish_config_dir/conf.d/__fish_config_op_registry.fish"
|
||||
end
|
||||
@@ -1,6 +1,9 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# logging/terminal-capture
|
||||
#
|
||||
# SYNOPSIS
|
||||
# __fish_config_sync_logging
|
||||
#
|
||||
@@ -29,7 +32,7 @@ function __fish_config_sync_logging --description 'Sync C5 logging state: sentin
|
||||
set -l yay_wrapper "$HOME/.local/bin/yay"
|
||||
set -l wrapper_version 1
|
||||
|
||||
if __fish_config_op_enabled __fish_config_op_logging
|
||||
if __fish_config_op_enabled (status current-function)
|
||||
# Logging enabled: remove sentinel and regenerate wrappers if binaries exist
|
||||
rm -f $sentinel
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# autoexec/sync
|
||||
#
|
||||
# SYNOPSIS
|
||||
# __fish_user_dots_link
|
||||
#
|
||||
@@ -41,7 +44,7 @@ function __fish_user_dots_link --description 'Manage the user-dots convenience s
|
||||
end
|
||||
|
||||
# Enabled: creation is a C2 startup side-effect.
|
||||
__fish_config_op_enabled __fish_config_op_autoexec; or return 0
|
||||
__fish_config_op_enabled (status current-function); or return 0
|
||||
|
||||
test -d "$__fish_user_dots_path"; or return 0
|
||||
if test -L "$link"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# COMPONENT
|
||||
# logging/multiplexer-capture
|
||||
#
|
||||
# SYNOPSIS
|
||||
# _zellij_dump_log
|
||||
#
|
||||
@@ -23,7 +26,7 @@
|
||||
# EXAMPLE
|
||||
# _zellij_dump_log
|
||||
function _zellij_dump_log --description 'Dump the current Zellij pane scrollback to a log file, with pruning'
|
||||
__fish_config_op_enabled __fish_config_op_logging; or return 0
|
||||
__fish_config_op_enabled (status current-function); or return 0
|
||||
set -q ZELLIJ; or return 0
|
||||
type -q zellij; or return 0
|
||||
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 12-ai-and-developer-tools
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/dev-tools
|
||||
#
|
||||
# DEPENDENCIES
|
||||
# agents-init
|
||||
#
|
||||
@@ -35,7 +38,7 @@
|
||||
# agy -i "initial prompt"
|
||||
# agy models
|
||||
function agy --wraps=agy --description 'agy wrapper: auto-initializes AGENTS/ sub-repo before launch'
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command agy $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 04-git-and-version-control
|
||||
#
|
||||
# COMPONENT
|
||||
# autoexec/sync
|
||||
#
|
||||
# SYNOPSIS
|
||||
# auto-pull [list]
|
||||
# auto-pull add [PATH]
|
||||
@@ -136,7 +139,7 @@ function auto-pull --description 'Manage the auto-pull repository registry'
|
||||
return 0
|
||||
|
||||
case status
|
||||
if __fish_config_op_enabled __fish_config_op_autoexec
|
||||
if __fish_config_op_enabled (status current-function)
|
||||
echo "$c_ok""auto-pull: ENABLED$c_reset $c_dim(C2 auto-execution on)$c_reset"
|
||||
else
|
||||
echo "$c_warn""auto-pull: DISABLED$c_reset $c_dim(via __fish_config_op_autoexec)$c_reset"
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 14-miscellaneous
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/shell-tools
|
||||
#
|
||||
# SYNOPSIS
|
||||
# bash [args...]
|
||||
#
|
||||
@@ -18,7 +21,7 @@
|
||||
# bash
|
||||
function bash --wraps='bash' --description 'bash switches to bash shell'
|
||||
# Opinionated guard (C1): fall back to bare command bash when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command bash $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 01-file-and-directory
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
#
|
||||
# SYNOPSIS
|
||||
# cat [args...]
|
||||
#
|
||||
@@ -21,7 +24,7 @@
|
||||
# cat ~/projects/myapp
|
||||
function cat --wraps='bat' --description 'Use bat for files, ls for directories, and raw cat for ANSI logs'
|
||||
# Opinionated guard (C1): fall back to bare command cat when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command cat $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 12-ai-and-developer-tools
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/dev-tools
|
||||
#
|
||||
# DEPENDENCIES
|
||||
# agents-init
|
||||
#
|
||||
@@ -33,7 +36,7 @@
|
||||
# claude --resume
|
||||
# claude "Explain the recent changes"
|
||||
function claude --wraps=claude --description 'claude wrapper: auto-links AGENTS.md as CLAUDE.md'
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command claude $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
# path, and the user-dots convenience symlink toggle (Dots link)
|
||||
#
|
||||
# Toggle rows use ← / → (or h / l) to step OFF ← DEFAULT → ON; DEFAULT erases
|
||||
# the variable so the master switch / built-in default applies. Value rows
|
||||
# the variable so the master switch / built-in default applies. On the
|
||||
# Universal/Session pages, Enter on a category row (C1–C6) opens that
|
||||
# category's sub-category drill-down page for finer-grained toggles;
|
||||
# Escape backs out to the category list. Value rows
|
||||
# (Sponge, Paths) use Enter to edit inline; ← / h clears to default. List rows
|
||||
# (e.g. Extra secret, OK codes) accept values separated by commas and/or
|
||||
# whitespace — "A, B", "A,B" and "A B" all yield the same two entries.
|
||||
@@ -49,7 +52,10 @@
|
||||
# ↑ ↓ / k j Move cursor
|
||||
# ← → / h l Toggle rows: OFF ← DEFAULT → ON
|
||||
# ← / h Value rows: clear to default
|
||||
# Enter Value rows: edit inline (Sponge / Paths pages)
|
||||
# Enter Category rows (Universal/Session): open sub-category
|
||||
# drill-down page. Value rows: edit inline (Sponge /
|
||||
# Paths pages)
|
||||
# Escape Sub-category page: back out to the category list
|
||||
# Tab / S-Tab Next / previous page
|
||||
# q / Escape Exit
|
||||
#
|
||||
@@ -82,7 +88,8 @@ function config-settings --description 'Interactive TUI for managing fish config
|
||||
echo "$c_head""Navigation:$c_reset"
|
||||
echo " $c_flag↑ ↓$c_reset or $c_flag""k j$c_reset Move cursor up / down"
|
||||
echo " $c_flag← →$c_reset or $c_flag""h l$c_reset Toggle pages: OFF ← DEFAULT → ON"
|
||||
echo " $c_flag""Enter$c_reset Edit value (Sponge / Paths pages)"
|
||||
echo " $c_flag""Enter$c_reset Open sub-category page (Universal / Session);"
|
||||
echo " edit value (Sponge / Paths pages)"
|
||||
echo " $c_flag← / h$c_reset Clear value to default (value rows)"
|
||||
echo " $c_flag""Tab / S-Tab$c_reset Next / previous page"
|
||||
echo " $c_flag""q$c_reset / $c_flag""Esc$c_reset Exit"
|
||||
@@ -110,6 +117,12 @@ function config-settings --description 'Interactive TUI for managing fish config
|
||||
__fish_config_op_greeting \
|
||||
__fish_config_opinionated
|
||||
|
||||
# ── Drill-down navigation state (Universal/Session pages only) ────────
|
||||
# in_subcat: 1 while viewing a category's sub-category page (Enter to
|
||||
# open, Escape to back out). subcat_row: cursor row within that page.
|
||||
set -l in_subcat 0
|
||||
set -l subcat_row 0
|
||||
|
||||
# ── Value-page row metadata (parallel: var / type) ────────────────────
|
||||
set -l sponge_vars sponge_delay sponge_purge_only_on_exit sponge_allow_previously_successful sponge_successful_exit_codes __fish_sponge_extra_sensitive
|
||||
set -l sponge_types int bool bool list list
|
||||
@@ -140,16 +153,34 @@ function config-settings --description 'Interactive TUI for managing fish config
|
||||
trap 'printf "\e[?25h"; set -g __config_settings_exit 1' INT
|
||||
|
||||
# ── Draw dispatch (page 0/1 = toggle table; 2/3 = value page) ─────────
|
||||
# Records the actual line count of whatever it just drew into panel_h,
|
||||
# so every erase (redraw loop, inline editor, final cleanup) matches
|
||||
# reality -- the sub-category page is n+7 lines (2-6 sub-categories:
|
||||
# 9-13 lines), never the category list's fixed 16.
|
||||
function __cs_dispatch_draw --no-scope-shadowing
|
||||
switch $cur_page
|
||||
case 0
|
||||
__config_settings_draw $cur_row universal $toggle_vars
|
||||
if test $in_subcat -eq 1
|
||||
__config_settings_draw_subcat $subcat_row universal $toggle_vars[(math $cur_row + 1)]
|
||||
set panel_h (math 7 + (count (__config_settings_subcats $toggle_vars[(math $cur_row + 1)])))
|
||||
else
|
||||
__config_settings_draw $cur_row universal $toggle_vars
|
||||
set panel_h 16
|
||||
end
|
||||
case 1
|
||||
__config_settings_draw $cur_row session $toggle_vars
|
||||
if test $in_subcat -eq 1
|
||||
__config_settings_draw_subcat $subcat_row session $toggle_vars[(math $cur_row + 1)]
|
||||
set panel_h (math 7 + (count (__config_settings_subcats $toggle_vars[(math $cur_row + 1)])))
|
||||
else
|
||||
__config_settings_draw $cur_row session $toggle_vars
|
||||
set panel_h 16
|
||||
end
|
||||
case 2
|
||||
__config_settings_draw_value $cur_row sponge
|
||||
set panel_h 16
|
||||
case 3
|
||||
__config_settings_draw_value $cur_row paths
|
||||
set panel_h 16
|
||||
end
|
||||
end
|
||||
__cs_dispatch_draw
|
||||
@@ -174,24 +205,50 @@ function config-settings --description 'Interactive TUI for managing fish config
|
||||
|
||||
switch $key
|
||||
case up k
|
||||
set cur_row (math "max(0, $cur_row - 1)")
|
||||
if test $in_subcat -eq 1
|
||||
set subcat_row (math "max(0, $subcat_row - 1)")
|
||||
else
|
||||
set cur_row (math "max(0, $cur_row - 1)")
|
||||
end
|
||||
case down j
|
||||
# Hoist the page index: fish cannot expand a command-substitution
|
||||
# index inside a quoted math string.
|
||||
set -l pidx (math $cur_page + 1)
|
||||
set cur_row (math "min($page_rows[$pidx] - 1, $cur_row + 1)")
|
||||
if test $in_subcat -eq 1
|
||||
set -l n (count (__config_settings_subcats $toggle_vars[(math $cur_row + 1)]))
|
||||
set subcat_row (math "min($n, $subcat_row + 1)")
|
||||
else
|
||||
# Hoist the page index: fish cannot expand a command-substitution
|
||||
# index inside a quoted math string.
|
||||
set -l pidx (math $cur_page + 1)
|
||||
set cur_row (math "min($page_rows[$pidx] - 1, $cur_row + 1)")
|
||||
end
|
||||
case tab
|
||||
set cur_page (math "($cur_page + 1) % 4")
|
||||
set cur_row 0
|
||||
set in_subcat 0
|
||||
case backtab
|
||||
set cur_page (math "($cur_page + 3) % 4")
|
||||
set cur_row 0
|
||||
set in_subcat 0
|
||||
case right l
|
||||
if test $cur_page -le 1
|
||||
# Toggle page: step toward ON
|
||||
set -l scope universal
|
||||
test $cur_page -eq 1; and set scope session
|
||||
set -l varname $toggle_vars[(math $cur_row + 1)]
|
||||
# Default: the category variable itself -- correct both
|
||||
# when not in a sub-category page at all, and when in
|
||||
# one but sitting on its row 0 (the category's own
|
||||
# toggle). Only row >= 1 of a sub-category page
|
||||
# resolves to a different, sub-category variable.
|
||||
# Hoist the category variable into a plain local first --
|
||||
# fish cannot expand a command-substitution index
|
||||
# ("$toggle_vars[(math ...)]") inside a quoted string
|
||||
# (same reason the down/j case above hoists $pidx).
|
||||
set -l cvar $toggle_vars[(math $cur_row + 1)]
|
||||
set -l varname $cvar
|
||||
if test $in_subcat -eq 1 -a $subcat_row -ne 0
|
||||
set -l rows (__config_settings_subcats $cvar)
|
||||
set -l fields (string split -- \t $rows[$subcat_row])
|
||||
set varname "$cvar"_(string replace -a -- '-' '_' $fields[1])
|
||||
end
|
||||
set -l cur_val (__config_settings_get_val $varname $scope)
|
||||
set -l next_val on
|
||||
test "$cur_val" = off; and set next_val DEFAULT
|
||||
@@ -217,7 +274,17 @@ function config-settings --description 'Interactive TUI for managing fish config
|
||||
if test $cur_page -le 1
|
||||
set -l scope universal
|
||||
test $cur_page -eq 1; and set scope session
|
||||
set -l varname $toggle_vars[(math $cur_row + 1)]
|
||||
# Same varname resolution as the right/l case above
|
||||
# (hoisted local -- see the comment there for why the
|
||||
# command-substitution index can't be inlined into the
|
||||
# quoted string directly).
|
||||
set -l cvar $toggle_vars[(math $cur_row + 1)]
|
||||
set -l varname $cvar
|
||||
if test $in_subcat -eq 1 -a $subcat_row -ne 0
|
||||
set -l rows (__config_settings_subcats $cvar)
|
||||
set -l fields (string split -- \t $rows[$subcat_row])
|
||||
set varname "$cvar"_(string replace -a -- '-' '_' $fields[1])
|
||||
end
|
||||
set -l cur_val (__config_settings_get_val $varname $scope)
|
||||
set -l next_val off
|
||||
test "$cur_val" = on; and set next_val DEFAULT
|
||||
@@ -246,7 +313,12 @@ function config-settings --description 'Interactive TUI for managing fish config
|
||||
end
|
||||
end
|
||||
case enter
|
||||
if test $cur_page -ge 2
|
||||
if test $cur_page -le 1
|
||||
if test $in_subcat -eq 0 -a $cur_row -le 5
|
||||
set in_subcat 1
|
||||
set subcat_row 0
|
||||
end
|
||||
else if test $cur_page -ge 2
|
||||
set -l v_vars $sponge_vars
|
||||
set -l v_types $sponge_types
|
||||
set -l v_defaults $sponge_defaults
|
||||
@@ -313,8 +385,14 @@ function config-settings --description 'Interactive TUI for managing fish config
|
||||
set did_redraw 1
|
||||
end
|
||||
end
|
||||
case q Q quit escape
|
||||
case q Q quit
|
||||
break
|
||||
case escape
|
||||
if test $in_subcat -eq 1
|
||||
set in_subcat 0
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Skip redraw entirely when the key reader timed out with no resize
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 01-file-and-directory
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
#
|
||||
# SYNOPSIS
|
||||
# du [--disk|--dir|--dua] [args...]
|
||||
#
|
||||
@@ -23,7 +26,7 @@
|
||||
# du --disk
|
||||
function du --description 'Execute du'
|
||||
# Opinionated guard (C1): fall back to bare command du when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command du $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 03-editors-and-viewers
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/dev-tools
|
||||
#
|
||||
# SYNOPSIS
|
||||
# edit [-V|-t] [-e EDITOR] [-c] [-x TEXT] [-n] [-v|-s] [FILE...]
|
||||
#
|
||||
@@ -50,7 +53,7 @@ function edit --description 'Open files in a terminal or GUI editor with fallbac
|
||||
set -l c_reset (set_color normal)
|
||||
|
||||
# Opinionated guard (C1): fall back to the legacy bare-editor behavior.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
if set -q EDITOR; and test -n "$EDITOR"
|
||||
$EDITOR $argv
|
||||
else if type -q nvim
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 08-terminal-management
|
||||
#
|
||||
# COMPONENT
|
||||
# overrides/prompt
|
||||
#
|
||||
# SYNOPSIS
|
||||
# fish_right_prompt
|
||||
#
|
||||
@@ -31,7 +34,7 @@ function fish_right_prompt
|
||||
# Docker context — only relevant alongside the starship prompt, and only
|
||||
# when docker is actually installed (guarded like every other optional
|
||||
# integration in this config).
|
||||
if type -q docker; and type -q starship; and __fish_config_op_enabled __fish_config_op_overrides
|
||||
if type -q docker; and type -q starship; and __fish_config_op_enabled (status current-function)
|
||||
set -l docker_ctx (docker context show 2>/dev/null)
|
||||
if test -n "$docker_ctx"; and test "$docker_ctx" != default
|
||||
set_color blue
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 04-git-and-version-control
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/history-logs
|
||||
#
|
||||
# SYNOPSIS
|
||||
# hist
|
||||
#
|
||||
@@ -15,7 +18,7 @@
|
||||
# hist
|
||||
function hist --description 'Search fish history and put it in the prompt'
|
||||
# Opinionated guard (C4): integrations disabled
|
||||
if not __fish_config_op_enabled __fish_config_op_integrations
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_reset (set_color normal)
|
||||
echo "$c_err"'hist: disabled by __fish_config_op_integrations'"$c_reset" >&2
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 14-miscellaneous
|
||||
#
|
||||
# COMPONENT
|
||||
# logging/terminal-capture
|
||||
#
|
||||
# SYNOPSIS
|
||||
# kitty-logging [install | uninstall | status | dismiss] [-h]
|
||||
#
|
||||
@@ -97,7 +100,7 @@ function kitty-logging --description 'Install/manage the fish-config Kitty scrol
|
||||
else
|
||||
echo " Watcher file: $c_warn""not installed$c_reset"
|
||||
end
|
||||
if __fish_config_op_enabled __fish_config_op_logging
|
||||
if __fish_config_op_enabled (status current-function)
|
||||
echo " C5 logging: $c_ok""enabled$c_reset"
|
||||
else
|
||||
echo " C5 logging: $c_warn""disabled$c_reset (capture is currently inert)"
|
||||
@@ -143,7 +146,7 @@ function kitty-logging --description 'Install/manage the fish-config Kitty scrol
|
||||
end
|
||||
echo "$c_ok""→ Installed.$c_reset Watcher wired into $conf"
|
||||
echo " $c_dim""Restart Kitty (new windows) for it to take effect.$c_reset"
|
||||
if not __fish_config_op_enabled __fish_config_op_logging
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
echo " $c_warn""Note: C5 logging is disabled, so capture is currently inert.$c_reset"
|
||||
end
|
||||
return 0
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 03-editors-and-viewers
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/shell-tools
|
||||
#
|
||||
# SYNOPSIS
|
||||
# less [args...]
|
||||
#
|
||||
@@ -18,7 +21,7 @@
|
||||
# less /var/log/syslog
|
||||
function less --wraps='ov' --description 'Pager wrapper: $PAGER → ov → less → more → cat'
|
||||
# Opinionated guard (C1): fall back to bare command less when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command less $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 11-pager-and-logging
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/history-logs
|
||||
#
|
||||
# SYNOPSIS
|
||||
# logs [-h] [-c <category>]
|
||||
#
|
||||
@@ -35,7 +38,7 @@
|
||||
# logs -c scrollback
|
||||
function logs --description 'Browse terminal log files interactively with fzf'
|
||||
# Opinionated guard (C4): integrations disabled
|
||||
if not __fish_config_op_enabled __fish_config_op_integrations
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_reset (set_color normal)
|
||||
echo "$c_err"'logs: disabled by __fish_config_op_integrations'"$c_reset" >&2
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 01-file-and-directory
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
#
|
||||
# SYNOPSIS
|
||||
# ls [args...]
|
||||
#
|
||||
@@ -20,7 +23,7 @@
|
||||
# ls -a ~/projects
|
||||
function ls --description 'List all files'
|
||||
# Opinionated guard (C1): fall back to bare command ls when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command ls $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 01-file-and-directory
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
#
|
||||
# SYNOPSIS
|
||||
# mkdir [args...]
|
||||
#
|
||||
@@ -20,7 +23,7 @@
|
||||
# mkdir ~/projects/myapp/src
|
||||
function mkdir --description 'Execute mkdir'
|
||||
# Opinionated guard (C1): fall back to bare command mkdir when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command mkdir $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 01-file-and-directory
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
#
|
||||
# SYNOPSIS
|
||||
# mv [args...]
|
||||
#
|
||||
@@ -27,7 +30,7 @@
|
||||
# mv ~/.config/btop/themes/themes ~/.config/btop/themes
|
||||
function mv --wraps='mv' --description 'Move files with auto-collapse for nested directories'
|
||||
# Opinionated guard (C1): fall back to bare command mv when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command mv $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 10-network
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/network
|
||||
#
|
||||
# SYNOPSIS
|
||||
# ping [args...]
|
||||
#
|
||||
@@ -21,7 +24,7 @@
|
||||
# ping --legend google.com
|
||||
function ping --description 'prettyping with default nolegend'
|
||||
# Opinionated guard (C1): fall back to bare command ping when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command ping $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 01-file-and-directory
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/search
|
||||
#
|
||||
# SYNOPSIS
|
||||
# rg [args...]
|
||||
#
|
||||
@@ -21,7 +24,7 @@
|
||||
# rg -l "TODO" ~/projects/myapp
|
||||
function rg --description 'alias rg=rg --hyperlink-format=kitty'
|
||||
# Opinionated guard (C1): fall back to bare command rg when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command rg $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 01-file-and-directory
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/filesystem
|
||||
#
|
||||
# SYNOPSIS
|
||||
# rm [-e [options] | -S | args...]
|
||||
#
|
||||
@@ -38,7 +41,7 @@
|
||||
# Falls back to /usr/bin/rm when trash is unavailable.
|
||||
function rm --description 'Ultimate rm: trash, list, empty, and secure-erase'
|
||||
# Opinionated guard (C1): fall back to bare command rm when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command rm $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
# CATEGORY
|
||||
# 11-pager-and-logging
|
||||
#
|
||||
# COMPONENT
|
||||
# site exit-plain: overrides/key-bindings
|
||||
# site logging-guard: logging/terminal-capture
|
||||
#
|
||||
# SYNOPSIS
|
||||
# smart_exit [-h] [-n]
|
||||
#
|
||||
@@ -32,7 +36,7 @@ function smart_exit --description 'Capture colorized scrollback before exiting,
|
||||
# Opinionated guard (C3): exit plainly when overrides are disabled.
|
||||
# This composes with Task #4's __fish_config_enable_logging, which will
|
||||
# gate only the scrollback capture while leaving the exit wrapper active.
|
||||
if not __fish_config_op_enabled __fish_config_op_overrides
|
||||
if not __fish_config_op_enabled (status current-function) exit-plain
|
||||
builtin exit $argv
|
||||
end
|
||||
|
||||
@@ -60,7 +64,7 @@ function smart_exit --description 'Capture colorized scrollback before exiting,
|
||||
# C5 — Logging & Capture: skip all capture when logging is disabled.
|
||||
# When disabled, tell Kitty the window is handled so its watcher doesn't
|
||||
# capture either — belt-and-suspenders alongside the sentinel file.
|
||||
if not __fish_config_op_enabled __fish_config_op_logging
|
||||
if not __fish_config_op_enabled (status current-function) logging-guard
|
||||
if test -n "$KITTY_WINDOW_ID"
|
||||
kitty @ set-user-vars "logged_by_shell=true" 2>/dev/null
|
||||
end
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 08-terminal-management
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/window-mgmt
|
||||
#
|
||||
# SYNOPSIS
|
||||
# split [-h | -v] [command...]
|
||||
#
|
||||
@@ -27,7 +30,7 @@
|
||||
# split -v nvim README.md
|
||||
function split --description 'Run a command in a new terminal split'
|
||||
# Opinionated guard (C4): integrations disabled
|
||||
if not __fish_config_op_enabled __fish_config_op_integrations
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_reset (set_color normal)
|
||||
echo "$c_err"'split: disabled by __fish_config_op_integrations'"$c_reset" >&2
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 08-terminal-management
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/window-mgmt
|
||||
#
|
||||
# SYNOPSIS
|
||||
# spwin [args...]
|
||||
#
|
||||
@@ -22,7 +25,7 @@
|
||||
# spwin
|
||||
function spwin --wraps='~/.config/kitty/spawn-window.sh' --description 'spawn window in kitty or wezterm'
|
||||
# Opinionated guard (C4): integrations disabled
|
||||
if not __fish_config_op_enabled __fish_config_op_integrations
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_reset (set_color normal)
|
||||
echo "$c_err"'spwin: disabled by __fish_config_op_integrations'"$c_reset" >&2
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 08-terminal-management
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/network
|
||||
#
|
||||
# SYNOPSIS
|
||||
# ssh [args...]
|
||||
#
|
||||
@@ -20,7 +23,7 @@
|
||||
# ssh user@host
|
||||
function ssh --description 'Alias ssh to kitten ssh when using Kitty terminal'
|
||||
# Opinionated guard (C1): fall back to bare command ssh when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command ssh $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 08-terminal-management
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/window-mgmt
|
||||
#
|
||||
# SYNOPSIS
|
||||
# tab [args...]
|
||||
#
|
||||
@@ -23,7 +26,7 @@
|
||||
# tab
|
||||
function tab --description 'Spawn a new tab in the current terminal'
|
||||
# Opinionated guard (C4): integrations disabled
|
||||
if not __fish_config_op_enabled __fish_config_op_integrations
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_reset (set_color normal)
|
||||
echo "$c_err"'tab: disabled by __fish_config_op_integrations'"$c_reset" >&2
|
||||
|
||||
+4
-1
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 07-system-and-monitoring
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/monitor
|
||||
#
|
||||
# SYNOPSIS
|
||||
# top [args...]
|
||||
#
|
||||
@@ -18,7 +21,7 @@
|
||||
# top
|
||||
function top --wraps='btop' --description 'Use btop as a modern replacement for top'
|
||||
# Opinionated guard (C1): fall back to bare command top when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command top $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 05-package-management
|
||||
#
|
||||
# COMPONENT
|
||||
# integrations/pkg-upgrade
|
||||
#
|
||||
# SYNOPSIS
|
||||
# upgrade
|
||||
#
|
||||
@@ -19,7 +22,7 @@
|
||||
# upgrade
|
||||
function upgrade --description 'Full system upgrade via paru or yay'
|
||||
# Opinionated guard (C4): integrations disabled
|
||||
if not __fish_config_op_enabled __fish_config_op_integrations
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_reset (set_color normal)
|
||||
echo "$c_err"'upgrade: disabled by __fish_config_op_integrations'"$c_reset" >&2
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# CATEGORY
|
||||
# 13-media-and-utilities
|
||||
#
|
||||
# COMPONENT
|
||||
# aliases/network
|
||||
#
|
||||
# SYNOPSIS
|
||||
# yt-dlp [args...] URL [URL...]
|
||||
#
|
||||
@@ -29,7 +32,7 @@
|
||||
# yt-dlp --no-embed-thumbnail dQw4w9WgXcQ # drops our thumbnail default
|
||||
function yt-dlp --description 'yt-dlp with embedding + SponsorBlock defaults'
|
||||
# Opinionated guard (C1): fall back to bare command yt-dlp when disabled.
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
if not __fish_config_op_enabled (status current-function)
|
||||
command yt-dlp $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user