Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17875] ファイルの概要

このコミットは、Go言語のVimプラグイン(misc/vim/ftplugin/go/fmt.vim)に新しい設定フラグ g:gofmt_command を追加するものです。これにより、Vimの :Fmt コマンドが使用する gofmt 実行可能ファイルのパスをユーザーがカスタマイズできるようになります。

コミット

commit c4f5421bc773f55be51097b9e29d70b68edb7f99
Author: David Crawshaw <david.crawshaw@zentus.com>
Date:   Tue Nov 12 09:28:07 2013 +1100

    misc/vim: add a gofmt_command flag for :Fmt

    R=dsymonds, dominik.honnef, n13m3y3r, rsc, kamil.kisiel
    CC=golang-dev
    https://golang.org/cl/22940044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/c4f5421bc773f55be51097b9e29d70b68edb7f99

元コミット内容

misc/vim: add a gofmt_command flag for :Fmt

変更の背景

Go言語の開発において、コードのフォーマットは gofmt ツールによって標準化されています。Vimエディタを使用するGo開発者は、通常、Go言語のVimプラグインが提供する :Fmt コマンドを使用して、現在開いているGoファイルのコードを gofmt で自動的にフォーマットします。

このコミットが導入される以前は、Vimプラグインは gofmt コマンドを直接呼び出していました。これは、gofmt がシステムのPATH環境変数に存在することを前提としていました。しかし、開発環境によっては、gofmt の実行可能ファイルが標準のPATHにない場合や、特定のバージョンの gofmt を使用したい場合、あるいは gofmt と互換性のある別のフォーマッタ(例: goimports など)を使用したい場合があります。

このような状況に対応するため、ユーザーが :Fmt コマンドによって呼び出されるフォーマッタを柔軟に指定できるようにする必要がありました。この変更は、Vimプラグインの使いやすさとカスタマイズ性を向上させることを目的としています。

前提知識の解説

Vimのftplugin (Filetype Plugin)

Vimには、特定のファイルタイプ(例: Go、Python、JavaScriptなど)に特化した設定やコマンドを自動的にロードする「ファイルタイププラグイン(ftplugin)」の仕組みがあります。misc/vim/ftplugin/go/fmt.vim は、Go言語のファイルを開いたときにロードされるVimスクリプトであり、Goコードのフォーマットに関連する機能を提供します。

Vimのグローバル変数 (g:) とバッファローカル変数 (b:)

Vimスクリプトでは、変数を定義して設定を管理します。

  • g: プレフィックスを持つ変数はグローバル変数であり、Vimセッション全体でアクセス可能です。ユーザーは ~/.vimrc などの設定ファイルでこれらの変数を設定することで、プラグインの挙動をカスタマイズできます。
  • b: プレフィックスを持つ変数はバッファローカル変数であり、特定のバッファ(開いているファイル)にのみ有効です。b:did_ftplugin_go_fmt のような変数は、ftpluginが既にロードされたかどうかを追跡するためによく使用されます。

Vimのコマンド定義 (command!)

Vimスクリプトでは、command! キーワードを使用して新しいユーザー定義コマンドを作成できます。

  • -buffer: このフラグは、定義されたコマンドが現在のバッファでのみ利用可能であることを示します。
  • Fmt: 定義されるコマンドの名前です。
  • call s:GoFormat(): コマンドが実行されたときに呼び出されるVimスクリプト関数です。s: プレフィックスは、その関数がスクリプトローカルであることを示します。

Vimの外部コマンド実行 (%!)

Vimでは、%! コマンドを使用して、現在のバッファ全体を外部コマンドの標準入力に渡し、そのコマンドの標準出力をバッファの内容で置き換えることができます。これは、外部ツール(この場合は gofmt)を使ってバッファの内容を処理し、その結果をVimに反映させるためによく使われる強力な機能です。

VimScriptの文字列連結と実行 (., execute)

VimScriptでは、. 演算子を使って文字列を連結できます。また、execute コマンドは、文字列として与えられたVimScriptコマンドを実行します。これにより、動的にコマンドを構築して実行することが可能になります。

技術的詳細

このコミットの主要な変更点は、gofmt コマンドの呼び出しをハードコードされた文字列から、ユーザーが設定可能な変数 g:gofmt_command を介したものに変更したことです。

  1. 新しいグローバル変数の導入: g:gofmt_command という新しいグローバル変数が導入されました。この変数は、gofmt 実行可能ファイルのパスまたはコマンド名を保持します。 デフォルト値は "gofmt" に設定されており、これは以前の挙動(PATHから gofmt を探す)と互換性があります。

    "   g:gofmt_command [default="gofmt"]
    "
    "       Flag naming the gofmt executable to use.
    "
    if !exists("g:gofmt_command")
        let g:gofmt_command = "gofmt"
    endif
    

    このコードブロックは、g:gofmt_command がまだ定義されていない場合にのみ、そのデフォルト値を設定します。これにより、ユーザーが ~/.vimrc などでこの変数を事前に設定している場合は、その値が尊重されます。

  2. s:GoFormat() 関数の変更: s:GoFormat() 関数内で gofmt を呼び出す部分が変更されました。

    変更前:

    silent %!gofmt
    

    これは、現在のバッファの内容を gofmt コマンドの標準入力に渡し、その出力をバッファに書き戻すことを意味します。

    変更後:

    silent execute "%!" . g:gofmt_command
    

    この変更により、gofmt という固定のコマンド名ではなく、g:gofmt_command 変数の値が使用されるようになりました。execute コマンドと文字列連結 (.) を組み合わせることで、Vimは g:gofmt_command の値(例: "gofmt""/usr/local/bin/goimports" など)を %! コマンドの一部として動的に実行します。

    例えば、ユーザーが let g:gofmt_command = "goimports" と設定した場合、Vimは silent %!goimports を実行するのと同じ効果を得ます。

この変更により、VimのGoプラグインはより柔軟になり、ユーザーは自分の開発環境や好みに合わせてフォーマッタを簡単に切り替えることができるようになりました。

コアとなるコードの変更箇所

misc/vim/ftplugin/go/fmt.vim ファイルの以下の部分が変更されました。

--- a/misc/vim/ftplugin/go/fmt.vim
+++ b/misc/vim/ftplugin/go/fmt.vim
@@ -18,15 +18,21 @@
 "
 "       Flag to indicate whether to enable the commands listed above.
 "
+"   g:gofmt_command [default="gofmt"]
+"
+"       Flag naming the gofmt executable to use.
+"
 if exists(\"b:did_ftplugin_go_fmt\")
     finish
 endif
 
-
 if !exists(\"g:go_fmt_commands\")
     let g:go_fmt_commands = 1
 endif
 
+if !exists(\"g:gofmt_command\")
+    let g:gofmt_command = \"gofmt\"
+endif
 
 if g:go_fmt_commands
     command! -buffer Fmt call s:GoFormat()
@@ -34,7 +40,7 @@ endif
 
 function! s:GoFormat()
     let view = winsaveview()
-    silent %!gofmt
+    silent execute \"%!\" . g:gofmt_command
     if v:shell_error
         let errors = []
         for line in getline(1, line('$'))

コアとなるコードの解説

  1. コメントの追加: g:gofmt_command 変数に関する新しいコメントが追加され、その目的とデフォルト値が説明されています。これは、プラグインのユーザーが新しい設定オプションを理解するのに役立ちます。

  2. g:gofmt_command のデフォルト値設定: if !exists("g:gofmt_command") ブロックが追加され、g:gofmt_command がまだ定義されていない場合に "gofmt" をデフォルト値として設定します。これにより、既存のユーザーは設定を変更することなく、以前と同じ挙動を維持できます。

  3. s:GoFormat() 関数内の gofmt 呼び出しの動的化: silent %!gofmt の行が silent execute "%!" . g:gofmt_command に変更されました。

    • "%!": これはVimの外部コマンド実行プレフィックスです。
    • . (ドット): VimScriptにおける文字列連結演算子です。
    • g:gofmt_command: ユーザーが設定した gofmt 実行可能ファイルのパスまたはコマンド名を含む変数です。
    • execute: 文字列として構築されたコマンドを実行します。

    この変更により、gofmt の呼び出しが静的なものから動的なものに変わり、ユーザーが g:gofmt_command を設定することで、任意のフォーマッタコマンドを実行できるようになりました。

関連リンク

  • Go言語の公式ウェブサイト: https://golang.org/
  • gofmt ツールに関するドキュメント: gofmt はGo言語の標準ツールであり、Goのインストールに含まれています。詳細なドキュメントは通常、Goの公式ドキュメントや go help fmt コマンドで確認できます。
  • Vimのドキュメント:
    • ftplugin: :help ftplugin
    • g:, b:: :help g: / :help b:
    • command!: :help :command
    • %!: :help :!
    • execute: :help :execute

参考にした情報源リンク