bash-completionと自作シェルその後
Thu Mar 6 10:40:57 JST 2025 (modified: Thu Mar 6 12:27:36 JST 2025)
views: 2522, keywords:自作シェル, sush, 寿司シェル, bash-completion
前回、bash-completionが動いたと書いたんですが、当然「動いた」と「使える」は違うわけでいろいろ直していました。で、やっと自分で使ってまあこんなもんかなというところまできたのでまたメモを書いておきます。
gitの補完の謎
まずあのあと、gitの後のサブコマンド(addやbranchとかのアレ)の補完ができないかいろいろ調べていました。どのコマンドがどんなふうに補完されるかは、Bashではcompleteというコマンドで調査できます。次の例はLinuxのBashの例です。
### Bashの例 ###
$ complete | head -n 3
complete -F _longopt mv
complete -F _root_command gksudo
complete -F _command nice出力の読み方は、たとえば1行目については「mvは_longoptという関数をつかって補完候補を見つける」というふうに読みます。_longoptというのはコマンドのロングオプション(とファイル)を探す関数で、Bashがbash-completionを読み込んだときに一緒に読み込まれます。
ということは、gitの補完方法についてはcomplete | grep gitとすれば探せるはずですが、立ち上げたばかりのBashの場合、
### Bashの例 ###
$ complete | grep git
$ #何も出てこないというように空振ります。
じゃあどうやって補完しているんだという話になりますが、1回gitで補完をしてcompleteの出力を調べると、
### Bashの例 ###
$ git <tab> #←なにか補完を試みる(なんでもよい)
$ complete | grep git
complete -o bashdefault -o default -o nospace -F __git_wrap__gitk_main gitk
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main /usr/bin/git
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main gitというように、しれっとgitの項目ができているのがわかります。
補完機能の自動ロード
ということは自動で補完機能がロードされているということになります。で、どうやってということになるんですが、「デフォルトの補完機能」というものがあり、これを調べると手がかりになります。
### Bashの例 ###
$ complete | grep 'complete .* -D'
complete -F _comp_complete_load -Dこれは「補完対象に対応する補完機能が見当たらない場合、_comp_complete_loadで補完しろ」ということを意味します。で、_comp_complete_loadがなにかやってるなということになります。実際、コマンドに対応する機能をロードしているのはこの関数から呼ばれている_comp_loadです。_comp_loadのコードはここで読めます。めっちゃ長いですが。わたしは読みましたよ。読んだというか自分の作っているシェルに文法全部理解させましたよ。ええ。死ぬ。
ということで
自作シェルでもcomplete -Dの関数が呼ばれるようにして、このたびめでたくgitの補完ができるようになりました。やってることがまともではないので誰も褒めてくれませんが褒めて褒めて。
これでgitのサブコマンドの補完と、そのあとの補完がエラーなく動くようになりました #自作シェル pic.twitter.com/pNkgzxTt6U
— 上田隆一 (@ryuichiueda) February 26, 2025
ブランチの補完もうごきましたー🎉 #自作シェル pic.twitter.com/7vzBG6zWT8
— 上田隆一 (@ryuichiueda) February 26, 2025
_comp_complete_loadが呼ばれている様子です。
### 自作シェルの例 ###
$ sush
Rusty Bash (a.k.a. Sushi shell), version 1.0.4 - release
🍣 complete | grep git
🍣 git a #なんか補完してみる
add am archive apply
^C
🍣 complete | grep git
complete -F __git_wrap__gitk_main gitk
complete -F __git_wrap__git_main git #セットされている
#今後の課題: ほんとはもうひとつ読み込まれるはずだけど読み込まれていない#さらにその後
gitに気をとられてたらcdとかvimとかの補完がうまく動かなくなったことに気づいて直してました。いまは直したものが最新のリリースになっているので使ってみてissueに文句でも書いていただければ幸いです。
現場からは以上です。
ノート
Tweet