[インデックス 12342] ファイルの概要
このコミットは、Go言語の公式ツールである go tool コマンドに対するZshシェル補完機能を追加するものです。これにより、Zshユーザーは go コマンドとそのサブコマンド、および関連するフラグや引数を入力する際に、より効率的に作業を進めることができるようになります。具体的には、go build, go test, go get などの主要なサブコマンドや、go tool の内部ツール(5g, 6g, 8g, 5l, 6l, 8l, dist など)に対する補完が提供されます。
コミット
- コミットハッシュ:
664481eb6b3e1237a6fcca590326203985a2db5c - 作者: Rémy Oudompheng oudomphe@phare.normalesup.org
- コミット日時: Sat Mar 3 00:12:40 2012 +0100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/664481eb6b3e1237a6fcca590326203985a2db5c
元コミット内容
misc: add zsh completion for go tool.
R=golang-dev, minux.ma, rsc
CC=golang-dev, remy
https://golang.org/cl/5699079
変更の背景
コマンドラインインターフェース(CLI)での作業効率は、開発者にとって非常に重要です。特に、頻繁に使用するコマンドや複雑なオプションを持つコマンドの場合、手動での入力は時間がかかり、タイプミスを誘発しやすくなります。シェル補完機能は、ユーザーがコマンドの一部を入力した際に、残りの部分や利用可能なオプション、引数などを自動的に提案することで、この問題を解決します。
Go言語の go tool は、ビルド、テスト、パッケージ管理、ドキュメント生成など、Go開発における多岐にわたるタスクを処理する中心的なコマンドです。このコマンドには多くのサブコマンドとフラグが存在するため、それらを手動で覚えるのは困難です。
このコミットは、Zshユーザーが go tool をより快適に、そして効率的に利用できるようにするために、Zshの強力な補完システムを活用して、go tool のサブコマンドやオプション、引数に対する自動補完機能を追加することを目的としています。これにより、開発者はコマンドの入力にかかる時間を削減し、より本質的な開発作業に集中できるようになります。
前提知識の解説
Zsh (Z Shell)
Zshは、Bourne Shell (sh) をベースにしたUnixシェルであり、BashやKshなどの他のシェルと同様に、コマンドラインインターフェースを提供します。Zshは、その強力なカスタマイズ性、豊富な機能、そして特に高度な補完システムで知られています。多くの開発者に愛用されており、macOSのデフォルトシェルとしても採用されています。
シェル補完 (Shell Completion)
シェル補完は、ユーザーがコマンドラインでコマンドやファイル名、オプションなどを入力する際に、Tabキーを押すことで、シェルが残りの部分を自動的に補完したり、利用可能な候補を一覧表示したりする機能です。これにより、入力の手間を省き、タイプミスを防ぎ、コマンドの利用方法を学習するのに役立ちます。
Zshの補完システム
Zshの補完システムは非常に強力で柔軟です。compinit 関数によって初期化され、compctl や _arguments、_values、_alternative などの組み込み関数や、ユーザー定義の補完関数 (_ で始まる関数名が慣例) を使用して、複雑な補完ルールを定義できます。
compctl: 特定のコマンドに対して補完関数を割り当てるために使用されます。_arguments: コマンドの引数やオプションに対する補完ルールを定義するための主要な関数です。オプションのショートハンド (-s) や、引数の説明 (:description:)、カスタム補完関数 (:arg:__my_func) などを指定できます。_values: 特定の固定値のリストから補完候補を生成するために使用されます。_alternative: 複数の補完方法を試行し、最初に成功したものを採用するために使用されます。例えば、ファイル名補完とカスタムリスト補完のどちらかを適用する場合などに使われます。_path_files: ファイルパスを補完するための組み込み関数です。
go tool コマンド
go tool は、Go言語のSDKに含まれるコマンドラインユーティリティです。go build, go test, go get など、Go開発者が日常的に使用する主要なコマンドを統合的に提供します。また、コンパイラ (5g, 6g, 8g) やリンカ (5l, 6l, 8l)、プロファイリングツール (vet) など、低レベルのツールを実行するためのインターフェースとしても機能します。
技術的詳細
このコミットで追加されたZsh補完スクリプト misc/zsh/go は、__go_tool_complete という名前の補完関数を定義し、それを go コマンドに compdef で関連付けています。
スクリプトの主要な部分は、__go_tool_complete 関数内にあります。この関数は、現在のコマンドラインの状態(どの引数を補完しようとしているかなど)に基づいて、適切な補完候補を生成します。
-
commands配列の定義:go toolの主要なサブコマンドとその簡単な説明がcommands配列に定義されています。これは、goコマンドの直後にサブコマンドを補完する際に使用されます。 -
build_flags配列の定義:go build,go install,go get,go testなど、ビルドに関連するサブコマンドで共通して使用されるフラグ(例:-a,-n,-x,-gcflagsなど)とその説明がbuild_flags配列に定義されています。 -
__go_list関数: このヘルパー関数は、go listコマンドを使用してGoのインポートパスを動的に取得し、補完候補として提供します。これにより、ユーザーがパッケージ名を正確に覚えていなくても、利用可能なパッケージを補完できるようになります。 -
case ${words[2]} in ... esacによるサブコマンドごとの補完ロジック:words[2]は、goコマンドの直後に入力されたサブコマンドを指します。このcaseステートメントは、選択されたサブコマンドに応じて異なる補完ルールを適用します。clean|doc:_arguments -s -w : '*:importpaths:__go_list'を使用して、インポートパスの補完を提供します。fix|fmt|list|vet:_alternativeを使用して、インポートパス (__go_list) または.goファイル (_path_files -g "*.go") のいずれかを補完候補として提供します。install:build_flagsに加えて、-vフラグとインポートパスの補完を提供します。get:build_flagsのみを補完します。build:build_flags、-v、-o(出力ファイル)、そしてインポートパスまたは.goファイルの補完を提供します。test:build_flagsに加えて、テスト固有の多くのフラグ(例:-c,-i,-v,-short,-parallel,-cpu,-run,-bench,-benchtime,-timeout,-cpuprofile,-memprofile,-memprofilerate)と、インポートパスまたは.goファイルの補完を提供します。help:go helpのサブコマンド(例:gopath,importpath,remoteなど)を補完します。run:build_flagsと.goファイルの補完を提供します。tool:go toolの内部ツール(例:5g,6g,8g,5l,6l,8l,distなど)に対する補完ロジックが含まれています。5g,6g,8g(コンパイラ): コンパイラ固有のフラグ(例:-I,-L,-S,-Vなど)と.goファイルの補完を提供します。5l,6l,8l(リンカ): リンカ固有のフラグ(例:-o,-Lなど)とオブジェクトファイル (*.a,*.o) の補完を提供します。dist:distツール固有のサブコマンド(例:banner,bootstrap,cleanなど)を補完します。
このスクリプトは、Zshの強力な補完フレームワークを効果的に利用し、go tool の複雑なコマンド構造に対応した、非常に詳細で使いやすい補完機能を実現しています。
コアとなるコードの変更箇所
diff --git a/misc/zsh/go b/misc/zsh/go
index f17763d93f..23afa96569 100644
--- a/misc/zsh/go
+++ b/misc/zsh/go
@@ -12,3 +12,140 @@ compctl -g "*.go" gofmt
# gccgo
compctl -g "*.go" gccgo
++
+# go tool
+__go_tool_complete() {
+ typeset -a commands build_flags
+ commands+=(\
+ 'build[compile packages and dependencies]'\
+ 'clean[remove object files]'\
+ 'doc[run godoc on package sources]'\
+ 'fix[run go tool fix on packages]'\
+ 'fmt[run gofmt on package sources]'\
+ 'get[download and install packages and dependencies]'\
+ 'help[display help]'\
+ 'install[compile and install packages and dependencies]'\
+ 'list[list packages]'\
+ 'run[compile and run Go program]'\
+ 'test[test packages]'\
+ 'tool[run specified go tool]'\
+ 'version[print Go version]'\
+ 'vet[run go tool vet on packages]'\
+ )
+ if (( CURRENT == 2 )); then
+ # explain go commands
+ _values 'go tool commands' ${commands[@]}
+ return
+ fi
+ build_flags=(\
+ '-a[force reinstallation of packages that are already up-to-date]'\
+ '-n[print the commands but do not run them]'\
+ "-p[number of parallel builds]:number"\
+ '-x[print the commands]'\
+ "-work[print temporary directory name and keep it]"\
+ "-gcflags[flags for 5g/6g/8g]:flags"\
+ "-ldflags[flags for 5l/6l/8l]:flags"\
+ "-gccgoflags[flags for gccgo]:flags"\
+ )
+ __go_list() {
+ local expl importpaths
+ declare -a importpaths
+ importpaths=($(go list ${words[$CURRENT]}... 2>/dev/null))\
+ _wanted importpaths expl 'import paths' compadd "$@" - "${importpaths[@]}"\
+ }\
+ case ${words[2]} in\
+ clean|doc)\
+ _arguments -s -w : '*:importpaths:__go_list'\
+ ;;\
+ fix|fmt|list|vet)\
+ _alternative ':importpaths:__go_list' ':files:_path_files -g "*.go"'\
+ ;;\
+ install)\
+ _arguments -s -w : ${build_flags[@]} \\\
+ "-v[show package names]" \\\
+ '*:importpaths:__go_list'\
+ ;;\
+ get)\
+ _arguments -s -w : \\\
+ ${build_flags[@]}\
+ ;;\
+ build)\
+ _arguments -s -w : \\\
+ ${build_flags[@]} \\\
+ "-v[show package names]" \\\
+ "-o[output file]:file:_files" \\\
+ "*:args:{ _alternative ':importpaths:__go_list' ':files:_path_files -g \"*.go\"' }"\
+ ;;\
+ test)\
+ _arguments -s -w : \\\
+ ${build_flags[@]} \\\
+ "-c[do not run, compile the test binary]" \\\
+ "-i[do not run, install dependencies]" \\\
+ "-v[print test output]" \\\
+ "-x[print the commands]" \\\
+ "-short[use short mode]" \\\
+ "-parallel[number of parallel tests]:number" \\\
+ "-cpu[values of GOMAXPROCS to use]:number list" \\\
+ "-run[run tests and examples matching regexp]:regexp" \\\
+ "-bench[run benchmarks matching regexp]:regexp" \\\
+ "-benchtime[run each benchmark during n seconds]:duration" \\\
+ "-timeout[kill test after that duration]:duration" \\\
+ "-cpuprofile[write CPU profile to file]:file:_files" \\\
+ "-memprofile[write heap profile to file]:file:_files" \\\
+ "-memprofilerate[set heap profiling rate]:number" \\\
+ "*:args:{ _alternative ':importpaths:__go_list' ':files:_path_files -g \"*.go\"' }"\
+ ;;\
+ help)\
+ _values "${commands[@]}" \\\
+ 'gopath[GOPATH environment variable]' \\\
+ 'importpath[description of import paths]' \\\
+ 'remote[remote import path syntax]'\
+ 'testflag[description of testing flags]'\
+ 'testfunc[description of testing functions]'\
+ ;;\
+ run)\
+ _arguments -s -w : \\\
+ ${build_flags[@]} \\\
+ '*:file:_path_files -g "*.go"'\
+ ;;\
+ tool)\
+ if (( CURRENT == 3 )); then\
+ _values "go tool" $(go tool)\
+ return\
+ fi\
+ case ${words[3]} in\
+ [568]g)\
+ _arguments -s -w : \\\
+ '-I[search for packages in DIR]:includes:_path_files -/' \\\
+ '-L[show full path in file:line prints]' \\\
+ '-S[print the assembly language]' \\\
+ '-V[print the compiler version]' \\\
+ '-e[no limit on number of errors printed]' \\\
+ '-h[panic on an error]' \\\
+ '-l[disable inlining]' \\\
+ '-m[print optimization decisions]' \\\
+ '-o[file specify output file]:file'\
+ '-p[assumed import path for this code]:importpath'\
+ '-u[disable package unsafe]'\
+ "*:file:_files -g '*.go'"\
+ ;;\
+ [568]l)\
+ local O=${words[3]%l}\
+ _arguments -s -w : \\\
+ '-o[file specify output file]:file'\
+ '-L[search for packages in DIR]:includes:_path_files -/' \\\
+ "*:file:_files -g '*.[ao$O]'"\
+ ;;\
+ dist)\
+ _values "dist tool" banner bootstrap clean env install version\
+ ;;\
+ *)\
+ # use files by default\
+ _files\
+ ;;\
+ esac\
+ ;;\
+ esac\
+}\
+\
+compdef __go_tool_complete go\
コアとなるコードの解説
このコミットは、misc/zsh/go という新しいファイルを追加しており、その内容はGoコマンドのZsh補完スクリプトです。
-
__go_tool_complete()関数定義: この関数がgoコマンドの補完ロジックの本体です。typeset -a commands build_flags:commandsとbuild_flagsという2つの配列を宣言しています。commands+=(\ ... ):goコマンドの主要なサブコマンド(build,clean,doc,fix,fmt,get,help,install,list,run,test,tool,version,vet)とその簡単な説明を定義しています。これらの説明は、補完候補が表示される際にユーザーに役立ちます。if (( CURRENT == 2 )); then ... fi: これは、ユーザーがgoと入力した直後(つまり、2番目の引数を補完しようとしている場合)に、上記のcommands配列の内容を補完候補として表示するためのロジックです。_values関数が使用され、サブコマンドのリストと説明が表示されます。build_flags=(\ ... ):go buildやgo testなど、ビルド関連のコマンドで共通して使用されるフラグ(例:-a,-n,-p,-x,-work,-gcflags,-ldflags,-gccgoflags)とその説明を定義しています。__go_list()関数:- このネストされた関数は、
go listコマンドを実行してGoのインポートパスを動的に取得し、補完候補として提供します。これにより、ユーザーは既存のGoパッケージを簡単に補完できます。2>/dev/nullはエラー出力を抑制しています。 _wantedはZshの補完システムの一部で、補完候補を整形して表示するために使われます。
- このネストされた関数は、
case ${words[2]} in ... esac: これは、ユーザーが入力したgoコマンドのサブコマンド(words[2]に格納される)に基づいて、異なる補完ロジックを適用するための主要な分岐点です。clean|doc:_argumentsを使用して、インポートパス (__go_list) の補完を提供します。fix|fmt|list|vet:_alternativeを使用して、インポートパス (__go_list) または.goファイル (_path_files -g "*.go") のいずれかを補完候補として提供します。install:build_flagsに加えて、-v(詳細表示) フラグとインポートパスの補完を提供します。get:build_flagsのみを補完します。build:build_flags、-v、-o(出力ファイル)、そしてインポートパスまたは.goファイルの補完を提供します。test:build_flagsに加えて、テストに特化した多くのフラグ(-c,-i,-v,-x,-short,-parallel,-cpu,-run,-bench,-benchtime,-timeout,-cpuprofile,-memprofile,-memprofilerate)と、インポートパスまたは.goファイルの補完を提供します。help:go helpのサブコマンド(gopath,importpath,remote,testflag,testfunc)を補完します。run:build_flagsと.goファイルの補完を提供します。tool:go toolの内部ツールに対する補完ロジックです。if (( CURRENT == 3 )); then ... fi:go toolの直後(3番目の引数)に、利用可能な内部ツール(5g,6g,8g,5l,6l,8l,distなど)をgo toolコマンドの出力から動的に取得して補完します。case ${words[3]} in ... esac: 選択された内部ツールに応じて、さらに詳細な補完を提供します。[568]g)(コンパイラ): コンパイラ固有のフラグ(-I,-L,-S,-V,-e,-h,-l,-m,-o,-p,-u)と.goファイルの補完を提供します。[568]l)(リンカ): リンカ固有のフラグ(-o,-L)とオブジェクトファイル (*.a,*.o) の補完を提供します。dist):distツール固有のサブコマンド(banner,bootstrap,clean,env,install,version)を補完します。*): 上記のいずれにも該当しない場合は、デフォルトでファイル補完 (_files) を行います。
-
compdef __go_tool_complete go: この行は、定義した__go_tool_complete関数をgoコマンドの補完関数としてZshに登録します。これにより、Zshはgoコマンドが入力された際に、この関数を呼び出して補完候補を生成するようになります。
このスクリプト全体で、Zshの強力な補完機能が活用され、Go開発者が go コマンドをより効率的に使用できるようになっています。
関連リンク
参考にした情報源リンク
- Zsh Completion System - Zsh Documentation
- Go Command Documentation - pkg.go.dev
- Zsh: The Missing Guide - Shell Completion
- Go tool commands - golang.org (これは一般的な
goコマンドのドキュメントであり、go toolの内部ツールについては直接的な詳細が少ないですが、全体像を理解するのに役立ちます。) - Zsh compctl man page
- Zsh _arguments man page
- Zsh _values man page
- Zsh _alternative man page
- Zsh _path_files man page