[インデックス 15945] ファイルの概要
このコミットは、Go言語のドキュメントツールであるgodoc
をVimエディタから利用するためのプラグインmisc/vim/plugin/godoc.vim
に対する改善です。具体的には、log.Print
のような「パッケージ名.関数名」形式の識別子に対して、VimのGodoc
コマンドが正しく動作するように修正されています。
コミット
commit d7434816c1a2407030f59837496a8dc86e6d1968
Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Date: Tue Mar 26 17:39:46 2013 +1100
misc/vim: make Godoc command work with "log.Print".
R=dsymonds
CC=golang-dev
https://golang.org/cl/7757043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d7434816c1a2407030f59837496a8dc86e6d1968
元コミット内容
このコミットは、Vimのgodoc.vim
プラグインにおいて、log.Print
のようにドットを含む識別子に対してGodoc
コマンドが期待通りに動作しない問題を修正します。以前は、log.Print
のような識別子に対してGodoc
コマンドを実行すると、log
またはPrint
のいずれか一方しか認識されず、log
パッケージ全体のドキュメントを表示したり、Print
という単独の識別子に対するドキュメントを検索したりすることができませんでした。この変更により、ドットを含む識別子全体を正しく認識し、パッケージのドキュメントを表示した上で、必要に応じてより詳細なフィードバックを提供するようになります。
変更の背景
Go言語では、標準ライブラリやサードパーティライブラリの関数や変数にアクセスする際に、パッケージ名.識別子名
という形式(例: fmt.Println
, log.Print
)が頻繁に用いられます。Vimのgodoc.vim
プラグインは、カーソル下の単語(cword
)に基づいてgodoc
コマンドを実行し、Goのドキュメントを表示する機能を提供していました。
しかし、Vimのデフォルトの「単語」の定義(iskeyword
オプション)では、ドット(.
)が単語の一部として扱われないことが一般的です。このため、log.Print
のような識別子にカーソルがある状態でGodoc
コマンドを実行すると、Vimはlog
またはPrint
のいずれか一方のみを単語として認識し、godoc log.Print
というコマンドを生成できませんでした。結果として、ユーザーはlog
パッケージ全体のドキュメントを見たい場合や、Print
関数の具体的なドキュメントを見たい場合に、期待する結果を得ることができませんでした。
このコミットは、このVimのiskeyword
設定と、godoc
コマンドへの引数の渡し方を調整することで、ユーザーがGo言語の慣用的なコードスタイルでドキュメントを効率的に参照できるようにすることを目的としています。
前提知識の解説
- Go言語の
godoc
コマンド:godoc
はGo言語に標準で付属するツールで、Goのソースコードからドキュメントを生成・表示します。パッケージ名(例:godoc fmt
)を指定するとそのパッケージのドキュメントを、パッケージ名.識別子名
(例:godoc fmt.Println
)を指定すると特定の関数や変数のドキュメントを表示できます。 - Vimの
iskeyword
オプション: Vimエディタにはiskeyword
というオプションがあり、これは「単語」を構成する文字の集合を定義します。例えば、デフォルトでは英数字やアンダースコアなどが含まれますが、ドット(.
)は通常含まれません。この設定は、w
(単語移動)や*
(カーソル下の単語を検索)などのコマンドの挙動に影響を与えます。 - Vimscriptの
expand('<cword>')
: Vimscriptの関数で、カーソル下の「単語」(iskeyword
の設定に基づく)を取得します。 - Vimscriptの
setlocal
: 現在のバッファ(ファイル)のみにオプションを設定するコマンドです。グローバルな設定を変更せずに一時的に挙動を変える際に使用されます。 - Vimscriptの
split()
関数: 文字列を指定した区切り文字で分割し、リスト(配列)として返します。 - Vimscriptの
search()
関数: 現在のバッファ内で指定されたパターンを検索します。
技術的詳細
このコミットの技術的な核心は、Vimのiskeyword
オプションの一時的な変更と、取得した単語の解析ロジックの改善にあります。
-
iskeyword
の一時的な変更:let oldiskeyword = &iskeyword
で現在のiskeyword
設定を保存します。setlocal iskeyword+=.
で、現在のバッファに限り、iskeyword
にドット(.
)を追加します。これにより、log.Print
のような文字列全体がexpand('<cword>')
によって一つの単語として認識されるようになります。let word = expand('<cword>')
で、ドットを含む単語全体を取得します。let &iskeyword = oldiskeyword
で、元のiskeyword
設定に戻します。これにより、他のVimの操作に影響を与えません。
-
単語の解析と
godoc
呼び出しのロジック:- 取得した
word
(例:log.Print
)をsplit(word, '\.')
でドットを区切り文字として分割し、words
というリスト(例:["log", "Print"]
)に格納します。 call s:GodocWord(words[0])
を呼び出し、まずリストの最初の要素(例:log
)に対してgodoc
を実行します。これにより、log
パッケージ全体のドキュメントが表示されます。これは、log.Print
のような呼び出しの場合、通常ユーザーが最初に知りたい情報がパッケージの概要であるためです。if len(words) > 1
の条件で、もし単語がドットで区切られた複数の部分からなる場合(例:log.Print
のように第二要素が存在する場合)の追加処理を行います。search('^\%(const\|var\|type\|\s\+\) ' . words[1] . '\s\+=\s')
とsearch('^func ' . words[1] . '(\')
というVimscriptのsearch
コマンドを使って、現在のファイル内でwords[1]
(例:Print
)がconst
、var
、type
、またはfunc
として宣言されているかを検索します。- この検索は、ユーザーが入力した
パッケージ名.識別子名
の識別子名
部分が、実は現在のファイル内で定義されているローカルな定数、変数、型、または関数である可能性を考慮しています。もしローカルで定義されていれば、それ以上の特別なドキュメント検索は不要と判断し、return
します。 - もしローカルな定義が見つからず、かつ
words
が複数の要素を持つ場合(つまり、godoc
が直接そのパッケージ名.識別子名
の形式でドキュメントを提供しない可能性のある、例えばメソッドや非公開の識別子である場合)、echo 'No documentation found for "' . word . '".'
というメッセージを表示します。これは、godoc
がパッケージレベルのドキュメントは提供したが、指定された完全な識別子に対する直接的なドキュメントは見つからなかったことをユーザーに伝えます。
- 取得した
この一連のロジックにより、log.Print
のようなケースでは、まずlog
パッケージのドキュメントが表示され、その上でPrint
がローカルな定義でなければ「ドキュメントが見つかりません」という補足メッセージが表示されるという挙動になります。
コアとなるコードの変更箇所
変更はmisc/vim/plugin/godoc.vim
ファイル内のs:Godoc
関数に集中しています。
--- a/misc/vim/plugin/godoc.vim
+++ b/misc/vim/plugin/godoc.vim
@@ -70,13 +70,26 @@ endfunction
function! s:Godoc(...)\
let word = join(a:000, ' ')\
if !len(word)\
+ let oldiskeyword = &iskeyword\
+ setlocal iskeyword+=.\
let word = expand('<cword>')\
+ let &iskeyword = oldiskeyword\
endif\
let word = substitute(word, '[^a-zA-Z0-9\\/._~-]', '', 'g')\
- if !len(word)\
+ let words = split(word, '\.')\
+ if !len(words)\
return\
endif\
- call s:GodocWord(word)\
+ call s:GodocWord(words[0])\
+ if len(words) > 1\
+ if search('^\%(const\\|var\\|type\\|\\s\\+\\) ' . words[1] . '\\s\\+=\\s')\
+ return\
+ endif\
+ if search('^func ' . words[1] . '(\')\
+ return\
+ endif\
+ echo 'No documentation found for "' . word . '".'\
+ endif\
endfunction\
\
command! -nargs=* -range -complete=customlist,go#complete#Package Godoc :call s:Godoc(<q-args>)
コアとなるコードの解説
if !len(word)
ブロック内:let oldiskeyword = &iskeyword
: 現在のiskeyword
設定をoldiskeyword
変数に保存します。setlocal iskeyword+=.
: 現在のVimバッファに対して、iskeyword
オプションにドット(.
)を追加します。これにより、expand('<cword>')
がlog.Print
のようなドットを含む単語全体を認識できるようになります。let word = expand('<cword>')
: カーソル下の単語を取得します。この時点でiskeyword
にドットが含まれているため、log.Print
全体が取得されます。let &iskeyword = oldiskeyword
:iskeyword
設定を元の値に戻し、他のVim操作への影響を避けます。
call s:GodocWord(word)
の変更:- 元の
call s:GodocWord(word)
が削除され、より複雑なロジックに置き換えられています。 let words = split(word, '\.')
: 取得した単語(例:log.Print
)をドットで分割し、words
リスト(例:["log", "Print"]
)に格納します。if !len(words)
: 分割結果が空の場合(単語が取得できなかった場合)は処理を終了します。call s:GodocWord(words[0])
: まず、分割された単語の最初の部分(例:log
)に対してs:GodocWord
を呼び出します。これにより、log
パッケージのドキュメントが表示されます。if len(words) > 1
ブロック:search('^\%(const\\|var\\|type\\|\\s\\+\\) ' . words[1] . '\\s\\+=\\s')
:words
の2番目の要素(例:Print
)が、現在のファイル内でconst
、var
、type
、または空白で始まる行で定義されているかを検索します。これは、Print
がローカルな定数、変数、または型である可能性をチェックします。search('^func ' . words[1] . '(\')
:words
の2番目の要素が、現在のファイル内でfunc
として定義されているかを検索します。これは、Print
がローカルな関数である可能性をチェックします。- 上記の
search
のいずれかが成功した場合、return
して処理を終了します。これは、ローカルな定義が見つかった場合、パッケージのドキュメント表示で十分と判断するためです。 - どちらの
search
も成功しなかった場合、echo 'No documentation found for "' . word . '".'
というメッセージを表示します。これは、godoc
が直接その完全な識別子に対するドキュメントを提供できない場合に、ユーザーにその旨を伝えるためのものです。
- 元の
関連リンク
- Go言語の
godoc
コマンドに関する公式ドキュメント: https://pkg.go.dev/cmd/godoc - Vimの
iskeyword
オプションに関するヘルプ::help 'iskeyword'
(Vim内で実行) - Vimscriptの
expand()
関数に関するヘルプ::help expand()
(Vim内で実行) - Vimscriptの
split()
関数に関するヘルプ::help split()
(Vim内で実行) - Vimscriptの
search()
関数に関するヘルプ::help search()
(Vim内で実行)
参考にした情報源リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Go言語のGerritコードレビューシステム (過去の変更履歴): https://go-review.googlesource.com/
- Vimのドキュメント (オンライン): https://vimhelp.org/
log
パッケージのドキュメント: https://pkg.go.dev/logfmt
パッケージのドキュメント: https://pkg.go.dev/fmt