NushellでCobraの入力補完を使える様にする
しばたです。
先日tenvを使ってみた記事を書きました。
tenvはGo言語製でCLIフレームワークのCobraを使っており、Cobraの標準機能で各種シェル上で入力補完が使える様になっているのですがNushellについては現状非対応のためひと工夫必要となります。
本記事ではその手法を解説します。
Cobraの入力補完
CobraはGo言語製ツールで広く使われているCLIフレームワークでtenv以外にもhugoをはじめ多くのツールで採用されています。
フレームワークの標準機能として入力補完が可能となっており、本日時点で
- Bash
- Zsh
- Fish
- PowerShell
に対応しています。
一応Nushellも追加対応させるPull Requestが出ているものの、なんやかんやあって中断された状態になっています。
Nushell側も当時からかなりの変更が入っているので、おそらくマージされることは無くこのままクローズされてしまうと思います。
NushellでCobraの入力補完を使える様にする
Cobraの入力補完の仕組み自体は割とシンプルで、
[コマンド] complete [対象シェル]
を入力すると各シェル用のスクリプトを生成し、これをシェルの起動時に仕込むことで実現しています。
生成されたスクリプトはデバッグ用コードが多く含まれており一見複雑ですが、コアとなる部分は以下の
[コマンド] __complete [入力中の文字列]
という部分でこの隠しコマンドが補完文字列を生成しています。
たとえばtenvでtenv tf t
まで入力したときの補完をしたい場合は
tenv __complete tf l
の様にすればOKです。
この場合
~> tenv __complete tf l
list List installed Terraform versions.
list-remote List installable Terraform versions.
:4
Completion ended with directive: ShellCompDirectiveNoFileComp
の様な出力となり、最初の3行は標準出力に補完文字列と処理の結果(戻り値)を、最後の行は標準エラー出力に処理結果のメッセージを表示しています。
このためNushellにおいては
tenv __complete tf l |
complete | get stdout | lines |
split column -r '\t' value description |
where not ($it.value starts-with ':')
といった形で整形してやることでNushellの補完機能で使える様になります。
# Nushellの入力補完に必要な情報だけをRecord型で出力してやる
~> tenv __complete tf l |
::: complete | get stdout | lines |
::: split column -r '\t' value description |
::: where not ($it.value starts-with ':')
╭───┬─────────────┬──────────────────────────────────────╮
│ # │ value │ description │
├───┼─────────────┼──────────────────────────────────────┤
│ 0 │ list │ List installed Terraform versions. │
│ 1 │ list-remote │ List installable Terraform versions. │
╰───┴─────────────┴──────────────────────────────────────╯
さらにこれをtenv以外のコマンドでも使える様にすると以下のクロージャーになります。
# Cobra製プログラム用のexternal completer
let cobra_completer = {|spans: list<string>|
let comp_cmd = $spans.0
let comp_value = $spans | skip 1
run-external $comp_cmd '__complete' ...$comp_value
| complete | get stdout | lines
| split column -r '\t' value description
| where not ($it.value starts-with ':')
}
このクロージャーをNushellのexeternal completerに組み込んでやれば無事入力補完が動作します。
# Cobra用completer
let cobra_completer = {|spans: list<string>|
let comp_cmd = $spans.0
let comp_value = $spans | skip 1
run-external $comp_cmd '__complete' ...$comp_value
| complete | get stdout | lines
| split column -r '\t' value description
| where not ($it.value starts-with ':')
}
# AWS CLI用completer
let aws_completer = {|spans: list<string>|
with-env {COMP_LINE: ($spans | str join ' ')} {
aws_completer
| $"value(char newline)" + $in
| from tsv --flexible --no-infer
}
}
# carapaceを呼び出すcompleter
let carapace_completer = {|spans: list<string>|
carapace $spans.0 nushell ...$spans | from json
}
let external_completer = {|spans: list<string>|
match $spans.0 {
aws => $aws_completer
tenv => $cobra_completer
ec2rdp => $cobra_completer
_ => $carapace_completer
} | do $in $spans
}
tenv以外に自作ツールのec2rdpもCobraを使っているので補完対象にしてみました。
結果はこんな感じです。
いい感じです。
自作ツールの方もバッチリ動作してくれました。
最後に
以上となります。
将来的にはNushellも標準で対応してくれるんじゃないかと期待しています。
それまでは本記事の方法で代替すると良いでしょう。