feat(docs): run codespans over the man-page pipeline too

A token was typeset by whichever pipeline happened to render it: the
site marked tmux and local.fish through codespans, while the man page
and config-help marked only what the SSOT had backticked by hand. Run
the same pass in build_concat() so prose is marked identically wherever
it is rendered (549 -> 662 spans in the concat).

codespans now treats a four-space block as code. The site never meets
one -- prettify() has already turned it into a fence by then -- but the
concat keeps the indented form pandoc wants, and its contents are
verbatim: without this the table of contents alone would come out with
ov, bat, less and cat wrapped inside a code block. Section 5 is
unaffected for the same reason; its entries arrive as indented blocks
that pandoc already sets in a monospace font.

test_codespans_is_site_only asserted the opposite guarantee and was
passing only because its example, -r/--resume, sits inside one of those
newly-protected blocks. It is replaced by tests for what is now true:
indented blocks stay verbatim, prose spans reach the concat, and
section 5 carries no backticks.

The man page is left for CI to regenerate; pandoc is not needed to
build the concat.
This commit is contained in:
2026-08-31 21:56:55 -04:00
parent 2ce8bebf29
commit b01124f99d
4 changed files with 184 additions and 111 deletions
+20 -6
View File
@@ -95,6 +95,16 @@ def build_concat(root: Path) -> str:
with no frontmatter fences and no Astro-visible frontmatter key. When with no frontmatter fences and no Astro-visible frontmatter key. When
present, its contents are re-emitted byte-for-byte as the leading present, its contents are re-emitted byte-for-byte as the leading
`---`-fenced block, ahead of every heading. `---`-fenced block, ahead of every heading.
Bodies go through `codespans` here so a token is typeset the same way
in every output: `tmux` and `local.fish` are wrapped on the site by
that pass, and without it the man page marked only what the SSOT
happened to backtick by hand. Section 5 is unaffected -- its entries
arrive as indented verbatim blocks, which `codespans` leaves alone and
pandoc already sets in a monospace font.
Only bodies are passed: the pandoc metadata block above is not prose
and must survive byte-for-byte.
""" """
entries = build_entries(mt.parse_functions(FUNCTIONS)) entries = build_entries(mt.parse_functions(FUNCTIONS))
chunks: list[str] = [] chunks: list[str] = []
@@ -117,6 +127,7 @@ def build_concat(root: Path) -> str:
body = re.sub(r"<LinkButton.*?</LinkButton>\n*", "", body, flags=re.DOTALL) body = re.sub(r"<LinkButton.*?</LinkButton>\n*", "", body, flags=re.DOTALL)
body = re.sub(r"<CardGrid.*?</CardGrid>\n*", "", body, flags=re.DOTALL) body = re.sub(r"<CardGrid.*?</CardGrid>\n*", "", body, flags=re.DOTALL)
body = re.sub(r"\[([^\]]+)\]\(/[^)]+\)", r"\1", body) body = re.sub(r"\[([^\]]+)\]\(/[^)]+\)", r"\1", body)
body = codespans.add_code_spans(body, _code_vocabulary())
chunks.append(mt.shift_headings(body, depth)) chunks.append(mt.shift_headings(body, depth))
return "\n\n".join(chunks) + "\n" return "\n\n".join(chunks) + "\n"
@@ -495,12 +506,15 @@ def _code_vocabulary() -> codespans.Vocabulary:
def prettify(body: str, entry_name: str | None = None) -> str: def prettify(body: str, entry_name: str | None = None) -> str:
"""Rewrite a body's indented code blocks and labeled asides for the website. """Rewrite a body's indented code blocks and labeled asides for the website.
Site-only: the man page and `config-help` keep reading the untouched The block and aside rewrites are site-only: the man page and
SSOT, where the indented form and the `LABEL:` text are exactly what `config-help` keep reading the untouched SSOT, where the indented form
pandoc/`config-help` want. The same applies to the inline code spans and the `LABEL:` text are exactly what pandoc/`config-help` want.
added last: `-a/--all` and `__fish_config_op_aliases` are authored bare
so the `functions/*.fish` headers stay readable as plain text, and the The inline code spans added last are not site-only. `-a/--all` and
backticks the site wants are put on here rather than in the SSOT. `__fish_config_op_aliases` are authored bare so the `functions/*.fish`
headers stay readable as plain text, and the backticks every output
wants are put on here rather than in the SSOT -- `build_concat()` runs
the same pass for the man page and `config-help`.
""" """
out: list[str] = [] out: list[str] = []
block: list[str] = [] block: list[str] = []
+16 -4
View File
@@ -18,8 +18,9 @@ touched, so the man page and `config-help` keep the plain-text form.
Everything here is conservative by construction: leaving a token alone is Everything here is conservative by construction: leaving a token alone is
always safe and wrapping the wrong one is not, so every rule bails out the always safe and wrapping the wrong one is not, so every rule bails out the
moment it is unsure. The regions that must never be rewritten -- fenced moment it is unsure. The regions that must never be rewritten -- fenced
blocks, existing code spans, link targets, URLs, JSX attributes, blocks, indented code blocks, existing code spans, link targets, URLs, JSX
`<FileTree>` bodies, headings -- are recognised first and passed through. attributes, `<FileTree>` bodies, headings -- are recognised first and
passed through.
""" """
import functools import functools
@@ -359,6 +360,14 @@ FILE_TREE_OPEN = "<FileTree"
FILE_TREE_CLOSE = "</FileTree>" FILE_TREE_CLOSE = "</FileTree>"
CELL_SPLIT_RE = re.compile(r"(?<!\\)\|") CELL_SPLIT_RE = re.compile(r"(?<!\\)\|")
# A four-space indent is this manual's code block. The site never sees one
# -- prettify() has already turned it into a fence by the time this module
# runs -- but build_concat() keeps the indented form, because that is what
# pandoc and `config-help` want, and its contents are code that must not be
# rewritten: the table of contents alone would otherwise have `ov`, `bat`,
# `less` and `cat` wrapped inside a code block.
INDENTED_CODE = " "
def _skip_line(line: str) -> bool: def _skip_line(line: str) -> bool:
"""True for a line that must be passed through untouched. """True for a line that must be passed through untouched.
@@ -488,8 +497,9 @@ def add_code_spans(text: str, vocab: Vocabulary = EMPTY_VOCABULARY) -> str:
"""Wrap code-shaped tokens in `text` in inline code spans. """Wrap code-shaped tokens in `text` in inline code spans.
`text` is a rendered page body (no frontmatter). Fenced blocks, `text` is a rendered page body (no frontmatter). Fenced blocks,
`<FileTree>` bodies, headings, component markup, existing code spans, indented code blocks, `<FileTree>` bodies, headings, component markup,
link targets and URLs are left exactly as they are. existing code spans, link targets and URLs are left exactly as they
are.
""" """
scanner = _scanner(vocab) scanner = _scanner(vocab)
atom_re = _atom_re(vocab) atom_re = _atom_re(vocab)
@@ -510,6 +520,8 @@ def add_code_spans(text: str, vocab: Vocabulary = EMPTY_VOCABULARY) -> str:
if FILE_TREE_CLOSE in line: if FILE_TREE_CLOSE in line:
in_tree = False in_tree = False
continue continue
if line.startswith(INDENTED_CODE):
continue
eligible[i] = not _skip_line(line) eligible[i] = not _skip_line(line)
# Command columns are a property of a whole table, so the contiguous # Command columns are a property of a whole table, so the contiguous
+97 -97
View File
@@ -32,10 +32,10 @@ A production-grade Fish shell configuration targeting Fish 4.x. It provides:
- Drop-in replacements for common Unix tools (`ls`, `cat`, `rm`, `du`, `ping`, `less`) - Drop-in replacements for common Unix tools (`ls`, `cat`, `rm`, `du`, `ping`, `less`)
- Deep Kitty and WezTerm terminal integration: tab/window/pane management from - Deep Kitty and WezTerm terminal integration: tab/window/pane management from
the command line the command line
- Optional session logging: terminal scrollback, tmux/zellij panes, and - Optional session logging: terminal scrollback, `tmux`/`zellij` panes, and
paru/yay output captured to `~/.terminal_history` (off by default; see C5 Logging) `paru`/`yay` output captured to `~/.terminal_history` (off by default; see C5 Logging)
- Automatic Python virtualenv activation on directory change - Automatic Python virtualenv activation on directory change
- Cross-platform package management via pkg and fish-deps - Cross-platform package management via pkg and `fish-deps`
- AI scaffolding helpers for Claude Code and Antigravity - AI scaffolding helpers for Claude Code and Antigravity
- Catppuccin Mocha color theme throughout - Catppuccin Mocha color theme throughout
@@ -133,8 +133,8 @@ The configuration uses a structured file tree:
# 1. CONFIGURATION VARIABLES # 1. CONFIGURATION VARIABLES
These variables are exported from config.fish on every interactive session. These variables are exported from `config.fish` on every interactive session.
Override them in local.fish (see Section 10, Personalization). Override them in `local.fish` (see Section 10, Personalization).
## Environment Directories (XDG) ## Environment Directories (XDG)
@@ -290,7 +290,7 @@ Directories prepended to PATH in this order (first wins):
| `~/scripts` | Personal shell scripts | | `~/scripts` | Personal shell scripts |
| `~/bin` | Cargo binaries (appended — lowest priority) | | `~/bin` | Cargo binaries (appended — lowest priority) |
| `$BUN_INSTALL/bin` | Bun runtime and global packages | | `$BUN_INSTALL/bin` | Bun runtime and global packages |
| `$NPM_CONFIG_PREFIX/bin` | Global npm packages | | `$NPM_CONFIG_PREFIX/bin` | Global `npm` packages |
| `~/.lmstudio/bin` | LM Studio CLI | | `~/.lmstudio/bin` | LM Studio CLI |
| `~/.resend/bin` | Resend CLI | | `~/.resend/bin` | Resend CLI |
| `~/.fzf/bin` | `fzf` binary (git-installed) | | `~/.fzf/bin` | `fzf` binary (git-installed) |
@@ -306,7 +306,7 @@ TIP: This standard PATH setup is gated behind the opinionated component override
# 3. KEY BINDINGS # 3. KEY BINDINGS
The shell uses Vi key bindings (fish_vi_key_bindings). All custom bindings The shell uses Vi key bindings (`fish_vi_key_bindings`). All custom bindings
are active in Insert, Normal, and Visual modes unless noted. are active in Insert, Normal, and Visual modes unless noted.
Binding Action Binding Action
@@ -561,7 +561,7 @@ as keybindings, but they all serve the same purpose.
## 4.11 Shell Aliases ## 4.11 Shell Aliases
These aliases are defined in conf.d/tricks.fish via alias (which creates Fish These aliases are defined in `conf.d/tricks.fish` via alias (which creates Fish
functions). They are active in all interactive sessions. functions). They are active in all interactive sessions.
Abbreviation Description Abbreviation Description
@@ -800,7 +800,7 @@ functions). They are active in all interactive sessions.
Wraps mv to automatically collapse nested directories of the same name. Wraps mv to automatically collapse nested directories of the same name.
When extracting archives results in redundant structures (e.g., When extracting archives results in redundant structures (e.g.,
themes/themes/), calling `mv themes/themes themes` will gracefully themes/themes/), calling mv themes/themes themes will gracefully
move the inner contents up one level and remove the empty outer shell. move the inner contents up one level and remove the empty outer shell.
Opinionated component (C1): when disabled via __fish_config_op_aliases, Opinionated component (C1): when disabled via __fish_config_op_aliases,
@@ -1327,10 +1327,10 @@ functions). They are active in all interactive sessions.
Optional btop, dust, duf, prettyping, go, lazygit, Optional btop, dust, duf, prettyping, go, lazygit,
lazydocker, docker, yt-dlp, screen — single-purpose lazydocker, docker, yt-dlp, screen — single-purpose
wrapper conveniences that only matter if you wrapper conveniences that only matter if you
already use that tool; skipped by `install`/`sync` already use that tool; skipped by install/sync
unless --optional (or --all) is passed unless --optional (or --all) is passed
Terminal Emulators kitty, wezterm — only matter if one of them is Terminal Emulators kitty, wezterm — only matter if one of them is
your actual terminal; skipped by `install`/`sync` your actual terminal; skipped by install/sync
unless --terminals (or --all) is passed unless --terminals (or --all) is passed
Integrations wakatime, tailscale Integrations wakatime, tailscale
@@ -1565,13 +1565,13 @@ functions). They are active in all interactive sessions.
Runs, lists, inspects, re-attaches to, and terminates named background Runs, lists, inspects, re-attaches to, and terminates named background
jobs using tmux or GNU screen as the process engine. Unlike bkg and jobs using tmux or GNU screen as the process engine. Unlike bkg and
detach, which discard output, a jobrunner job keeps a live terminal you detach, which discard output, a jobrunner job keeps a live terminal you
can return to later — it survives closing the shell, and `attach` can return to later — it survives closing the shell, and attach
restores it in any subsequent session. restores it in any subsequent session.
Run and manage named background jobs. Jobs are detached from the shell Run and manage named background jobs. Jobs are detached from the shell
and backed by tmux (preferred) or GNU screen. and backed by tmux (preferred) or GNU screen.
If the job name is omitted when starting a new job (e.g. `jobrunner sleep 1`), If the job name is omitted when starting a new job (e.g. jobrunner sleep 1),
a memorable, random name (like `sleepy-badger`) will be generated. a memorable, random name (like sleepy-badger) will be generated.
Exit Status: Exit Status:
0 Command succeeded, or no jobs are running 0 Command succeeded, or no jobs are running
@@ -1582,7 +1582,7 @@ functions). They are active in all interactive sessions.
Detach from an attached job with Ctrl-A then D; the job keeps running. Detach from an attached job with Ctrl-A then D; the job keeps running.
Commands are executed directly rather than through a shell, so pipes and Commands are executed directly rather than through a shell, so pipes and
redirections must be wrapped explicitly, e.g. redirections must be wrapped explicitly, e.g.
`jobrunner run sync fish -c 'a | b'`. jobrunner run sync fish -c 'a | b'.
Example: Example:
jobrunner run -n build make -j8 jobrunner run -n build make -j8
@@ -1893,7 +1893,7 @@ functions). They are active in all interactive sessions.
Notes: Notes:
The exit builtin is wired to smart_exit for interactive sessions. Typing The exit builtin is wired to smart_exit for interactive sessions. Typing
`exit` or Ctrl+D behaves identically to calling smart_exit directly. exit or Ctrl+D behaves identically to calling smart_exit directly.
Example: Example:
smart_exit smart_exit
@@ -2122,7 +2122,7 @@ functions). They are active in all interactive sessions.
scripts/cli-agent.md to $XDG_CONFIG_HOME/aichat/roles/cli.md. Inherits scripts/cli-agent.md to $XDG_CONFIG_HOME/aichat/roles/cli.md. Inherits
every aichat flag and tab completion (--wraps aichat); passing --role/-r every aichat flag and tab completion (--wraps aichat); passing --role/-r
overrides the default role, so qc forwards to aichat unchanged. The overrides the default role, so qc forwards to aichat unchanged. The
function is only defined when aichat is installed. Run `qc --help` for function is only defined when aichat is installed. Run qc --help for
aichat's full flag reference with the command name rewritten to qc. aichat's full flag reference with the command name rewritten to qc.
Arguments: Arguments:
@@ -2350,7 +2350,7 @@ functions). They are active in all interactive sessions.
in the default browser via xdg-open — deep links to a section aren't in the default browser via xdg-open — deep links to a section aren't
supported there, so if a keyword is given a note points you to the site's supported there, so if a keyword is given a note points you to the site's
search box instead. Pass --man / -m to open the compiled man page search box instead. Pass --man / -m to open the compiled man page
(docs/fish-config.1) via `man -l`; if a section keyword is given, the (docs/fish-config.1) via man -l; if a section keyword is given, the
pager opens at the nearest match. Pass --help or -h for usage and the pager opens at the nearest match. Pass --help or -h for usage and the
navigation key reference. navigation key reference.
@@ -2369,9 +2369,9 @@ functions). They are active in all interactive sessions.
Otherwise, the manual is shown via the resolved pager (not captured stdout). Otherwise, the manual is shown via the resolved pager (not captured stdout).
Notes: Notes:
The preferred invocation is `help config [...]` — this function is The preferred invocation is help config [...] — this function is
registered as a handler in the help wrapper so that syntax works registered as a handler in the help wrapper so that syntax works
transparently. Direct `config-help` calls are also valid. transparently. Direct config-help calls are also valid.
Example: Example:
config-help config-help
@@ -2476,7 +2476,7 @@ functions). They are active in all interactive sessions.
Pulls the latest fish shell configuration from the upstream repository Pulls the latest fish shell configuration from the upstream repository
into ~/.config/fish. Git output is suppressed; status is reported into ~/.config/fish. Git output is suppressed; status is reported
through colored messages. After a successful pull the function prints a through colored messages. After a successful pull the function prints a
short summary of changed files; run `exec fish` to reload the shell. short summary of changed files; run exec fish to reload the shell.
Arguments: Arguments:
-h, --help Show this help message and exit -h, --help Show this help message and exit
@@ -2570,11 +2570,11 @@ functions). They are active in all interactive sessions.
Synopsis: kitty-logging [install | uninstall | status | dismiss] [-h] Synopsis: kitty-logging [install | uninstall | status | dismiss] [-h]
Manages the fish-config Kitty scrollback watcher that powers C5 logging. Manages the fish-config Kitty scrollback watcher that powers C5 logging.
`install` symlinks the canonical watcher into the Kitty config dir (so it install symlinks the canonical watcher into the Kitty config dir (so it
always tracks the source) and wires it into kitty.conf via a always tracks the source) and wires it into kitty.conf via a
sentinel-marked managed block, commenting out any conflicting active sentinel-marked managed block, commenting out any conflicting active
watcher line to avoid double-capture. `uninstall` reverses it. `status` watcher line to avoid double-capture. uninstall reverses it. status
reports wiring, installed watcher version, and C5 logging state. `dismiss` reports wiring, installed watcher version, and C5 logging state. dismiss
silences the per-session setup reminder. silences the per-session setup reminder.
Runtime capture stays governed by the C5 .logging_disabled sentinel, so Runtime capture stays governed by the C5 .logging_disabled sentinel, so
@@ -2654,9 +2654,9 @@ functions). They are active in all interactive sessions.
Generates a random, memorable string using a sequence of specified word Generates a random, memorable string using a sequence of specified word
categories and formatting modifiers. Words are pulled from curated categories and formatting modifiers. Words are pulled from curated
plain-text databases bundled in `data/words/`. plain-text databases bundled in data/words/.
Modifiers like `--separator` and `--case` are evaluated sequentially and Modifiers like --separator and --case are evaluated sequentially and
apply only to the components that follow them. apply only to the components that follow them.
Supported Components: Supported Components:
@@ -2674,7 +2674,7 @@ functions). They are active in all interactive sessions.
1 Unknown category or missing word list file 1 Unknown category or missing word list file
Notes: Notes:
Falls back to `random choice` if GNU `shuf` is missing, but `shuf` is Falls back to random choice if GNU shuf is missing, but shuf is
much faster for files with >1000 lines. much faster for files with >1000 lines.
Example: Example:
@@ -2706,7 +2706,7 @@ functions). They are active in all interactive sessions.
Synopsis: repo-open [-p|--print] [-r|--root] Synopsis: repo-open [-p|--print] [-r|--root]
repo-open --help repo-open --help
Opens the web page for the current repository's `origin` remote in a Opens the web page for the current repository's origin remote in a
browser (via open-url). Deep-links to the current branch when it exists browser (via open-url). Deep-links to the current branch when it exists
on the remote, falling back to the remote's default branch (main/master) on the remote, falling back to the remote's default branch (main/master)
otherwise, and to the current sub-directory when invoked below the repo otherwise, and to the current sub-directory when invoked below the repo
@@ -2778,7 +2778,7 @@ functions). They are active in all interactive sessions.
# 6. DEPENDENCY CATALOG # 6. DEPENDENCY CATALOG
fish-deps manages these tools. Run `fish-deps` to check status, `fish-deps` manages these tools. Run `fish-deps` to check status,
`fish-deps install` to install missing Required/Recommended ones, or add `fish-deps install` to install missing Required/Recommended ones, or add
`--optional`, `--terminals`, or `--all` to also include the Optional and/or `--optional`, `--terminals`, or `--all` to also include the Optional and/or
Terminal Emulators tiers. Terminal Emulators tiers.
@@ -2797,9 +2797,9 @@ Terminal Emulators tiers.
| `cargo` | Rust toolchain (via rustup); used by `fish-deps` to install Rust-based tools and to build fish from source. All paths are gated on `type -q cargo` and degrade gracefully. | | `cargo` | Rust toolchain (via rustup); used by `fish-deps` to install Rust-based tools and to build fish from source. All paths are gated on `type -q cargo` and degrade gracefully. |
| `starship` | Cross-shell prompt; loaded via `type -q starship` guard. Without it the Catppuccin nim-style fallback prompt activates. | | `starship` | Cross-shell prompt; loaded via `type -q starship` guard. Without it the Catppuccin nim-style fallback prompt activates. |
| `uv` | Python package and project manager (Astral); used by the fish-from-source build path in `fish-deps`. All consumers degrade gracefully without it. | | `uv` | Python package and project manager (Astral); used by the fish-from-source build path in `fish-deps`. All consumers degrade gracefully without it. |
| `direnv` | Per-directory environment loading; integration is fully guarded with `type -q direnv`. Without it the direnv hook is simply not loaded and auto-venv activates normally. | | `direnv` | Per-directory environment loading; integration is fully guarded with `type -q direnv`. Without it the `direnv` hook is simply not loaded and auto-venv activates normally. |
| `paru` | AUR helper (Arch only; preferred); guarded throughout — non-Arch systems silently skip AUR-specific paths. | | `paru` | AUR helper (Arch only; preferred); guarded throughout — non-Arch systems silently skip AUR-specific paths. |
| `yay` | AUR helper (Arch only; fallback to paru); same guards apply. | | `yay` | AUR helper (Arch only; fallback to `paru`); same guards apply. |
| `eza` | Modern `ls` replacement | | `eza` | Modern `ls` replacement |
| `zoxide` | Smart cd with frecency | | `zoxide` | Smart cd with frecency |
| `lsd` | `ls` replacement (fallback to `eza`) | | `lsd` | `ls` replacement (fallback to `eza`) |
@@ -2820,7 +2820,7 @@ matter if you already use that specific tool. Skipped by
| `btop` | Modern resource monitor; backs the `top` wrapper (falls back to system `top`). | | `btop` | Modern resource monitor; backs the `top` wrapper (falls back to system `top`). |
| `dust` | Disk usage tree (Rust); one of two backends for the `du` wrapper (falls back to system `du`). | | `dust` | Disk usage tree (Rust); one of two backends for the `du` wrapper (falls back to system `du`). |
| `duf` | Disk usage/free overview; the other backend for the `du` wrapper (falls back to system `du`). | | `duf` | Disk usage/free overview; the other backend for the `du` wrapper (falls back to system `du`). |
| `prettyping` | Colorized ping wrapper; backs the `ping` wrapper (falls back to system `ping`). | | `prettyping` | Colorized `ping` wrapper; backs the `ping` wrapper (falls back to system `ping`). |
| `go` | Go toolchain; only used to install `ov` via `go install` (see below), which gets the latest release and doesn't depend on your distro packaging `ov`. Package name varies by distro (`go` on Arch/Homebrew, `golang`/`golang-go` on Debian/Fedora) — install manually if the listed package name doesn't resolve on your system. | | `go` | Go toolchain; only used to install `ov` via `go install` (see below), which gets the latest release and doesn't depend on your distro packaging `ov`. Package name varies by distro (`go` on Arch/Homebrew, `golang`/`golang-go` on Debian/Fedora) — install manually if the listed package name doesn't resolve on your system. |
| `lazygit` | Terminal git UI; only referenced by the `lg` abbreviation. | | `lazygit` | Terminal git UI; only referenced by the `lg` abbreviation. |
| `lazydocker` | Terminal docker UI; backs the `ld` wrapper. | | `lazydocker` | Terminal docker UI; backs the `ld` wrapper. |
@@ -2886,7 +2886,7 @@ 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 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. `~/.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 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 "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 removes any existing link. It only ever manages a symlink and never clobbers a
real file or directory at that path. real file or directory at that path.
@@ -2896,16 +2896,16 @@ real file or directory at that path.
$__fish_user_dots_path/secrets.fish $__fish_user_dots_path/secrets.fish
Store API tokens, GPG keys, private credentials here. This file is never Store API tokens, GPG keys, private credentials here. This file is never
committed. It is sourced by local.fish directly, not by config.fish. committed. It is sourced by `local.fish` directly, not by `config.fish`.
`local.fish` is sourced at the end of config.fish on every interactive `local.fish` is sourced at the end of `config.fish` on every interactive
session, so it and its companion secrets.fish can override anything set session, so it and its companion `secrets.fish` can override anything set
earlier. earlier.
## Overriding Configuration Variables ## Overriding Configuration Variables
Any variable set in local.fish after the main config loads takes effect. Any variable set in `local.fish` after the main config loads takes effect.
Example: to increase the scrollback history limit: Example: to increase the scrollback history limit:
# in local.fish # in local.fish
@@ -2914,9 +2914,9 @@ Example: to increase the scrollback history limit:
## Fish Universal Variables ## Fish Universal Variables
Some settings (fzf colors, theme) are stored in fish_variables via Some settings (`fzf` colors, theme) are stored in `fish_variables` via
`set -U`. These are machine-local and git-ignored. Do not commit `set -U`. These are machine-local and git-ignored. Do not commit
fish_variables. `fish_variables`.
## Opinionated Components (Minimal Mode) ## Opinionated Components (Minimal Mode)
@@ -2994,13 +2994,13 @@ Examples:
# (erase both to go back to full-flavor defaults) # (erase both to go back to full-flavor defaults)
For an interactive alternative to setting these variables by hand, run For an interactive alternative to setting these variables by hand, run
config-settings — a full-screen TUI that flips any category (including C5 `config-settings` — a full-screen TUI that flips any category (including C5
logging) on or off, per session or universally. See its entry in Section 5. logging) on or off, per session or universally. See its entry in Section 5.
NOTE: NOTE:
- Command shadows (rm, cat, ls, ...) react immediately; conf.d-level components (bindings, prompt, abbreviations, hooks) take effect in new shells. - Command shadows (rm, cat, ls, ...) react immediately; conf.d-level components (bindings, prompt, abbreviations, hooks) take effect in new shells.
- With aliases disabled, rm falls back to bare `command rm` — files are deleted permanently, not trashed. - With aliases disabled, rm falls back to bare `command rm` — files are deleted permanently, not trashed.
- Disabled integration commands (spwin, tab, split, hist, logs, upgrade) print an error naming the variable that disabled them. - 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. - On CachyOS, the distro fish config's own aliases, history override, and bang-bang bindings are stripped per category as well.
### Sub-categories ### Sub-categories
@@ -3011,7 +3011,7 @@ variable (e.g. `__fish_config_op_aliases_filesystem`). These follow the
exact same truthy/falsy/unset cascade one level deeper: an explicit exact same truthy/falsy/unset cascade one level deeper: an explicit
sub-category value overrides the master switch and the parent category's sub-category value overrides the master switch and the parent category's
setting, and an unset sub-category inherits from its parent category (which setting, and an unset sub-category inherits from its parent category (which
in turn inherits from `__fish_config_opinionated`). Run config-settings and in turn inherits from `__fish_config_opinionated`). Run `config-settings` and
press Enter on a category row to browse and toggle its sub-categories press Enter on a category row to browse and toggle its sub-categories
interactively. See Components Reference for the interactively. See Components Reference for the
full sub-category breakdown of every category. full sub-category breakdown of every category.
@@ -3021,11 +3021,11 @@ full sub-category breakdown of every category.
### Starship ### Starship
The primary prompt is Starship, initialized by conf.d/starship.fish. The primary prompt is Starship, initialized by `conf.d/starship.fish`.
Configure it via ~/.config/starship.toml. Configure it via `~/.config/starship.toml`.
conf.d/starship.fish defines a fish_prompt wrapper that only activates when `conf.d/starship.fish` defines a `fish_prompt` wrapper that only activates when
starship is in PATH and C3 overrides are enabled (see Opinionated `starship` is in PATH and C3 overrides are enabled (see Opinionated
Components above). It emits OSC 133;A (prompt start) immediately before Components above). It emits OSC 133;A (prompt start) immediately before
Starship renders and OSC 133;B (input start) immediately after, placing Starship renders and OSC 133;B (input start) immediately after, placing
both markers on the prompt line itself. This allows ov to use them as both markers on the prompt line itself. This allows ov to use them as
@@ -3037,7 +3037,7 @@ markers automatically.
### Catppuccin Fallback Prompt ### Catppuccin Fallback Prompt
When Starship is absent or C3 overrides are disabled, a built-in nim-style When Starship is absent or C3 overrides are disabled, a built-in nim-style
two-line prompt activates from functions/fish_prompt.fish. No external two-line prompt activates from `functions/fish_prompt.fish`. No external
dependencies — fish builtins only. dependencies — fish builtins only.
Layout (a dim job line appears between the two rows for each running Layout (a dim job line appears between the two rows for each running
@@ -3063,7 +3063,7 @@ Elements:
┬─ / ╰─> Connector lines: Catppuccin Green on success, ┬─ / ╰─> Connector lines: Catppuccin Green on success,
Red on failure Red on failure
The right prompt (fish_right_prompt.fish) always renders, independently of The right prompt (`fish_right_prompt.fish`) always renders, independently of
which left prompt is active: which left prompt is active:
Segment Shown when Segment Shown when
@@ -3090,8 +3090,8 @@ the exit-status prefix and timestamp ever appear:
### FZF ### FZF
FZF is themed to Catppuccin Mocha via FZF_DEFAULT_OPTS, set in FZF is themed to Catppuccin Mocha via `FZF_DEFAULT_OPTS`, set in
conf.d/theme.fish (opinionated; disabled by `__fish_config_op_overrides`, `conf.d/theme.fish` (opinionated; disabled by `__fish_config_op_overrides`,
see Opinionated Components above). The colors applied: see Opinionated Components above). The colors applied:
Hex Role Catppuccin name Hex Role Catppuccin name
@@ -3106,8 +3106,8 @@ see Opinionated Components above). The colors applied:
#F5E0DC Spinner / pointer Rosewater #F5E0DC Spinner / pointer Rosewater
#6C7086 Border Overlay0 #6C7086 Border Overlay0
To customize, override FZF_DEFAULT_OPTS in local.fish — it is sourced after To customize, override `FZF_DEFAULT_OPTS` in `local.fish` — it is sourced after
conf.d/theme.fish on every session, so a `set -Ux FZF_DEFAULT_OPTS ...` `conf.d/theme.fish` on every session, so a `set -Ux FZF_DEFAULT_OPTS ...`
there always wins. there always wins.
### Catppuccin Mocha Syntax Highlighting ### Catppuccin Mocha Syntax Highlighting
@@ -3115,7 +3115,7 @@ there always wins.
The Catppuccin Mocha theme ships with this config in themes/ and is applied The Catppuccin Mocha theme ships with this config in themes/ and is applied
automatically on first run via `conf.d/first_run.fish` (gated by automatically on first run via `conf.d/first_run.fish` (gated by
`__fish_config_op_autoexec`; see Opinionated Components above). Colors are `__fish_config_op_autoexec`; see Opinionated Components above). Colors are
stored in fish_variables (universal). Three other bundled variants are stored in `fish_variables` (universal). Three other bundled variants are
available in themes/ — Latte, Frappé, and Macchiato. To switch: available in themes/ — Latte, Frappé, and Macchiato. To switch:
fish_config theme choose "Catppuccin Latte" fish_config theme choose "Catppuccin Latte"
@@ -3212,7 +3212,7 @@ and the `help config` interception.
### dev-tools ### dev-tools
`claude` (AGENTS.md/CLAUDE.md auto-linking) and `edit` (multi-editor `claude` (`AGENTS.md/CLAUDE.md` auto-linking) and `edit` (multi-editor
launcher), plus `agy`. launcher), plus `agy`.
## C2 — Startup Side-Effects ## C2 — Startup Side-Effects
@@ -3233,20 +3233,20 @@ These run automatically without any user action. Disabling
user-dots symlink Every startup Links $__fish_config_dir/user-dots user-dots symlink Every startup Links $__fish_config_dir/user-dots
to $__fish_user_dots_path to $__fish_user_dots_path
When C2 is disabled: no Fisher install, no theme application, no paru/yay When C2 is disabled: no Fisher install, no theme application, no `paru`/`yay`
wrapper generation, no automatic venv activation, no WakaTime reporting, wrapper generation, no automatic venv activation, no WakaTime reporting,
no auto-pull (the PWD handler is never registered), and the user-dots 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 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. 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` 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 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 to stop generating it and remove any existing link — honoured even when C2 is
enabled. Managed by the `__fish_user_dots_link` helper. enabled. Managed by the `__fish_user_dots_link` helper.
The first-run completion marker (`__fish_config_first_run_complete`) is still The first-run completion marker (`__fish_config_first_run_complete`) is still
set so the init does not re-run on subsequent shells. set so the init does not re-run on subsequent shells.
Python venv activation fires on every directory change. If a directory uses Python venv activation fires on every directory change. If a directory uses
direnv (`.envrc` present), direnv takes priority and auto-venv is skipped for `direnv` (`.envrc` present), `direnv` takes priority and auto-venv is skipped for
that directory. that directory.
Auto-pull fast-forwards opted-in repositories in the background when you cd Auto-pull fast-forwards opted-in repositories in the background when you cd
@@ -3416,44 +3416,44 @@ NOTE: **Turning off logging does not delete any existing logs.**
They remain in `$SCROLLBACK_HISTORY_DIR` (defaults to: `~/.terminal_history/`) They remain in `$SCROLLBACK_HISTORY_DIR` (defaults to: `~/.terminal_history/`)
until you remove them manually. until you remove them manually.
The tmux capture starts automatically when fish launches inside any tmux The `tmux` capture starts automatically when fish launches inside any `tmux`
pane (`$TMUX` is set). It uses tmux's native pipe-pane to stream all pane pane (`$TMUX` is set). It uses `tmux`'s native pipe-pane to stream all pane
output directly to disk without an intermediate process. Each fish shell output directly to disk without an intermediate process. Each fish shell
session gets its own log file; a new log is created on each shell start session gets its own log file; a new log is created on each shell start
(including exec fish and new splits). Before each new log, the oldest (including exec fish and new splits). Before each new log, the oldest
`tmux_*.log` files are pruned (by modification time) to keep the total within `tmux_*.log` files are pruned (by modification time) to keep the total within
`SCROLLBACK_HISTORY_MAX_FILES`, matching the paru/yay wrapper behaviour. `SCROLLBACK_HISTORY_MAX_FILES`, matching the `paru`/`yay` wrapper behaviour.
The zellij capture works differently: Zellij has no live output-streaming The `zellij` capture works differently: Zellij has no live output-streaming
facility like pipe-pane, so the log is taken as a one-shot snapshot when the facility like pipe-pane, so the log is taken as a one-shot snapshot when the
shell exits, via `zellij action dump-screen --full --ansi` (the `--ansi` flag shell exits, via `zellij action dump-screen --full --ansi` (the `--ansi` flag
preserves color). The dump is captured on the fish process's stdout and preserves color). The dump is captured on the fish process's stdout and
written to the log file by fish itself (not via `--path`, which would make the written to the log file by fish itself (not via `--path`, which would make the
zellij server write the file). A fish_exit handler (registered whenever `zellij` server write the file). A `fish_exit` handler (registered whenever
`$ZELLIJ` is set) writes the pane's full scrollback and then prunes old `$ZELLIJ` is set) writes the pane's full scrollback and then prunes old
`zellij_*.log` files the same way. Because the capture happens at exit, toggling `zellij_*.log` files the same way. Because the capture happens at exit, toggling
`__fish_config_op_logging` takes effect on the next exit with no restart or `__fish_config_op_logging` takes effect on the next exit with no restart or
sentinel coordination needed — the C5 guard is re-checked when the handler sentinel coordination needed — the C5 guard is re-checked when the handler
fires. fires.
LIMITATION — zellij capture only fires on a clean shell exit (typing `exit`, LIMITATION — `zellij` capture only fires on a clean shell exit (typing `exit`,
Ctrl-D, or a logout), because that is when the fish_exit handler runs. It does `Ctrl-D`, or a logout), because that is when the `fish_exit` handler runs. It does
NOT capture when you close a pane or quit zellij through zellij itself: NOT capture when you close a pane or quit `zellij` through `zellij` itself:
- Closing a pane signals the shell and tears the pane down concurrently, so - Closing a pane signals the shell and tears the pane down concurrently, so
even if the handler runs, `dump-screen` may find the pane buffer already even if the handler runs, `dump-screen` may find the pane buffer already
gone. gone.
- Quitting zellij kills the zellij server, and `dump-screen` needs a live - Quitting `zellij` kills the `zellij` server, and `dump-screen` needs a live
server to read from — there is nothing left to snapshot. server to read from — there is nothing left to snapshot.
This is a structural difference from tmux, NOT a bug. tmux streams pane output This is a structural difference from `tmux`, NOT a bug. `tmux` streams pane output
to disk continuously via pipe-pane, so whatever was printed is already saved to disk continuously via pipe-pane, so whatever was printed is already saved
no matter how the pane dies. Zellij can only snapshot, and the only reliable no matter how the pane dies. Zellij can only snapshot, and the only reliable
snapshot point from the shell is a clean exit. To guarantee a zellij pane is snapshot point from the shell is a clean exit. To guarantee a `zellij` pane is
logged, end the session with `exit` or Ctrl-D rather than zellij's close-pane logged, end the session with `exit` or `Ctrl-D` rather than `zellij`'s close-pane
or quit actions. or quit actions.
The Kitty watcher is managed by the kitty-logging command: it symlinks the The Kitty watcher is managed by the `kitty-logging` command: it symlinks the
watcher (`fish-config-watcher.py`) into the Kitty config directory and wires it watcher (`fish-config-watcher.py`) into the Kitty config directory and wires it
into `kitty.conf` via a managed block. Inside Kitty, a non-blocking into `kitty.conf` via a managed block. Inside Kitty, a non-blocking
per-session reminder points first-time users at `kitty-logging install` until per-session reminder points first-time users at `kitty-logging install` until
@@ -3479,19 +3479,19 @@ Disabling `__fish_config_op_logging` (or leaving it unset):
bare `/usr/bin/paru` and `/usr/bin/yay` are used instead. bare `/usr/bin/paru` and `/usr/bin/yay` are used instead.
3. Kitty's `watcher.py` reads the sentinel on each save attempt and 3. Kitty's `watcher.py` reads the sentinel on each save attempt and
skips capture — no Kitty restart required. skips capture — no Kitty restart required.
4. smart_exit stops saving scrollback logs. 4. `smart_exit` stops saving scrollback logs.
5. Stops `tmux pipe-pane` capture in every open fish shell inside tmux. 5. Stops `tmux pipe-pane` capture in every open fish shell inside `tmux`.
Enabling `__fish_config_op_logging`: Enabling `__fish_config_op_logging`:
1. Removes the sentinel in every open shell. 1. Removes the sentinel in every open shell.
2. Regenerates paru/yay logging wrappers in `~/.local/bin/`. 2. Regenerates `paru`/`yay` logging wrappers in `~/.local/bin/`.
3. Kitty watcher resumes capture on the next session exit. 3. Kitty watcher resumes capture on the next session exit.
4. Restarts tmux pipe-pane capture in every open fish shell inside tmux. 4. Restarts `tmux` pipe-pane capture in every open fish shell inside `tmux`.
Changes propagate to all running shells through an event handler that fires Changes propagate to all running shells through an event handler that fires
whenever `__fish_config_op_logging` changes — no shell restart needed. whenever `__fish_config_op_logging` changes — no shell restart needed.
Note: C3 and C5 compose independently. C3 controls whether the smart_exit Note: C3 and C5 compose independently. C3 controls whether the `smart_exit`
wrapper is active at all; C5 controls only the scrollback-capture block 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. inside it. With C3 disabled, exit is plain builtin exit regardless of C5.
@@ -3508,7 +3508,7 @@ Kitty watcher scrollback capture, and `smart_exit`'s logging-guard path.
### multiplexer-capture ### multiplexer-capture
tmux `pipe-pane` and zellij `dump-screen` capture. `tmux` `pipe-pane` and `zellij` `dump-screen` capture.
### pkg-logs ### pkg-logs
@@ -3566,7 +3566,7 @@ commit them. Fisher installs and updates them automatically.
## Sponge History Filtering ## Sponge History Filtering
Sponge removes failed commands from history and, via conf.d/sponge_privacy.fish, Sponge removes failed commands from history and, via `conf.d/sponge_privacy.fish`,
also filters privacy-sensitive commands through three layers. Detection is also filters privacy-sensitive commands through three layers. Detection is
heuristic — pattern- and variable-name-based — so this reduces the risk of a heuristic — pattern- and variable-name-based — so this reduces the risk of a
credential landing in persistent history; it is not a guarantee that no credential landing in persistent history; it is not a guarantee that no
@@ -3586,14 +3586,14 @@ Commands matching any of these structural signatures are never recorded:
- `sshpass`, `docker login -p`, `openssl -passin/-passout` - `sshpass`, `docker login -p`, `openssl -passin/-passout`
Layer 2 — Dynamic secret values (session globals, refreshed each login): Layer 2 — Dynamic secret values (session globals, refreshed each login):
On the first prompt, after secrets.fish has loaded, the literal values of On the first prompt, after `secrets.fish` has loaded, the literal values of
all exported variables whose names suggest credentials (TOKEN, PASSWORD, all exported variables whose names suggest credentials (TOKEN, PASSWORD,
SECRET, API_KEY, etc.) are collected, regex-escaped, and added as a SECRET, `API_KEY`, etc.) are collected, regex-escaped, and added as a
session-scoped overlay. Because globals shadow universals in Fish, the session-scoped overlay. Because globals shadow universals in Fish, the
combined list is what sponge sees. Rotating a token takes effect on the combined list is what sponge sees. Rotating a token takes effect on the
next login automatically. next login automatically.
Layer 3 — Per-command filter (sponge_filter_secrets): Layer 3 — Per-command filter (`sponge_filter_secrets`):
Catches credentials in variables exported after login, such as tokens Catches credentials in variables exported after login, such as tokens
sourced from a project .env file mid-session. sourced from a project .env file mid-session.
@@ -3621,12 +3621,12 @@ their values), add name tokens — via `config-settings` → Sponge, or directly
set -U -a __fish_sponge_extra_sensitive ACME_API VAULT_PW set -U -a __fish_sponge_extra_sensitive ACME_API VAULT_PW
Tokens are folded into the Layer 2 name match case-insensitively as substrings, Tokens are folded into the Layer 2 name match case-insensitively as substrings,
so ACME_API also covers ACME_API_KEY. (The match uses `--entire` to return the so `ACME_API` also covers `ACME_API_KEY`. (The match uses `--entire` to return the
full variable name, so partial-name tokens dereference the right value.) full variable name, so partial-name tokens dereference the right value.)
The `config-settings` Sponge page also surfaces sponge's own tuning variables — The `config-settings` Sponge page also surfaces sponge's own tuning variables —
sponge_delay, sponge_successful_exit_codes, sponge_purge_only_on_exit, and `sponge_delay`, `sponge_successful_exit_codes`, `sponge_purge_only_on_exit`, and
sponge_allow_previously_successful — so they can be changed without typing `sponge_allow_previously_successful` — so they can be changed without typing
variable names. variable names.
## Bundled Plugin Functionality ## Bundled Plugin Functionality
@@ -3705,14 +3705,14 @@ Or use the interactive TUI — run `config-settings` and navigate to the
"Dots Path" row (last row). Press Enter to type a new path, or ← / h to "Dots Path" row (last row). Press Enter to type a new path, or ← / h to
reset to the default. reset to the default.
config.fish sources local.fish from that directory on every interactive `config.fish` sources `local.fish` from that directory on every interactive
session. local.fish is responsible for sourcing its own secrets.fish: session. `local.fish` is responsible for sourcing its own `secrets.fish`:
$__fish_user_dots_path/ $__fish_user_dots_path/
├── secrets.fish API keys, tokens, passwords, personal identifiers ├── secrets.fish API keys, tokens, passwords, personal identifiers
└── local.fish Machine-specific paths, env vars, and sourcing secrets └── local.fish Machine-specific paths, env vars, and sourcing secrets
fish_variables (auto-managed by fish) is excluded from this repo via `fish_variables` (auto-managed by fish) is excluded from this repo via
.gitignore. Do not commit it. .gitignore. Do not commit it.
## secrets.fish ## secrets.fish
@@ -3749,9 +3749,9 @@ wrong on any other system.
abbr -a dcr 'docker context use my-remote-server' abbr -a dcr 'docker context use my-remote-server'
abbr -a dcw 'docker context use work-server' abbr -a dcw 'docker context use work-server'
local.fish is sourced at the end of config.fish with an existence check so `local.fish` is sourced at the end of `config.fish` with an existence check so
the public config works cleanly on any machine without the private repo. the public config works cleanly on any machine without the private repo.
local.fish in turn sources secrets.fish when it exists. `local.fish` in turn sources `secrets.fish` when it exists.
--- ---
@@ -3823,7 +3823,7 @@ For other systems or building from source, see https://fishshell.com.
## Enable or Disable Session Logging ## Enable or Disable Session Logging
Session logging is opt-in: it is off until you turn it on. To enable all Session logging is opt-in: it is off until you turn it on. To enable all
logging and capture (scrollback, tmux/zellij pane logs, AUR helper wrappers, logging and capture (scrollback, `tmux`/`zellij` pane logs, AUR helper wrappers,
Kitty watcher): Kitty watcher):
set -U __fish_config_op_logging on set -U __fish_config_op_logging on
@@ -3843,12 +3843,12 @@ See C5 — Logging and Capture for the full component breakdown.
## Change or Disable the Greeting ## Change or Disable the Greeting
This config suppresses the distro greeting (e.g. CachyOS fastfetch) by This config suppresses the distro greeting (e.g. CachyOS `fastfetch`) by
default. To let the distro greeting through: default. To let the distro greeting through:
set -U __fish_config_op_greeting off set -U __fish_config_op_greeting off
To set a custom greeting, define fish_greeting in your local.fish: To set a custom greeting, define `fish_greeting` in your `local.fish`:
# in $__fish_user_dots_path/local.fish # in $__fish_user_dots_path/local.fish
function fish_greeting function fish_greeting
@@ -3868,7 +3868,7 @@ Machine-specific config goes in `$__fish_user_dots_path/local.fish` (defaults
to `~/.config/.user-dots/fish/local.fish`). Secrets go in `secrets.fish` in to `~/.config/.user-dots/fish/local.fish`). Secrets go in `secrets.fish` in
the same directory. the same directory.
If local.fish is not loading, verify the path: If `local.fish` is not loading, verify the path:
echo $__fish_user_dots_path echo $__fish_user_dots_path
test -f "$__fish_user_dots_path/local.fish"; and echo exists; or echo missing test -f "$__fish_user_dots_path/local.fish"; and echo exists; or echo missing
@@ -3900,7 +3900,7 @@ Fix: create a dedicated `conf.d/` file instead of appending to `config.fish`:
# ~/.config/fish/conf.d/mytool.fish # ~/.config/fish/conf.d/mytool.fish
mytool init fish | source mytool init fish | source
All existing integrations (starship, zoxide, direnv) already have `conf.d/` All existing integrations (`starship`, `zoxide`, `direnv`) already have `conf.d/`
files. See Return Sentinel for background. files. See Return Sentinel for background.
## Missing Dependencies ## Missing Dependencies
@@ -3937,7 +3937,7 @@ override it in `local.fish` (See Personalization):
fish_default_key_bindings fish_default_key_bindings
This restores Emacs-style bindings without disabling the rest of C3 This restores Emacs-style bindings without disabling the rest of C3
(bang-bang, autopair, starship prompt, pager settings, etc.). (bang-bang, autopair, `starship` prompt, pager settings, etc.).
To disable the entire C3 category (Vi mode and all other key/environment To disable the entire C3 category (Vi mode and all other key/environment
overrides): overrides):
@@ -4012,7 +4012,7 @@ its search box to jump straight to what you need.
help config --man help config --man
help config pkg --man help config pkg --man
Opens the compiled docs/fish-config.1 directly via man -l, bypassing Opens the compiled `docs/fish-config.1` directly via man `-l`, bypassing
the pager fallback chain. If a section keyword is given, the pager opens the pager fallback chain. If a section keyword is given, the pager opens
at the nearest matching heading. The symlink is created once on first at the nearest matching heading. The symlink is created once on first
run (like an install step) and MANPATH is set each session, enabling run (like an install step) and MANPATH is set each session, enabling
@@ -4020,7 +4020,7 @@ the standard invocation:
man fish-config man fish-config
NOTE: fish-config (hyphen) is this config's man page. fish_config NOTE: fish-config (hyphen) is this config's man page. `fish_config`
(underscore) is fish's built-in browser-based configuration tool — (underscore) is fish's built-in browser-based configuration tool —
a completely separate command. Do not mix them up. a completely separate command. Do not mix them up.
+51 -4
View File
@@ -1401,13 +1401,60 @@ def test_codespans_vocabulary_comes_from_the_deps_catalog():
assert "find" in vocab.full, "…but it still counts as a command-line opener" assert "find" in vocab.full, "…but it still counts as a command-line opener"
def test_codespans_is_site_only(): def test_codespans_leaves_indented_code_blocks_alone():
"""The concat (man page, config-help) keeps the plain-text form.""" """A four-space block is code, whatever it happens to contain.
The concat keeps the indented form pandoc wants, so unlike the site
this pass meets real indented blocks -- the table of contents among
them, which is nothing but a list of command names.
"""
body = "\n".join(
[
"Pick a viewer:",
"",
" 1. ov + bat section navigation",
" 2. less plain text with --jump",
"",
"Then run config-help.",
]
)
got = _spans(body).split("\n")
assert got[2] == " 1. ov + bat section navigation", got[2]
assert got[3] == " 2. less plain text with --jump", got[3]
assert got[5] == "Then run `config-help`.", "prose after the block was skipped"
def test_codespans_reach_the_man_page_pipeline():
"""Prose is marked identically wherever it is rendered.
`build_concat` runs the same pass `build_site` does, so a token the
site typesets as code is typeset as code in the man page and
`config-help` too, instead of only where the SSOT hand-wrote a
backtick.
"""
import build_manual
manual = Path(__file__).parent / "manual"
text = build_manual.build_concat(manual)
assert "`local.fish`" in text, "prose code spans never reached the concat"
assert "`tmux`" in text, "a vocabulary command was not wrapped in the concat"
def test_concat_section_five_stays_verbatim():
"""Section 5's entries are indented blocks, not prose.
They are generated from the `functions/*.fish` headers and pandoc sets
them verbatim, so a backtick there would be a literal character on the
page rather than markup.
"""
import build_manual import build_manual
text = build_manual.build_concat(Path(__file__).parent / "manual") text = build_manual.build_concat(Path(__file__).parent / "manual")
assert "-r/--resume" in text, "sanity: the bare flag-pair form is what's authored" body = text.split("\n# 5. ", 1)[1].split("\n# 6. ", 1)[0]
assert "`-r`/`--resume`" not in text, "code spans leaked into the man-page pipeline" offenders = [
line for line in body.split("\n") if line.startswith(" ") and "`" in line
]
assert not offenders, f"backticks inside verbatim entries: {offenders[:3]}"
TESTS = [v for k, v in sorted(globals().items()) if k.startswith("test_")] TESTS = [v for k, v in sorted(globals().items()) if k.startswith("test_")]