feat(config-help): add --html and --man flags; add config-update function
config-help gains two new flags: - --html / -w: opens docs/html/index.html in the default browser using smart browser detection (xdg-mime https scheme handler → known binaries → xdg-open fallback) to avoid MIME-type mismatches with non-browser apps - --man / -m: opens the compiled docs/fish-config.1 man page via man -l config-update is a new function that pulls the latest fish config from the hard-coded upstream URL without requiring a configured git remote. Suppresses git output and reports status with colored messages. Supports --dry-run and --force flags. README updated to document all new commands.
This commit is contained in:
@@ -328,13 +328,17 @@ A curated offline reference manual is available at `docs/fish-config.md`. It cov
|
||||
|---|---|
|
||||
| `help config` | Open the offline manual in the best available pager |
|
||||
| `help config <keyword>` | Jump directly to a section matching the keyword |
|
||||
| `config-help --html` | Open the pre-built HTML docs in the default browser |
|
||||
| `config-help --man` | Open the compiled man page via `man -l` |
|
||||
|
||||
The viewer falls back through: **ov** (syntax highlight + section navigation) → **bat** (syntax highlight) → **man -l** (pre-compiled man page) → **less** → **cat**.
|
||||
The pager viewer falls back through: **ov** (syntax highlight + section navigation) → **bat** (syntax highlight) → **man -l** (pre-compiled man page) → **less** → **cat**.
|
||||
|
||||
Examples: `help config keybindings` · `help config pkg` · `help config fish-deps` · `help config abbreviations`
|
||||
|
||||
> **Tip:** `help config` is the preferred way to access offline docs — it integrates naturally with fish's built-in `help` command. The underlying `config-help` function is still available directly if needed.
|
||||
|
||||
The `--html` flag opens `docs/html/index.html` in your default browser. It detects the correct browser by querying the system's `https://` scheme handler (via `xdg-mime`), falling back through known browser binaries, then `xdg-open` as a last resort. Set `$fish_help_browser` or `$BROWSER` to override.
|
||||
|
||||
You can also read the documentation as a standard man page — the symlink and `MANPATH` are set up automatically on shell start:
|
||||
|
||||
```fish
|
||||
@@ -345,6 +349,18 @@ The man page is auto-generated from `docs/fish-config.md` by the CI pipeline on
|
||||
|
||||
> **Note:** `fish-config` (hyphen) is this configuration's man page. `fish_config` (underscore) is fish's built-in browser-based configuration tool — a completely separate command. Don't mix them up.
|
||||
|
||||
### Updating the Config
|
||||
|
||||
Pull the latest changes from the upstream repository without needing a configured git remote:
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `config-update` | Fetch and apply the latest commits from upstream |
|
||||
| `config-update --dry-run` | Preview available changes without applying them |
|
||||
| `config-update --force` | Stash local changes, pull, then restore the stash |
|
||||
|
||||
The remote URL (`https://git.rootiest.dev/rootiest/fish-config.git`) is hard-coded, so `config-update` works even on a fresh clone with no `origin` set. All git output is suppressed; colored status messages report what changed. After a successful pull, reload the shell with `exec fish`.
|
||||
|
||||
### Dependency Management
|
||||
|
||||
`fish-deps` is a unified command for checking, installing, and updating all tools this config depends on.
|
||||
|
||||
+120
-9
@@ -3,6 +3,8 @@
|
||||
|
||||
# SYNOPSIS
|
||||
# config-help [section]
|
||||
# config-help --html
|
||||
# config-help --man
|
||||
# config-help --help
|
||||
#
|
||||
# DESCRIPTION
|
||||
@@ -12,24 +14,127 @@
|
||||
# that matches the keyword. Lookup order: docs/fish-config.index (exact
|
||||
# keyword aliases), then a normalized heading scan as fallback.
|
||||
# When opened with ov a sticky navigation hint is shown at the top of the
|
||||
# screen. Pass --help or -h to print usage and navigation key reference.
|
||||
# screen. Pass --html / -w to open the pre-built HTML version in the
|
||||
# default browser via xdg-open. Pass --man / -m to open the compiled
|
||||
# man page directly via man -l. Pass --help or -h for usage reference.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# section Optional keyword to jump to a matching section heading
|
||||
# --help Print usage and navigation reference, then exit
|
||||
# -h Alias for --help
|
||||
# section Optional keyword to jump to a matching section heading
|
||||
# -w, --html Open the offline HTML docs in the default browser
|
||||
# -m, --man Open the compiled man page via man -l
|
||||
# -h, --help Print usage and navigation reference, then exit
|
||||
#
|
||||
# RETURNS
|
||||
# 0 Manual displayed (or --help printed)
|
||||
# 1 Documentation file not found
|
||||
# 1 Documentation file not found, or required tool not available
|
||||
#
|
||||
# EXAMPLE
|
||||
# config-help
|
||||
# config-help keybindings
|
||||
# config-help pkg
|
||||
# config-help fish-deps
|
||||
# config-help --html
|
||||
# config-help --man
|
||||
# config-help --help
|
||||
function config-help --description 'Open the offline fish shell configuration manual'
|
||||
# ── --html / -w ──────────────────────────────────────────────
|
||||
if contains -- --html $argv; or contains -- -w $argv
|
||||
set -l html_file "$__fish_config_dir/docs/html/index.html"
|
||||
if not test -f "$html_file"
|
||||
set_color red
|
||||
echo "error: HTML docs not found at $html_file" >&2
|
||||
set_color normal
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l page_url "file://$html_file"
|
||||
|
||||
# Browser detection — mirrors fish's help.fish priority order but
|
||||
# resolves actual browser binaries before falling back to xdg-open.
|
||||
# xdg-open dispatches on the file's MIME type (text/html), which can
|
||||
# be associated with non-browser apps (e.g. ebook readers). Using a
|
||||
# real browser binary directly with a file:// URI avoids that lookup.
|
||||
set -l graphical_browsers \
|
||||
firefox firefox-esr chromium chromium-browser google-chrome \
|
||||
brave-browser vivaldi vivaldi-stable epiphany falkon qutebrowser \
|
||||
opera x-www-browser htmlview
|
||||
|
||||
set -l browser $fish_help_browser
|
||||
|
||||
if not set -q browser[1]
|
||||
if set -q BROWSER
|
||||
echo $BROWSER | read -at browser
|
||||
if not type -q $browser[1]
|
||||
set_color red
|
||||
echo "error: \$BROWSER '$browser[1]' is not a valid command" >&2
|
||||
set_color normal
|
||||
return 1
|
||||
end
|
||||
else
|
||||
# Resolve the https scheme handler from xdg-mime and use its
|
||||
# binary directly — most reliable on modern Linux desktops.
|
||||
if type -q xdg-mime
|
||||
set -l desk (xdg-mime query default x-scheme-handler/https 2>/dev/null)
|
||||
if test -n "$desk"
|
||||
set -l candidate (string replace -r '\.desktop$' '' -- $desk)
|
||||
if type -q $candidate
|
||||
set browser $candidate
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Fall back to trying known browser binaries in order.
|
||||
if not set -q browser[1]
|
||||
for b in $graphical_browsers
|
||||
if type -q -f $b
|
||||
set browser $b
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Last resort: xdg-open (may hit wrong app for local files).
|
||||
if not set -q browser[1]; and type -q xdg-open
|
||||
set browser xdg-open
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not set -q browser[1]
|
||||
set_color red
|
||||
echo "error: could not find a web browser — set \$fish_help_browser or \$BROWSER" >&2
|
||||
set_color normal
|
||||
return 1
|
||||
end
|
||||
|
||||
set_color green
|
||||
echo "Opening HTML docs in $browser[1]…"
|
||||
set_color normal
|
||||
|
||||
# Background the browser so it doesn't block the terminal.
|
||||
sh -c '("$@") &' -- $browser $page_url
|
||||
return 0
|
||||
end
|
||||
|
||||
# ── --man / -m ───────────────────────────────────────────────
|
||||
if contains -- --man $argv; or contains -- -m $argv
|
||||
set -l man_file "$__fish_config_dir/docs/fish-config.1"
|
||||
if not test -f "$man_file"
|
||||
set_color red
|
||||
echo "error: man page not found at $man_file" >&2
|
||||
set_color normal
|
||||
return 1
|
||||
end
|
||||
if not type -q man
|
||||
set_color red
|
||||
echo "error: man not found — cannot open man page" >&2
|
||||
set_color normal
|
||||
return 1
|
||||
end
|
||||
man -l "$man_file"
|
||||
return 0
|
||||
end
|
||||
|
||||
# ── --help / -h ──────────────────────────────────────────────
|
||||
if contains -- --help $argv; or contains -- -h $argv
|
||||
set_color --bold
|
||||
@@ -41,15 +146,19 @@ function config-help --description 'Open the offline fish shell configuration ma
|
||||
echo USAGE
|
||||
set_color normal
|
||||
echo " config-help "(set_color yellow)"[section]"(set_color normal)
|
||||
echo " config-help "(set_color yellow)"--html"(set_color normal)
|
||||
echo " config-help "(set_color yellow)"--man"(set_color normal)
|
||||
echo " config-help "(set_color yellow)"--help"(set_color normal)
|
||||
echo ""
|
||||
set_color --bold brblue
|
||||
echo ARGUMENTS
|
||||
set_color normal
|
||||
echo " "(set_color yellow)"section"(set_color normal)" Optional keyword to jump to a matching section heading."
|
||||
echo " Searches docs/fish-config.index for aliases first, then"
|
||||
echo " falls back to a normalized (case- and punctuation-insensitive)"
|
||||
echo " scan of heading lines."
|
||||
echo " "(set_color yellow)"section"(set_color normal)" Optional keyword to jump to a matching section heading."
|
||||
echo " Searches docs/fish-config.index for aliases first, then"
|
||||
echo " falls back to a normalized (case- and punctuation-insensitive)"
|
||||
echo " scan of heading lines."
|
||||
echo " "(set_color yellow)"-w, --html"(set_color normal)" Open the offline HTML docs in the default browser."
|
||||
echo " "(set_color yellow)"-m, --man"(set_color normal)" Open the compiled man page via man -l."
|
||||
echo ""
|
||||
set_color --bold brblue
|
||||
echo EXAMPLES
|
||||
@@ -59,6 +168,8 @@ function config-help --description 'Open the offline fish shell configuration ma
|
||||
echo " "(set_color green)"config-help pkg"(set_color normal)" jump to the pkg function entry"
|
||||
echo " "(set_color green)"config-help fish-deps"(set_color normal)" jump to fish-deps"
|
||||
echo " "(set_color green)"config-help abbreviations"(set_color normal)" jump to Abbreviations section"
|
||||
echo " "(set_color green)"config-help --html"(set_color normal)" open HTML docs in browser"
|
||||
echo " "(set_color green)"config-help --man"(set_color normal)" open compiled man page"
|
||||
echo ""
|
||||
set_color --bold brblue
|
||||
echo "NAVIGATION (ov pager)"
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# config-update [-h | --help] [-f | --force] [-n | --dry-run]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Pulls the latest fish shell configuration from the upstream repository
|
||||
# (https://git.rootiest.dev/rootiest/fish-config.git) into ~/.config/fish.
|
||||
# The remote URL is hard-coded so the update works even if the local clone
|
||||
# has no configured remote. Git output is suppressed; status is reported
|
||||
# through colored messages. After a successful pull the function prints a
|
||||
# short summary of changed files.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# -h, --help Show this help message and exit
|
||||
# -f, --force Stash local changes before pulling, then pop the stash
|
||||
# -n, --dry-run Check for upstream changes without applying them
|
||||
#
|
||||
# RETURNS
|
||||
# 0 Config updated (or already up to date)
|
||||
# 1 Update failed (network error, merge conflict, or not a git repo)
|
||||
#
|
||||
# EXAMPLE
|
||||
# config-update
|
||||
# config-update --dry-run
|
||||
# config-update --force
|
||||
function config-update --description 'Pull latest fish config from upstream'
|
||||
set -l c_head (set_color --bold cyan)
|
||||
set -l c_cmd (set_color --bold white)
|
||||
set -l c_flag (set_color yellow)
|
||||
set -l c_ok (set_color green)
|
||||
set -l c_warn (set_color yellow)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_dim (set_color brblack)
|
||||
set -l c_reset (set_color normal)
|
||||
|
||||
set -l REMOTE_URL https://git.rootiest.dev/rootiest/fish-config.git
|
||||
set -l CONFIG_DIR ~/.config/fish
|
||||
set -l opt_force 0
|
||||
set -l opt_dry 0
|
||||
|
||||
# ── parse flags ───────────────────────────────────────────────
|
||||
for arg in $argv
|
||||
switch $arg
|
||||
case -h --help
|
||||
echo "$c_head""Usage:$c_reset $c_cmd""config-update$c_reset $c_flag""[-h] [-f] [-n]$c_reset"
|
||||
echo
|
||||
echo " Pull the latest fish config from upstream and apply it locally."
|
||||
echo
|
||||
echo "$c_head""Options:$c_reset"
|
||||
echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show this help message"
|
||||
echo " $c_flag-f$c_reset, $c_flag--force$c_reset Stash local changes, pull, then restore stash"
|
||||
echo " $c_flag-n$c_reset, $c_flag--dry-run$c_reset Check for updates without applying them"
|
||||
echo
|
||||
echo "$c_head""Remote:$c_reset $c_dim""$REMOTE_URL$c_reset"
|
||||
return 0
|
||||
case -f --force
|
||||
set opt_force 1
|
||||
case -n --dry-run
|
||||
set opt_dry 1
|
||||
case '*'
|
||||
echo "$c_err""Unknown option: $arg$c_reset" >&2
|
||||
echo "Run $c_cmd""config-update --help$c_reset for usage." >&2
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
# ── verify config dir is a git repo ──────────────────────────
|
||||
if not test -d "$CONFIG_DIR/.git"
|
||||
echo "$c_err""Error:$c_reset $c_dim""$CONFIG_DIR$c_reset is not a git repository." >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
echo "$c_head""Fish Config Updater$c_reset"
|
||||
echo "$c_dim""Remote: $REMOTE_URL$c_reset"
|
||||
echo
|
||||
|
||||
# ── fetch upstream ────────────────────────────────────────────
|
||||
echo "$c_dim""→ Fetching upstream changes...$c_reset"
|
||||
if not git -C "$CONFIG_DIR" fetch "$REMOTE_URL" main:refs/remotes/_config_update/main 2>/dev/null
|
||||
echo "$c_err""Error:$c_reset Could not reach upstream remote." >&2
|
||||
echo "$c_dim""Check your internet connection and try again.$c_reset" >&2
|
||||
git -C "$CONFIG_DIR" branch -D -r _config_update/main 2>/dev/null 1>/dev/null
|
||||
return 1
|
||||
end
|
||||
|
||||
# ── compare local HEAD to upstream ───────────────────────────
|
||||
set -l local_sha (git -C "$CONFIG_DIR" rev-parse HEAD 2>/dev/null)
|
||||
set -l remote_sha (git -C "$CONFIG_DIR" rev-parse _config_update/main 2>/dev/null)
|
||||
|
||||
if test "$local_sha" = "$remote_sha"
|
||||
echo "$c_ok""✓ Already up to date.$c_reset"
|
||||
git -C "$CONFIG_DIR" branch -D -r _config_update/main 2>/dev/null 1>/dev/null
|
||||
return 0
|
||||
end
|
||||
|
||||
# ── count incoming commits ────────────────────────────────────
|
||||
set -l ahead (git -C "$CONFIG_DIR" rev-list HEAD.._config_update/main 2>/dev/null | count)
|
||||
echo "$c_ok""$ahead new commit(s) available upstream.$c_reset"
|
||||
|
||||
# ── list changed files (preview) ─────────────────────────────
|
||||
set -l changed_files (git -C "$CONFIG_DIR" diff --name-only HEAD _config_update/main 2>/dev/null)
|
||||
if test (count $changed_files) -gt 0
|
||||
echo
|
||||
echo "$c_head""Changed files:$c_reset"
|
||||
for f in $changed_files
|
||||
echo " $c_dim""·$c_reset $f"
|
||||
end
|
||||
end
|
||||
|
||||
# ── dry-run exits here ────────────────────────────────────────
|
||||
if test $opt_dry -eq 1
|
||||
echo
|
||||
echo "$c_warn""Dry run — no changes applied.$c_reset"
|
||||
git -C "$CONFIG_DIR" branch -D -r _config_update/main 2>/dev/null 1>/dev/null
|
||||
return 0
|
||||
end
|
||||
|
||||
echo
|
||||
|
||||
# ── check for local modifications ─────────────────────────────
|
||||
set -l dirty (git -C "$CONFIG_DIR" status --porcelain 2>/dev/null)
|
||||
if test -n "$dirty"
|
||||
if test $opt_force -eq 1
|
||||
echo "$c_warn""→ Stashing local changes...$c_reset"
|
||||
if not git -C "$CONFIG_DIR" stash push -m "config-update auto-stash" 2>/dev/null 1>/dev/null
|
||||
echo "$c_err""Error:$c_reset Could not stash local changes." >&2
|
||||
git -C "$CONFIG_DIR" branch -D -r _config_update/main 2>/dev/null 1>/dev/null
|
||||
return 1
|
||||
end
|
||||
else
|
||||
echo "$c_warn""Warning:$c_reset You have uncommitted local changes." >&2
|
||||
echo "$c_dim""Run with $c_flag--force$c_dim to stash them automatically,$c_reset" >&2
|
||||
echo "$c_dim""or commit/stash manually before updating.$c_reset" >&2
|
||||
git -C "$CONFIG_DIR" branch -D -r _config_update/main 2>/dev/null 1>/dev/null
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
# ── apply the update ──────────────────────────────────────────
|
||||
echo "$c_dim""→ Applying update...$c_reset"
|
||||
if not git -C "$CONFIG_DIR" merge --ff-only _config_update/main 2>/dev/null 1>/dev/null
|
||||
# ff-only failed — try a regular merge
|
||||
set -l merge_out (git -C "$CONFIG_DIR" merge _config_update/main 2>&1)
|
||||
if test $status -ne 0
|
||||
echo "$c_err""Error:$c_reset Merge failed — resolve conflicts manually." >&2
|
||||
echo "$c_dim""$merge_out$c_reset" >&2
|
||||
git -C "$CONFIG_DIR" branch -D -r _config_update/main 2>/dev/null 1>/dev/null
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
# ── restore stash if we created one ──────────────────────────
|
||||
if test $opt_force -eq 1 -a -n "$dirty"
|
||||
echo "$c_dim""→ Restoring stashed changes...$c_reset"
|
||||
if not git -C "$CONFIG_DIR" stash pop 2>/dev/null 1>/dev/null
|
||||
echo "$c_warn""Warning:$c_reset Stash pop had conflicts — resolve manually with $c_cmd""git stash pop$c_reset"
|
||||
end
|
||||
end
|
||||
|
||||
# ── success summary ───────────────────────────────────────────
|
||||
set -l new_sha (git -C "$CONFIG_DIR" rev-parse --short HEAD 2>/dev/null)
|
||||
echo "$c_ok""✓ Config updated to $new_sha ($ahead commit(s) applied).$c_reset"
|
||||
echo
|
||||
echo "$c_dim""Reload your shell or run $c_cmd""exec fish$c_dim to apply changes.$c_reset"
|
||||
|
||||
git -C "$CONFIG_DIR" branch -D -r _config_update/main 2>/dev/null 1>/dev/null
|
||||
return 0
|
||||
end
|
||||
Reference in New Issue
Block a user