[インデックス 13696] ファイルの概要
このコミットは、Go言語のVimプラグインにおけるオートコンプリート機能の改善と、godocコマンドの挙動に関する修正を目的としています。特に、$GOPATH変数の尊重、パッケージ名に含まれる特殊文字(ダッシュ、ドット、アンダースコア)の適切な処理、そして$GOROOT変数の決定方法の堅牢化に焦点を当てています。
コミット
commit 5e8de365dced2d35975361760c6df9e4357fd6b9
Author: Tobias Columbus <tobias.columbus@gmail.com>
Date: Tue Aug 28 03:59:16 2012 +0800
misc/vim: fix for autocompletion
Vim autocompletion respects the $GOPATH variable and does not
ignore dashes ('-'), dots ('.') and underscores ('_') like found
in many remote packages.
Environment variable $GOROOT is determined by calling
'go env GOROOT' instead of relying on the user's environment
variables.
Fixes #3876
Fixes #3882
R=golang-dev, franciscossouza, dsymonds, minux.ma
CC=golang-dev
https://golang.org/cl/6443151
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5e8de365dced2d35975361760c6df9e4357fd6b9
元コミット内容
Vimのオートコンプリート機能の修正。
Vimのオートコンプリートは$GOPATH変数を尊重し、多くのリモートパッケージに見られるようなダッシュ (-)、ドット (.)、アンダースコア (_) を無視しないように修正されました。
環境変数$GOROOTは、ユーザーの環境変数に依存するのではなく、go env GOROOTを呼び出すことによって決定されるようになりました。
Fixes #3876 Fixes #3882
変更の背景
このコミットが行われた背景には、Go言語のVimプラグインにおける既存のオートコンプリート機能の限界と、GOROOT環境変数の扱いの問題がありました。
$GOPATHの不完全なサポート: 以前のVimプラグインは、Goのパッケージを検索する際に$GOROOT下の標準ライブラリパスのみを考慮し、ユーザーが設定した$GOPATH内のワークスペースを適切に参照していませんでした。これにより、$GOPATHにインストールされたサードパーティ製パッケージやユーザー自身のプロジェクトのパッケージがオートコンプリートの候補として表示されないという問題がありました。- 特殊文字を含むパッケージ名の問題: 多くのリモートリポジトリやGoモジュールでは、パッケージ名にダッシュ (
-)、ドット (.)、アンダースコア (_) などの特殊文字が含まれることがあります。しかし、Vimプラグインのオートコンプリート機能がこれらの文字を適切に扱わず、オートコンプリートの候補から除外してしまうことがありました。これは、特にGitHubなどのバージョン管理システムから取得したパッケージで顕著な問題でした。 $GOROOTの決定の不安定性:GOROOTはGoのインストールディレクトリを示す重要な環境変数ですが、ユーザーの環境設定に依存している場合、設定ミスや環境の違いによってVimプラグインが正しいGOROOTを特定できない可能性がありました。go env GOROOTコマンドは、Goツールチェイン自体が認識しているGOROOTのパスを正確に返すため、このコマンドを使用することでより堅牢かつ正確なGOROOTの決定が可能になります。
これらの問題は、Go開発者がVimをIDEとして使用する際の生産性を著しく低下させるものであり、本コミットによってこれらの課題が解決されました。
前提知識の解説
このコミットを理解するためには、以下のGo言語およびVimに関する基本的な知識が必要です。
- Go言語の環境変数 (
GOROOT,GOPATH):GOROOT: Go言語のSDKがインストールされているルートディレクトリを指します。Goの標準ライブラリやツールチェインの実行ファイルなどがこのパス以下に配置されます。GOPATH: Goのワークスペースのルートディレクトリを指します。Go 1.11以降のGo Modulesの導入によりその重要性は薄れましたが、このコミットが作成された2012年当時は、サードパーティ製パッケージやユーザー自身のプロジェクトのソースコード、コンパイル済みバイナリ、パッケージアーカイブなどがこのパス以下に配置される、Go開発における非常に重要な概念でした。GOPATHは複数のパスをコロン (:) で区切って指定することができ、Goツールはこれらのパスを順に検索してパッケージを見つけます。
- Vimのオートコンプリート機能:
- Vimには、コード補完を支援する機能が組み込まれています。Go言語のVimプラグインは、このVimの補完フレームワークを利用して、Goのパッケージ名や識別子を補完候補として提示します。
globpath(): Vimスクリプト関数で、指定されたパスパターンに一致するファイルやディレクトリのリストを返します。これは、特定のディレクトリ構造内でGoパッケージのアーカイブファイル(.aファイル)やディレクトリを検索するために使用されます。substitute(): Vimスクリプト関数で、文字列内のパターンを別の文字列に置換します。正規表現を使用できます。isdirectory(): Vimスクリプト関数で、指定されたパスがディレクトリであるかどうかを判定します。
- Goのパッケージ構造:
- Goのパッケージは、通常、
$GOROOT/pkg/<OS>_<ARCH>/または$GOPATH/pkg/<OS>_<ARCH>/以下にコンパイル済みのアーカイブファイル(.a拡張子)として配置されます。例えば、Linux 64bit環境であればlinux_amd64ディレクトリの下に置かれます。 - ソースコードは
$GOROOT/src/または$GOPATH/src/以下に配置されます。
- Goのパッケージは、通常、
go envコマンド:- Go 1.0から導入されたコマンドで、Goの環境変数の値を表示します。特に
go env GOROOTは、Goツールチェインが認識しているGOROOTの正確なパスを返します。これは、ユーザーが手動で設定した環境変数よりも信頼性が高い情報源となります。
- Go 1.0から導入されたコマンドで、Goの環境変数の値を表示します。特に
- Vimスクリプト:
- Vimの機能を拡張するために使用されるスクリプト言語です。このコミットで変更されているファイルはVimスクリプトで書かれています。
技術的詳細
このコミットは、主にmisc/vim/autoload/go/complete.vimとmisc/vim/plugin/godoc.vimの2つのVimスクリプトファイルを変更しています。
misc/vim/autoload/go/complete.vimの変更点
このファイルはGoパッケージのオートコンプリート機能を提供します。主な変更点は以下の通りです。
GOROOTの決定方法の変更:- 変更前は、単にVimの環境変数
$GOROOTを参照していました。 - 変更後は、まず
executable('go')でgoコマンドが実行可能かを確認します。 - 実行可能であれば、
system('go env GOROOT')コマンドを実行し、その出力からGOROOTのパスを取得します。これにより、Goツールチェイン自体が認識している正確なGOROOTパスを使用するようになります。 v:shell_error変数でコマンドの実行エラーをチェックし、エラーが発生した場合はメッセージを表示します。goコマンドが実行可能でない場合や、go env GOROOTが失敗した場合は、フォールバックとして引き続き$GOROOT環境変数を参照します。
- 変更前は、単にVimの環境変数
GOPATHのサポート追加:- 変更前は、
GOROOT下のパッケージのみを検索対象としていました。 - 変更後は、
$GOPATH環境変数をコロン (:) で分割し、複数のワークスペースパスを取得します。 - これらの
GOPATH内のワークスペースパスも、GOROOTと同様にパッケージ検索の対象ディレクトリリスト (dirs) に追加されます。
- 変更前は、
- パッケージ検索ロジックの改善:
- パッケージを検索するルートディレクトリが、単一の
GOROOTから、GOROOTとGOPATH内のすべてのワークスペースを含むdirsリストに変更されました。 for dir in dirsループが導入され、各ルートディレクトリに対してglobpath()関数を用いてパッケージを検索するようになりました。これにより、GOROOTとGOPATHの両方からパッケージが適切に補完候補として収集されるようになります。
- パッケージを検索するルートディレクトリが、単一の
misc/vim/plugin/godoc.vimの変更点
このファイルはVimからgodocコマンドを実行する機能を提供します。主な変更点は以下の通りです。
godoc検索ワードの正規表現の緩和:- 変更前は、
godocで検索するワードから[^a-zA-Z0-9\\/](英数字とスラッシュ以外の文字)を厳密に除去していました。 - 変更後は、
[^a-zA-Z0-9\\\\/._~-]という正規表現に変更され、ダッシュ (-)、ドット (.)、アンダースコア (_)、チルダ (~) も許容されるようになりました。これにより、これらの特殊文字を含むパッケージ名や識別子もgodocで正しく検索できるようになります。
- 変更前は、
これらの変更により、VimのGo開発環境は、より現代のGoエコシステム(特にGOPATHの利用や特殊文字を含むパッケージ名)に適合し、開発者の利便性が向上しました。
コアとなるコードの変更箇所
misc/vim/autoload/go/complete.vim
--- a/misc/vim/autoload/go/complete.vim
+++ b/misc/vim/autoload/go/complete.vim
@@ -29,21 +29,43 @@ if len(s:goarch) == 0
endif
function! go#complete#Package(ArgLead, CmdLine, CursorPos)
- let goroot = $GOROOT
- if len(goroot) == 0
- " should not occur.
- return []
+ let dirs = []
+
+ if executable('go')
+ let goroot = substitute(system('go env GOROOT'), '\n', '', 'g')
+ if v:shell_error
+ echo '\'go env GOROOT\' failed'
+ endif
+ else
+ let goroot = $GOROOT
endif
- let ret = {}
- let root = expand(goroot.'/pkg/'.s:goos.'_'.s:goarch)
- for i in split(globpath(root, a:ArgLead.'*'), "\n")
- if isdirectory(i)
- let i .= '/'
- elseif i !~ '\.a$'
- continue
- endif
- let i = substitute(substitute(i[len(root)+1:], '[\\]', '/', 'g'), '\.a$', '', 'g')
- let ret[i] = i
+
+ if len(goroot) != 0 && isdirectory(goroot)
+ let dirs += [ goroot ]
+ endif
+
+ let workspaces = split($GOPATH, ':')
+ if workspaces != []
+ let dirs += workspaces
+ endif
+
+ if len(dirs) == 0
+ " should not happen
+ return []
+ endif
+
+ let ret = {}
+ for dir in dirs
+ let root = expand(dir . '/pkg/' . s:goos . '_' . s:goarch)
+ for i in split(globpath(root, a:ArgLead.'*'), "\n")
+ if isdirectory(i)
+ let i .= '/'
+ elseif i !~ '\.a$'
+ continue
+ endif
+ let i = substitute(substitute(i[len(root)+1:], '[\\]', '/', 'g'), '\.a$', '', 'g')
+ let ret[i] = i
+ endfor
endfor
return sort(keys(ret))\n endfunction
misc/vim/plugin/godoc.vim
--- a/misc/vim/plugin/godoc.vim
+++ b/misc/vim/plugin/godoc.vim
@@ -72,7 +72,7 @@ function! s:Godoc(...)\n if !len(word)\n let word = expand('<cword>')\n endif\n- let word = substitute(word, '[^a-zA-Z0-9\\/]', '', 'g')
+ let word = substitute(word, '[^a-zA-Z0-9\\\\/._~-]', '', 'g')
if !len(word)\n return\n endif
コアとなるコードの解説
misc/vim/autoload/go/complete.vim
let dirs = []:- パッケージを検索するルートディレクトリのリストを初期化します。これにより、
GOROOTとGOPATHの両方のパスを柔軟に扱うことが可能になります。
- パッケージを検索するルートディレクトリのリストを初期化します。これにより、
if executable('go') ... else ... endifブロック:- このブロックは
GOROOTのパスを決定するためのロジックです。 executable('go')でgoコマンドがシステム上で利用可能かを確認します。- もし利用可能であれば、
system('go env GOROOT')を実行してGoツールチェインが認識しているGOROOTのパスを取得します。substitute(..., '\n', '', 'g')は、system()コマンドの出力に含まれる改行文字を除去しています。 v:shell_errorは、直前のsystem()コマンドの実行が失敗したかどうかを示すVimの組み込み変数です。失敗した場合はエラーメッセージを表示します。goコマンドが利用できない場合や、go env GOROOTが失敗した場合は、従来の$GOROOT環境変数の値を使用します。これにより、goコマンドがパスにない環境でも最低限の機能が維持されます。
- このブロックは
if len(goroot) != 0 && isdirectory(goroot) ...:- 取得した
gorootパスが空でなく、かつ有効なディレクトリである場合に、そのパスをdirsリストに追加します。
- 取得した
let workspaces = split($GOPATH, ':') ...:$GOPATH環境変数の値をコロン (:) で分割し、複数のワークスペースパスを取得します。if workspaces != []で、GOPATHが設定されている場合にのみ、これらのワークスペースパスをdirsリストに追加します。これにより、GOPATHで指定されたすべてのワークスペースがパッケージ検索の対象となります。
for dir in dirs ... endfor:- このループは、
dirsリストに含まれる各ルートディレクトリ(GOROOTとGOPATH内の各ワークスペース)に対して、パッケージの検索処理を実行します。 let root = expand(dir . '/pkg/' . s:goos . '_' . s:goarch): 各ルートディレクトリの下にある、現在のOSとアーキテクチャに対応するコンパイル済みパッケージのディレクトリパスを構築します。- 内側の
for i in split(globpath(root, a:ArgLead.'*'), "\n")ループは、指定されたrootディレクトリ内で、ユーザーが入力している部分文字列 (a:ArgLead) に一致するパッケージ(ディレクトリまたは.aファイル)を検索します。 if isdirectory(i) ... elseif i !~ '\.a$' ... endif: 検索結果がディレクトリであれば末尾にスラッシュを追加し、.aファイルでなければスキップします。let i = substitute(substitute(i[len(root)+1:], '[\\]', '/', 'g'), '\.a$', '', 'g'): 取得したパスからルートパスと.a拡張子を除去し、Windowsパスのバックスラッシュをスラッシュに変換して、純粋なパッケージ名を取得します。let ret[i] = i: 取得したパッケージ名をret辞書に追加します。辞書を使用することで重複するパッケージ名を自動的に排除できます。
- このループは、
return sort(keys(ret)):- 収集されたすべてのユニークなパッケージ名をソートして返します。これがVimのオートコンプリート候補として表示されます。
misc/vim/plugin/godoc.vim
let word = substitute(word, '[^a-zA-Z0-9\\\\/._~-]', '', 'g'):- この行は、
godocコマンドに渡す検索ワードをクリーンアップするための正規表現を変更しています。 - 変更前は
[^a-zA-Z0-9\\/]で、英数字とスラッシュ以外のすべての文字を除去していました。 - 変更後は
[^a-zA-Z0-9\\\\/._~-]となり、英数字、スラッシュに加えて、ドット (.)、アンダースコア (_)、チルダ (~)、そしてダッシュ (-) も許容されるようになりました。 - これにより、
github.com/user/repo-nameのようなパスや、my_packageのようなパッケージ名がgodocで正しく扱えるようになり、より多くのGoパッケージに対してgodoc機能が利用可能になります。
- この行は、
これらの変更は、Go開発者がVimをより効果的に使用できるようにするための重要な改善であり、Goエコシステムの進化に合わせて開発ツールの互換性を維持する上で不可欠でした。
関連リンク
- Go言語公式ウェブサイト: https://golang.org/
- Vim公式ウェブサイト: https://www.vim.org/
- Go Modules (Go 1.11以降のパッケージ管理): https://go.dev/blog/go-modules (このコミットの時点では存在しませんでしたが、
GOPATHの理解を深める上で関連します)
参考にした情報源リンク
- コミット情報:
commit_data/13696.txtの内容 - Go言語のドキュメント(
go envコマンド、GOPATH、GOROOTに関する情報) - Vimスクリプトのドキュメント(
globpath(),substitute(),isdirectory(),executable(),system(),v:shell_errorに関する情報) - GitHub上のGoリポジトリのコミット履歴
- Go言語のパッケージ管理に関する一般的な知識
- Vimのオートコンプリート機能に関する一般的な知識