From ec47b0671c00409dd6f05e8f19b461101eeb8037 Mon Sep 17 00:00:00 2001 From: rootiest Date: Sat, 4 Jul 2026 02:34:20 -0400 Subject: [PATCH] feat(config-settings): add Dots link toggle for user-dots symlink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the user-dots symlink logic into the __fish_user_dots_link helper and add a dedicated __fish_user_dots_symlink toggle, surfaced as a 'Dots link' bool row on the config-settings Paths page. Unlike the opinionated categories it has no universal/session split — it acts on a literal path. Setting it falsy (or toggling off) stops symlink generation and removes any existing link immediately, honoured regardless of the C2 master switch. Creation remains a C2 startup side-effect. config.fish now calls the helper. Docs: README, fish-config.md (C2 table, Paths page, machine-local section), and fish-config.index updated. --- README.md | 4 +- config.fish | 19 ++------ docs/fish-config.index | 2 + docs/fish-config.md | 17 ++++++- functions/__config_settings_draw_value.fish | 8 ++-- functions/__fish_user_dots_link.fish | 53 +++++++++++++++++++++ functions/config-settings.fish | 31 ++++++++---- 7 files changed, 103 insertions(+), 31 deletions(-) create mode 100644 functions/__fish_user_dots_link.fish diff --git a/README.md b/README.md index beaa023..9d50965 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,9 @@ test -f "$__fish_user_dots_path/local.fish" and source "$__fish_user_dots_path/local.fish" ``` -For convenience, a git-ignored `user-dots` symlink in the fish config directory is pointed at `$__fish_user_dots_path` on startup, so the overlay can be browsed from `~/.config/fish/`. It is recreated if missing and repointed if the path variable changes. This is a C2 startup side-effect (`__fish_config_op_autoexec`); it only ever manages a symlink and never clobbers a real file or directory at that path. +For convenience, a git-ignored `user-dots` symlink in the fish config directory is pointed at `$__fish_user_dots_path` on startup, so the overlay can be browsed from `~/.config/fish/`. It is recreated if missing and repointed if the path variable changes. Creation is a C2 startup side-effect (`__fish_config_op_autoexec`); it only ever manages a symlink and never clobbers a real file or directory at that path. + +To opt out, set `__fish_user_dots_symlink` to a falsy value (or toggle **Dots link** off on the **Paths** page of `config-settings`). Disabling it stops the symlink being generated and removes any existing one immediately — honoured regardless of the C2 master switch. `fish_variables` (which fish auto-manages and may contain universal variable state) is excluded from this repo via `.gitignore`. diff --git a/config.fish b/config.fish index e260113..5561769 100644 --- a/config.fish +++ b/config.fish @@ -227,20 +227,11 @@ if status is-interactive set -q __fish_user_dots_path or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish" # ────────────────────── user-dots convenience symlink ─────────────────── - # Keep $__fish_config_dir/user-dots pointing at the resolved path so it can - # be browsed from the fish config dir. Git-ignored; a C2 startup side-effect. - # Only ever manages a symlink — never clobbers a real file/dir placed there. - if __fish_config_op_enabled __fish_config_op_autoexec - set -l __udots_link "$__fish_config_dir/user-dots" - if test -d "$__fish_user_dots_path" - if test -L "$__udots_link" - test (readlink "$__udots_link") != "$__fish_user_dots_path" - and ln -sfn "$__fish_user_dots_path" "$__udots_link" - else if not test -e "$__udots_link" - ln -s "$__fish_user_dots_path" "$__udots_link" - end - end - end + # Keep $__fish_config_dir/user-dots tracking the resolved path so it can be + # browsed from the fish config dir. Git-ignored. Controlled by the + # __fish_user_dots_symlink toggle (config-settings → Paths); creation is a + # C2 side-effect, removal-on-opt-out is honoured regardless. See the helper. + __fish_user_dots_link # ─────────────────────── Source machine-local config ──────────────────── # Sources local.fish if it exists. That file handles sourcing its own diff --git a/docs/fish-config.index b/docs/fish-config.index index 9fc1e8e..f47089b 100644 --- a/docs/fish-config.index +++ b/docs/fish-config.index @@ -216,6 +216,8 @@ install-methods=## Install Methods customization=# 7. CUSTOMIZATION customize=# 7. CUSTOMIZATION local=## Machine-local Configuration +user-dots=## Machine-local Configuration +dots-link=## Machine-local Configuration secrets=## Secrets and API Keys overrides=## Overriding Configuration Variables universal=## Fish Universal Variables diff --git a/docs/fish-config.md b/docs/fish-config.md index 264657a..00b7e06 100644 --- a/docs/fish-config.md +++ b/docs/fish-config.md @@ -1435,8 +1435,9 @@ Add -i (interactive confirmation) to destructive commands: Sponge — sponge history-scrubbing settings: delay, successful exit codes, purge-only-on-exit, allow-previously-successful, and extra sensitive variable-name tokens - Paths — scrollback log directory, scrollback max files, and the - user-dots path + Paths — scrollback log directory, scrollback max files, the + user-dots path, and the user-dots convenience symlink toggle + (Dots link) Toggle rows use ← → (or h/l) along an OFF ← DEFAULT → ON scale; DEFAULT erases the variable so the master switch / built-in default applies. Value @@ -1666,6 +1667,14 @@ custom location with: Typical uses: additional PATH entries, local aliases, hostname-specific env vars, work-specific tool configs. +For convenience, a git-ignored `user-dots` symlink in the fish config +directory tracks `$__fish_user_dots_path` so the overlay can be browsed from +`~/.config/fish/`. It is created if missing and repointed if the path changes. +Opt out by setting `__fish_user_dots_symlink` to a falsy value, or toggling +"Dots link" off on the config-settings Paths page — this stops generation and +removes any existing link. It only ever manages a symlink and never clobbers a +real file or directory at that path. + ## Secrets and API Keys $__fish_user_dots_path/secrets.fish @@ -1831,6 +1840,10 @@ wrapper generation, no automatic venv activation, no WakaTime reporting, no auto-pull (the PWD handler is never registered), and the user-dots convenience symlink is not created. The symlink is git-ignored and only ever managed as a symlink — a real file or directory at that path is left untouched. +The symlink has its own opt-out independent of C2: set __fish_user_dots_symlink +to a falsy value (or toggle "Dots link" off on the config-settings Paths page) +to stop generating it and remove any existing link — honoured even when C2 is +enabled. Managed by the __fish_user_dots_link helper. The first-run completion marker (__fish_config_first_run_complete) is still set so the init does not re-run on subsequent shells. diff --git a/functions/__config_settings_draw_value.fish b/functions/__config_settings_draw_value.fish index 27e015d..5b2b505 100644 --- a/functions/__config_settings_draw_value.fish +++ b/functions/__config_settings_draw_value.fish @@ -57,10 +57,10 @@ function __config_settings_draw_value else set title "Path Settings" set active_idx 3 - set vars __fish_scrollback_history_dir __fish_scrollback_history_max_files __fish_user_dots_path - set labels "Log dir" "Log max" "Dots path" - set types path int path - set hints "~/.terminal_history" 100 "(default)" + set vars __fish_scrollback_history_dir __fish_scrollback_history_max_files __fish_user_dots_path __fish_user_dots_symlink + set labels "Log dir" "Log max" "Dots path" "Dots link" + set types path int path bool + set hints "~/.terminal_history" 100 "(default)" on end set -l nrows (count $vars) diff --git a/functions/__fish_user_dots_link.fish b/functions/__fish_user_dots_link.fish new file mode 100644 index 0000000..6873671 --- /dev/null +++ b/functions/__fish_user_dots_link.fish @@ -0,0 +1,53 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# SYNOPSIS +# __fish_user_dots_link +# +# DESCRIPTION +# Manages the git-ignored `user-dots` convenience symlink in the fish config +# directory ($__fish_config_dir/user-dots), pointing it at the resolved +# $__fish_user_dots_path so the private overlay can be browsed from +# ~/.config/fish/. +# +# Behaviour is controlled by the __fish_user_dots_symlink toggle: +# - explicit falsy (0/false/…) — remove our symlink if present and stop. +# Honoured regardless of C2, so opting out always cleans up. +# - unset or truthy (default) — create the link if missing and repoint it +# if the target changed. This is a C2 startup side-effect, so it only +# creates when __fish_config_op_autoexec is enabled. +# +# Only ever manages a symlink; a real file or directory at that path is left +# untouched. +# +# ARGUMENTS +# (none) +# +# RETURNS +# 0 Always +# +# EXAMPLE +# __fish_user_dots_link +function __fish_user_dots_link --description 'Manage the user-dots convenience symlink' + set -l link "$__fish_config_dir/user-dots" + set -q __fish_user_dots_path + or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish" + + # Explicit opt-out: remove our symlink (never a real file/dir) and stop. + __fish_variable_check __fish_user_dots_symlink + if test $status -eq 1 + test -L "$link"; and rm -f "$link" + return 0 + end + + # Enabled: creation is a C2 startup side-effect. + __fish_config_op_enabled __fish_config_op_autoexec; or return 0 + + test -d "$__fish_user_dots_path"; or return 0 + if test -L "$link" + test (readlink "$link") != "$__fish_user_dots_path" + and ln -sfn "$__fish_user_dots_path" "$link" + else if not test -e "$link" + ln -s "$__fish_user_dots_path" "$link" + end +end diff --git a/functions/config-settings.fish b/functions/config-settings.fish index 6e76229..9e7ec13 100644 --- a/functions/config-settings.fish +++ b/functions/config-settings.fish @@ -80,9 +80,9 @@ function config-settings --description 'Interactive TUI for managing fish config 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 set -l sponge_labels Delay "Purge@exit" "Allow prev" "OK codes" "Extra secret" - set -l paths_vars __fish_scrollback_history_dir __fish_scrollback_history_max_files __fish_user_dots_path - set -l paths_types path int path - set -l paths_labels "Log dir" "Log max" "Dots path" + set -l paths_vars __fish_scrollback_history_dir __fish_scrollback_history_max_files __fish_user_dots_path __fish_user_dots_symlink + set -l paths_types path int path bool + set -l paths_labels "Log dir" "Log max" "Dots path" "Dots link" # Reset/blank-edit target for each value row. A non-empty entry is written # verbatim (sponge reads sponge_delay / sponge_successful_exit_codes with no @@ -91,10 +91,10 @@ function config-settings --description 'Interactive TUI for managing fish config # extra-sensitive list all tolerate being unset). Bool rows are not reset # through this path — they are a 2-state true/false with no unset state. set -l sponge_defaults 2 '' '' 0 '' - set -l paths_defaults '' '' '' + set -l paths_defaults '' '' '' '' # Rows per page index 0..3 - set -l page_rows 7 7 5 3 + set -l page_rows 7 7 5 4 set -l cur_page 0 # 0=Universal 1=Session 2=Sponge 3=Paths set -l cur_row 0 @@ -162,12 +162,21 @@ function config-settings --description 'Interactive TUI for managing fish config set -l next_val on test "$cur_val" = off; and set next_val DEFAULT __config_settings_apply $varname $scope $next_val - else if test $cur_page -eq 2 - # Sponge bool rows are 2-state (true/false) with no unset - # state — sponge reads them with no fallback. → sets true. + else + # Value pages: bool rows are 2-state (true/false). → sets + # true. Sponge reads its bools with no fallback; the Paths + # "Dots link" bool drives __fish_user_dots_link on change. + set -l v_vars $sponge_vars + set -l v_types $sponge_types + if test $cur_page -eq 3 + set v_vars $paths_vars + set v_types $paths_types + end set -l ridx (math $cur_row + 1) - if test "$sponge_types[$ridx]" = bool - set -U $sponge_vars[$ridx] true 2>/dev/null + if test "$v_types[$ridx]" = bool + set -U $v_vars[$ridx] true 2>/dev/null + test "$v_vars[$ridx]" = __fish_user_dots_symlink + and __fish_user_dots_link end end case left h @@ -196,6 +205,8 @@ function config-settings --description 'Interactive TUI for managing fish config set -l vtype $v_types[$ridx] if test "$vtype" = bool set -U $varname false 2>/dev/null + test "$varname" = __fish_user_dots_symlink + and __fish_user_dots_link else __config_settings_set_value $varname $vtype "$v_defaults[$ridx]" end