修复fish中hxc命令补全报错问题

问题现象

config.fish 中定义了如下 alias:

alias hxc='EDITOR=helix chezmoi edit'

使用 hxc 命令时按 Tab 键触发补全,会报错:

fish: Unknown command: __complete
/usr/share/fish/vendor_completions.d/chezmoi.fish (line 1):
CHEZMOI_ACTIVE_HELP=0 EDITOR=helix __complete chezmoi edit ''
                                   ^~~~~~~~~^
in command substitution
	called on line 25 of file /usr/share/fish/vendor_completions.d/chezmoi.fish
...

原因分析

fish 的 alias 命令其实是语法糖,会自动展开成一个带 --wraps 参数的 function

alias hxc='EDITOR=helix chezmoi edit'

等价于:

function hxc --wraps='EDITOR=helix chezmoi edit' --description 'alias hxc=EDITOR=helix chezmoi edit'
    EDITOR=helix chezmoi edit $argv
end

--wraps 的作用是告诉 fish:“这个函数应该复用某个命令的补全逻辑”。fish 会把 --wraps 的值整体当作一行命令去解析,取第一个词作为”真正的命令名”。

问题在于:--wraps 的值是 'EDITOR=helix chezmoi edit',第一个词被解析成了 EDITOR=helix(环境变量赋值),而不是 chezmoi

chezmoi 自带的补全脚本(/usr/share/fish/vendor_completions.d/chezmoi.fish)内部逻辑大致是:

set -l args (commandline -opc)
set -l requestComp "$args[1] __complete ..."

它假设 $args[1] 就是 chezmoi,但实际上因为 --wraps 解析错乱,chezmoi 变成了第二个词,最终拼出的命令变成:

EDITOR=helix __complete chezmoi edit ''

fish 把 EDITOR=helix 当作给下一条命令临时设置的环境变量(fish 3.4+ 支持这种写法),而实际执行的命令变成了单独的 __complete(缺少 chezmoi 前缀),这个命令不存在,于是报错 Unknown command: __complete

解决方法

alias 命令本身无法单独控制 --wraps 的内容,所以不要用 alias,改为直接手写 function,让 --wraps 只指向真正的命令 chezmoi edit

修改前:

alias hxc='EDITOR=helix chezmoi edit'

修改后:

function hxc --wraps='chezmoi edit' --description 'alias hxc=EDITOR=helix chezmoi edit'
    EDITOR=helix chezmoi edit $argv
end

这样:

  • --wraps='chezmoi edit' 让 fish 正确复用 chezmoi edit 的补全脚本
  • 函数体内 EDITOR=helix chezmoi edit $argv 依然正确设置了环境变量并执行命令

两者互不干扰,问题解决。

应用修改

编辑完 config.fish 后,记得让改动生效:

chezmoi apply
source ~/.config/fish/config.fish

或者用一步到位的方式编辑并应用:

chezmoi edit --apply ~/.config/fish/config.fish

之后再次尝试 hxc <Tab>,补全应正常工作,不再报错。

小结

项目说明
根本原因alias 自动生成的 --wraps 把整条命令(含环境变量赋值)当作补全目标解析,导致命令名错位
触发条件alias 内容中包含形如 VAR=value command 的环境变量前缀写法
解决方式改用 function ... --wraps='真正的命令',手动分离环境变量设置与 --wraps 目标