[インデックス 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のオートコンプリート機能に関する一般的な知識