fix(config_help): index-based section lookup with normalized fallback
Replace fragile pattern/jump-target approach with a two-stage lookup: 1. fish-config.index maps keyword aliases to exact heading text so "keybindings" resolves to "# 3. KEY BINDINGS" without guessing. 2. Normalized scan fallback strips non-alphanumeric chars from both keyword and headings for unknown terms. Line numbers are resolved at runtime via grep -F so the index never goes stale from doc edits — only heading renames require updates. Also fix --section-delimiter: ov matches against logical (ANSI-stripped) text, so "^#" is correct for bat-colored output; the previous ANSI regex never matched, leaving the sections sidebar empty.
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
# Fish Config Help Index
|
||||
# Format: keyword=exact heading text as it appears in fish-config.md
|
||||
# Multiple keywords may map to the same heading.
|
||||
# Update this file whenever headings are added, removed, or renamed.
|
||||
# config_help uses this for fast exact lookups; unknown keywords fall back
|
||||
# to a normalized heading scan automatically.
|
||||
|
||||
# ── Top-level ─────────────────────────────────────────────────
|
||||
name=# NAME
|
||||
synopsis=# SYNOPSIS
|
||||
description=# DESCRIPTION
|
||||
toc=# TABLE OF CONTENTS
|
||||
contents=# TABLE OF CONTENTS
|
||||
|
||||
# ── Section 1: Configuration Variables ───────────────────────
|
||||
variables=# 1. CONFIGURATION VARIABLES
|
||||
config=# 1. CONFIGURATION VARIABLES
|
||||
xdg=## Environment Directories (XDG)
|
||||
toolhomes=## Tool Homes (XDG-compliant)
|
||||
editor=## Editor and Pager
|
||||
pager=## Editor and Pager
|
||||
scrollback=## Scrollback History
|
||||
|
||||
# ── Section 2: PATH ───────────────────────────────────────────
|
||||
path=# 2. PATH SETUP
|
||||
|
||||
# ── Section 3: Key Bindings ───────────────────────────────────
|
||||
keybindings=# 3. KEY BINDINGS
|
||||
bindings=# 3. KEY BINDINGS
|
||||
key-bindings=# 3. KEY BINDINGS
|
||||
keys=# 3. KEY BINDINGS
|
||||
fzf-bindings=## FZF Bindings (from fzf --fish integration)
|
||||
fzf=## FZF Bindings (from fzf --fish integration)
|
||||
|
||||
# ── Section 4: Abbreviations ──────────────────────────────────
|
||||
abbreviations=# 4. ABBREVIATIONS
|
||||
abbr=# 4. ABBREVIATIONS
|
||||
abbrs=# 4. ABBREVIATIONS
|
||||
editors-abbr=## 4.1 Editors
|
||||
nav=## 4.2 Navigation and Listing
|
||||
navigation=## 4.2 Navigation and Listing
|
||||
listing=## 4.2 Navigation and Listing
|
||||
git-abbr=## 4.3 Git
|
||||
terminal=## 4.4 Terminal Windows, Tabs, and Panes
|
||||
panes=## 4.4 Terminal Windows, Tabs, and Panes
|
||||
windows=## 4.4 Terminal Windows, Tabs, and Panes
|
||||
tabs=## 4.4 Terminal Windows, Tabs, and Panes
|
||||
chezmoi=## 4.5 Chezmoi
|
||||
docker=## 4.6 Docker
|
||||
systemctl=## 4.7 Systemctl
|
||||
systemd=## 4.7 Systemctl
|
||||
ai-abbr=## 4.8 AI Assistants
|
||||
history=## 4.9 History Expansion
|
||||
misc-abbr=## 4.10 Miscellaneous
|
||||
|
||||
# ── Section 5: Functions ──────────────────────────────────────
|
||||
functions=# 5. FUNCTIONS REFERENCE
|
||||
files=## 5.1 File and Directory
|
||||
cat=### cat
|
||||
copy=### copy
|
||||
du=### du
|
||||
dusize=### dusize
|
||||
ls=### ls
|
||||
lsr=### lsr
|
||||
lss=### lss
|
||||
lstree=### lstree
|
||||
lt=### lt
|
||||
ltr=### ltr
|
||||
lx=### lx
|
||||
mkdir=### mkdir
|
||||
mkcd=### mkcd
|
||||
poke=### poke
|
||||
rm=### rm
|
||||
scrub=### scrub
|
||||
nav-fns=## 5.2 Navigation
|
||||
cdi=### cdi
|
||||
clone=### clone
|
||||
clonet=### clonet
|
||||
editors=## 5.3 Editors and Viewers
|
||||
edit=### edit
|
||||
fc=### fc
|
||||
less=### less
|
||||
rawfish=### rawfish
|
||||
view=### view
|
||||
git=## 5.4 Git and Version Control
|
||||
branch=### branch
|
||||
gi=### gi
|
||||
gitignore=### gi
|
||||
git-clean=### git-clean
|
||||
gitup=### gitup
|
||||
gitui=### gitui
|
||||
hist=### hist
|
||||
pkg=### pkg
|
||||
package=### pkg
|
||||
package-manager=## 5.5 Package Management
|
||||
packages=## 5.5 Package Management
|
||||
search=### search
|
||||
upgrade=### upgrade
|
||||
cleanup=### cleanup
|
||||
parur=### parur
|
||||
deps=## 5.6 Dependency Management
|
||||
fish-deps=### fish-deps
|
||||
check-deps=### check_fish_deps
|
||||
system=## 5.7 System and Monitoring
|
||||
top=### top
|
||||
swapstat=### swapstat
|
||||
sbver=### sbver
|
||||
ports=### ports
|
||||
screensleep=### screensleep
|
||||
lock=### lock
|
||||
sudo-toggle=### sudo-toggle
|
||||
limine=### limine-edit
|
||||
terminal-mgmt=## 5.8 Terminal Management
|
||||
tab=### tab
|
||||
split=### split
|
||||
spwin=### spwin
|
||||
detach=### detach
|
||||
bkg=### bkg
|
||||
ssh=### ssh
|
||||
clipboard=## 5.9 Clipboard
|
||||
copy-fn=### y
|
||||
paste=### paste
|
||||
network=## 5.10 Network
|
||||
gip=### gip
|
||||
ping=### ping
|
||||
qr=### qr
|
||||
logging=## 5.11 Pager and Logging
|
||||
logs=### logs
|
||||
smart-exit=### smart_exit
|
||||
ai=## 5.12 AI and Developer Tools
|
||||
antigravity=### antigravity
|
||||
claude=### claude-resume
|
||||
claude-docs=### claude-docs
|
||||
claude-pr=### claude-pr
|
||||
code-resume=### code-resume
|
||||
superpowers=### superpowers
|
||||
media=## 5.13 Media and Utilities
|
||||
dng2avif=### dng2avif
|
||||
spark=### spark
|
||||
miscfns=## 5.14 Miscellaneous
|
||||
bash=### bash
|
||||
cheat=### cheat
|
||||
dockup=### dockup
|
||||
joplin=### joplin
|
||||
replay=### replay
|
||||
tmux=### tmux-clean
|
||||
wake-lock=### wake-lock
|
||||
zellij=### zellij
|
||||
|
||||
# ── Section 6: Dependency Catalog ────────────────────────────
|
||||
catalog=# 6. DEPENDENCY CATALOG
|
||||
deps-catalog=# 6. DEPENDENCY CATALOG
|
||||
required=## Required
|
||||
integrations=## Integrations
|
||||
recommended=## Recommended
|
||||
install-methods=## Install Methods
|
||||
|
||||
# ── Section 7: Customization ──────────────────────────────────
|
||||
customization=# 7. CUSTOMIZATION
|
||||
customize=# 7. CUSTOMIZATION
|
||||
local=## Machine-local Configuration
|
||||
secrets=## Secrets and API Keys
|
||||
overrides=## Overriding Configuration Variables
|
||||
universal=## Fish Universal Variables
|
||||
|
||||
# ── Section 8: Fisher Plugins ─────────────────────────────────
|
||||
plugins=# 8. FISHER PLUGINS
|
||||
fisher=# 8. FISHER PLUGINS
|
||||
|
||||
# ── Section 9: Viewing This Manual ───────────────────────────
|
||||
viewing=# 9. VIEWING THIS MANUAL
|
||||
manual=# 9. VIEWING THIS MANUAL
|
||||
ov=## With ov (recommended)
|
||||
man-page=## As a man page (if compiled)
|
||||
manpage=## As a man page (if compiled)
|
||||
jump=## Jumping to a section
|
||||
+48
-25
@@ -8,7 +8,8 @@
|
||||
# Opens the offline fish shell configuration manual in the best available
|
||||
# pager. Falls back through ov -> bat -> man -> less -> cat.
|
||||
# If a section keyword is provided, the pager opens at the first heading
|
||||
# that matches the keyword (case-insensitive).
|
||||
# that matches the keyword. Lookup order: docs/fish-config.index (exact
|
||||
# keyword aliases), then a normalized heading scan as fallback.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# section Optional keyword to jump to a matching section heading
|
||||
@@ -24,6 +25,7 @@
|
||||
# config_help fish-deps
|
||||
function config_help --description 'Open the offline fish shell configuration manual'
|
||||
set -l doc_file "$__fish_config_dir/docs/fish-config.md"
|
||||
set -l idx_file "$__fish_config_dir/docs/fish-config.index"
|
||||
set -l man_file "$__fish_config_dir/docs/fish-config.1"
|
||||
|
||||
if not test -f "$doc_file"
|
||||
@@ -33,26 +35,48 @@ function config_help --description 'Open the offline fish shell configuration ma
|
||||
return 1
|
||||
end
|
||||
|
||||
# ── Resolve section start line ───────────────────────────────
|
||||
# Normalize both sides: strip non-alphanumeric chars and lowercase.
|
||||
# This lets "keybindings" match "KEY BINDINGS", "fish-deps" match
|
||||
# "fish-deps", etc. without requiring exact punctuation or case.
|
||||
# ── Resolve section ──────────────────────────────────────────
|
||||
# 1. Look up keyword in fish-config.index (keyword → exact heading text).
|
||||
# 2. Fall back to normalized scan of heading lines if not in index.
|
||||
# 3. Resolve start_line via grep -F on the heading text (immune to line
|
||||
# number drift — only breaks if the heading itself is renamed).
|
||||
set -l start_line 1
|
||||
set -l found_text ""
|
||||
if test -n "$argv[1]"
|
||||
set -l norm_kw (string lower -- $argv[1] | string replace -ra '[^a-z0-9]' '')
|
||||
set -l found ""
|
||||
for entry in (grep -n "^#" "$doc_file")
|
||||
set -l parts (string split -m 1 ':' -- $entry)
|
||||
set -l lnum $parts[1]
|
||||
set -l text $parts[2]
|
||||
set -l norm_text (string lower -- $text | string replace -ra '[^a-z0-9]' '')
|
||||
if string match -q "*$norm_kw*" $norm_text
|
||||
set found $lnum
|
||||
break
|
||||
|
||||
# ── Index lookup ─────────────────────────────────────────
|
||||
if test -f "$idx_file"
|
||||
while read -l idxline
|
||||
string match -qr '^[[:space:]]*(#|$)' -- $idxline; and continue
|
||||
set -l kv (string split -m 1 '=' -- $idxline)
|
||||
test (count $kv) -lt 2; and continue
|
||||
set -l k (string lower -- $kv[1] | string replace -ra '[^a-z0-9]' '')
|
||||
if test "$k" = "$norm_kw"
|
||||
set found_text $kv[2]
|
||||
break
|
||||
end
|
||||
end < "$idx_file"
|
||||
end
|
||||
|
||||
# ── Normalized scan fallback ─────────────────────────────
|
||||
if test -z "$found_text"
|
||||
for entry in (grep -n "^#" "$doc_file")
|
||||
set -l parts (string split -m 1 ':' -- $entry)
|
||||
set -l text $parts[2]
|
||||
set -l norm_text (string lower -- $text | string replace -ra '[^a-z0-9]' '')
|
||||
if string match -q "*$norm_kw*" $norm_text
|
||||
set found_text $text
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if test -n "$found"
|
||||
set start_line $found
|
||||
|
||||
if test -n "$found_text"
|
||||
set -l lnum (grep -Fn "$found_text" "$doc_file" | cut -d: -f1 | head -1)
|
||||
if test -n "$lnum"
|
||||
set start_line $lnum
|
||||
end
|
||||
else
|
||||
set_color yellow
|
||||
echo "note: no section matching '$argv[1]' — opening at top" >&2
|
||||
@@ -61,17 +85,16 @@ function config_help --description 'Open the offline fish shell configuration ma
|
||||
end
|
||||
|
||||
# ── Viewer fallback chain ────────────────────────────────────
|
||||
# bat colors the output; ov matches headers via an ANSI-aware regex.
|
||||
# bat emits: ESC[<color>m# ... so delimiter ^(\x1b\[[0-9;]*m)+# matches
|
||||
# any 8/24-bit color sequence before a '#', theme-agnostic.
|
||||
# ov matches section-delimiter against logical (displayed) text, so "^#"
|
||||
# works on bat-colored output — no ANSI regex needed.
|
||||
# Section nav: Space (next), ^ (previous), Alt+u (section list sidebar).
|
||||
# psub creates a seekable temp file so --jump-target works on bat output.
|
||||
# --pattern uses the exact heading text for a precise one-line match.
|
||||
if type -q ov; and type -q bat
|
||||
set -l ov_args \
|
||||
--section-delimiter "^(\x1b\[[0-9;]*m)+#" \
|
||||
--section-delimiter "^#" \
|
||||
--section-header
|
||||
if test $start_line -gt 1
|
||||
set -a ov_args --jump-target $start_line
|
||||
if test -n "$found_text"
|
||||
set -a ov_args --pattern (string escape --style=regex -- $found_text)
|
||||
end
|
||||
ov $ov_args (bat --color=always --style=plain --language=markdown "$doc_file" | psub)
|
||||
|
||||
@@ -80,8 +103,8 @@ function config_help --description 'Open the offline fish shell configuration ma
|
||||
set -l ov_args \
|
||||
--section-delimiter "^#" \
|
||||
--section-header
|
||||
if test $start_line -gt 1
|
||||
set -a ov_args --jump-target $start_line
|
||||
if test -n "$found_text"
|
||||
set -a ov_args --pattern (string escape --style=regex -- $found_text)
|
||||
end
|
||||
ov $ov_args "$doc_file"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user