|
| 1 | +# 一个复杂的小 bug: cd 补全问题 |
| 2 | + |
| 3 | +如果你同时在使用 [fnm](https://github.com/Schniz/fnm),[bash-completion](https://github.com/scop/bash-completion), bash-it 的 [aliases.completion.bash](https://github.com/Bash-it/bash-it/blob/master/completion/available/aliases.completion.bash) 这三个工具,你会遇到一个 BUG。 |
| 4 | + |
| 5 | +## BUG 描述 |
| 6 | + |
| 7 | +使用 cd 按 Tab 补全路径时,每个路径都会额外加上一个空格。 |
| 8 | + |
| 9 | +比如 `cd /<Tab>` 然后选中 /usr,补全后变成 `cd /usr <光标位置>`。但正常期望的应该是 `cd /usr<光标位置>`。 |
| 10 | + |
| 11 | +## 复现问题 |
| 12 | + |
| 13 | +省略,懒得写。 |
| 14 | + |
| 15 | +## 排错关键 |
| 16 | + |
| 17 | +当同时使用 fnm, bash-completion, bash-it 的 aliases.completion.bash: |
| 18 | + |
| 19 | +```sh |
| 20 | +> complete -p cd |
| 21 | +complete -F _comp_complete_minimal cd |
| 22 | + |
| 23 | +> alias cd |
| 24 | +alias cd='__fnmcd' |
| 25 | + |
| 26 | +> complete -p __fnmcd |
| 27 | +complete -F _comp_complete_minimal __fnmcd |
| 28 | +``` |
| 29 | + |
| 30 | +当同时开启 bash-completion 和 bash-it 的 aliases.completion.bash,不使用 fnm: |
| 31 | + |
| 32 | +```sh |
| 33 | +> complete -p cd |
| 34 | +complete -o nospace -F _comp_cmd_cd cd |
| 35 | + |
| 36 | +> alias cd |
| 37 | +-bash: alias: cd: not found |
| 38 | + |
| 39 | +> complete -p __fnmcd |
| 40 | +-bash: complete: __fnmcd: no completion specification |
| 41 | +``` |
| 42 | + |
| 43 | +当同时开启 bash-completion 和 fnm,不使用 bash-it 的 aliases.completion.bash: |
| 44 | + |
| 45 | +```sh |
| 46 | +> complete -p cd |
| 47 | +-bash: complete: cd: no completion specification |
| 48 | + |
| 49 | +> alias cd |
| 50 | +alias cd='__fnmcd' |
| 51 | + |
| 52 | +> complete -p __fnmcd |
| 53 | +-bash: complete: __fnmcd: no completion specification |
| 54 | +``` |
| 55 | + |
| 56 | +当同时开启 bash-it 的 aliases.completion.bash 和 bash-completion, fnm,不使用 bash-completion: |
| 57 | + |
| 58 | +```sh |
| 59 | +> complete -p cd |
| 60 | +-bash: complete: cd: no completion specification |
| 61 | + |
| 62 | +> alias cd |
| 63 | +alias cd='__fnmcd' |
| 64 | + |
| 65 | +> complete -p __fnmcd |
| 66 | +-bash: complete: __fnmcd: no completion specification |
| 67 | +``` |
| 68 | + |
| 69 | +## 原因分析 |
| 70 | + |
| 71 | +根因不在 bash-completion 也不在 bash-it,而在于 fnm 的 `--use_on_cd` 参数。 |
| 72 | + |
| 73 | +fnm 的[初始化](https://github.com/Schniz/fnm#bash)这么写:`eval "$(fnm env --use-on-cd --shell bash)"` |
| 74 | + |
| 75 | +然而在 [`fn use_on_cd`](https://github.com/Schniz/fnm/blob/1a58394b53c918fa130e22116056f7b4f8e4997c/src/shell/bash.rs) 可以看到这段。 |
| 76 | + |
| 77 | +```sh |
| 78 | +__fnmcd() {{ |
| 79 | + \cd "$@" || return $? |
| 80 | + __fnm_use_if_file_found |
| 81 | +}} |
| 82 | + |
| 83 | +alias cd=__fnmcd |
| 84 | +__fnm_use_if_file_found |
| 85 | +``` |
| 86 | + |
| 87 | +`_comp_complete_minimal` 是 bash-completion 源码里定义的。 |
| 88 | + |
| 89 | +由于 `alias cd='__fnmcd'` 的存在,aliases.completion.bash 会把 cd 的补全函数用 __fnmcd 的补全函数代替。 |
| 90 | + |
| 91 | +而 aliases.completion.bash 也会给 __fnmcd 添加一个 `complete -F _comp_complete_minimal __fnmcd` |
| 92 | + |
| 93 | +这就导致了 `complete -F _comp_complete_minimal cd`。 |
| 94 | + |
| 95 | +## 解决办法 |
| 96 | + |
| 97 | +不要用 --use-on-cd 参数。这功能只是在 cd 目录时自动查找是否存在 .node-version 或 .nvmrc 文件,自动切换 node 版本用的。 |
| 98 | + |
| 99 | +`eval "$(fnm env --shell bash)"` |
0 commit comments