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

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

このコミットは、VimエディタにおけるGo言語ファイルのファイルタイプ検出に関する問題を修正するものです。具体的には、Goファイルのファイルタイプが誤ってconf(設定ファイル)として検出されてしまうケースを解決します。

コミット

commit 41f4ba3ae53153d3de104d5f1af38109a83bc942
Author: Paul Sbarra <Sbarra.Paul@gmail.com>
Date:   Mon Dec 19 10:42:32 2011 +1100

    vim: fix go filetype detection
    
    The filetype needs to be set during BufRead in order for the did_filetype() check to prevent the file being detected as a conf file.  One example where this can occur is if a cgo file has a #include at the top of the file.  The # is detected in vim's generic configuration (conf file) toward the bottom of filetype.vim
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/5496066

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

https://github.com/golang/go/commit/41f4ba3ae53153d3de104d5f1af38109a83bc942

元コミット内容

VimのGo言語ファイルタイプ検出ロジックを修正し、BufReadPreイベントからBufReadイベントに切り替えることで、Goファイルが誤ってconfファイルとして検出される問題を解決します。特に、Cgoファイルのように先頭に#includeディレクティブを持つ場合にこの問題が発生していました。

変更の背景

Vimは、開かれたファイルのファイルタイプを自動的に検出する機能を持っています。この検出は、Vimの設定ファイル(通常はfiletype.vim)に記述されたルールに基づいて行われます。Go言語のファイルタイプ検出は、misc/vim/ftdetect/gofiletype.vimというファイルで行われていました。

問題は、Goファイル、特にCgo(GoとC言語を連携させるための機能)を使用しているファイルで発生していました。Cgoファイルでは、C言語のヘッダーファイルをインクルードするために、ファイルの先頭に#includeディレクティブを記述することがあります。Vimの一般的な設定ファイル(confファイル)のファイルタイプ検出ロジックは、ファイルの先頭にある#文字を検出して、そのファイルをconfファイルとして識別するルールを持っていました。

従来のgofiletype.vimでは、GoファイルのファイルタイプをBufReadPreイベント(ファイルが読み込まれる直前)で設定していました。しかし、このタイミングでは、Vimの内部的なdid_filetype()チェックがまだ完了しておらず、Vimが他の一般的なファイルタイプ検出ルール(この場合はconfファイルの検出ルール)を適用してしまう可能性がありました。結果として、#includeを持つGoファイルが、Goファイルとしてではなく、confファイルとして誤って認識され、Go言語特有のシンタックスハイライトやインデントが適用されないという問題が発生していました。

このコミットは、この誤検出を防ぎ、Goファイルが常に正しくGoファイルとして認識されるようにするために行われました。

前提知識の解説

  • Vim: 高機能なテキストエディタ。プログラマーに広く利用されており、カスタマイズ性が非常に高いことで知られています。
  • ファイルタイプ検出 (Filetype Detection): Vimの重要な機能の一つで、開かれたファイルの拡張子や内容に基づいて、そのファイルのプログラミング言語や形式を自動的に識別します。これにより、Vimは適切なシンタックスハイライト、インデント設定、およびその他の言語固有の機能を提供できます。
  • filetype.vim: Vimのファイルタイプ検出ルールが記述されている主要な設定ファイル。Vimは起動時にこのファイルを読み込み、ファイルタイプ検出のロジックを構築します。
  • au (autocmd): Vimの自動コマンドの略。特定のイベント(例: ファイルを開く、バッファを保存する)が発生したときに、指定されたコマンドを自動的に実行する機能です。
  • BufReadPre イベント: Vimの自動コマンドイベントの一つ。バッファ(ファイルの内容を一時的に保持するメモリ領域)がファイルから読み込まれる「直前」に発生します。
  • BufRead イベント: Vimの自動コマンドイベントの一つ。バッファがファイルから読み込まれた「直後」に発生します。
  • BufNewFile イベント: Vimの自動コマンドイベントの一つ。新しいファイルが作成される際に発生します。
  • set filetype=go: Vimのコマンドで、現在のバッファのファイルタイプをgoに設定します。
  • set fileencoding=utf-8: Vimのコマンドで、現在のバッファのファイルエンコーディングをUTF-8に設定します。
  • set fileencodings=utf-8: Vimのコマンドで、Vimがファイルを読み込む際に試行するエンコーディングのリストを設定します。この場合、UTF-8のみを試行します。
  • Cgo: Go言語の機能の一つで、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりすることを可能にします。Cgoを使用するGoファイルは、C言語のプリプロセッサディレクティブ(例: #include)を含むことがあります。
  • conf ファイルタイプ: Vimが認識する一般的な設定ファイルのファイルタイプ。多くの設定ファイルは、行の先頭に#でコメントアウトされた行を持つことが多いため、Vimのデフォルトのconfファイルタイプ検出ロジックは#文字をトリガーとすることがあります。
  • did_filetype(): Vimの内部関数またはフラグで、ファイルタイプが既に検出され、設定されたかどうかを示すものです。このチェックが完了していれば、Vimは他の一般的なファイルタイプ検出ルールを適用するのを停止します。

技術的詳細

このコミットの核心は、Vimの自動コマンドイベントのタイミング変更にあります。

Vimのファイルタイプ検出は、複数の段階とルールを経て行われます。一般的なルールはfiletype.vimに記述されており、特定の言語のファイルタイプ検出は、ftdetectディレクトリ内のスクリプト(例: gofiletype.vim)で行われます。

従来のgofiletype.vimでは、Goファイルのファイルタイプ設定にBufReadPreイベントを使用していました。このイベントは、ファイルの内容がバッファに読み込まれる直前に発生します。このタイミングでは、Vimはまだファイルの内容を完全に解析しておらず、また、ファイルタイプが既に設定されたかどうかを示す内部的なdid_filetype()チェックも完了していません。

そのため、Cgoファイルのように先頭に#includeディレクティブを持つGoファイルの場合、Vimはまず一般的なconfファイルタイプ検出ルールを適用しようとします。このルールは、ファイルの先頭にある#文字を検出すると、そのファイルをconfとして識別します。BufReadPreの段階では、Goファイルタイプが設定されていても、did_filetype()がまだtrueになっていないため、Vimはconfの検出ルールを適用し続けてしまい、結果としてconfファイルタイプが優先されてしまうことがありました。

このコミットでは、イベントをBufReadPreからBufReadに変更しています。BufReadイベントは、ファイルの内容がバッファに読み込まれた「直後」に発生します。このタイミングでは、Vimはファイルの内容を読み込み終えており、また、did_filetype()チェックも適切に機能するようになります。これにより、gofiletype.vimfiletype=goが設定された後、Vimはdid_filetype()trueであることを認識し、他の一般的なファイルタイプ検出ルール(confファイルの検出ルールなど)を適用するのを停止します。

結果として、#includeを持つCgoファイルであっても、VimはGoファイルとして正しく認識し、Go言語のシンタックスハイライトやその他の機能が適切に適用されるようになります。

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

変更はmisc/vim/ftdetect/gofiletype.vimファイルの一行のみです。

--- a/misc/vim/ftdetect/gofiletype.vim
+++ b/misc/vim/ftdetect/gofiletype.vim
@@ -1 +1 @@
-au BufReadPre,BufNewFile *.go set filetype=go fileencoding=utf-8 fileencodings=utf-8
+au BufRead,BufNewFile *.go set filetype=go fileencoding=utf-8 fileencodings=utf-8

コアとなるコードの解説

変更前:

au BufReadPre,BufNewFile *.go set filetype=go fileencoding=utf-8 fileencodings=utf-8

この行は、Go言語のファイル(.go拡張子を持つファイル)に対して自動コマンドを設定しています。

  • au: 自動コマンドを定義するVimコマンド。
  • BufReadPre: ファイルがバッファに読み込まれる直前にトリガーされるイベント。
  • BufNewFile: 新しいファイルが作成される際にトリガーされるイベント。
  • *.go: .go拡張子を持つすべてのファイルに適用されるパターン。
  • set filetype=go: ファイルタイプをgoに設定します。
  • fileencoding=utf-8: ファイルのエンコーディングをUTF-8に設定します。
  • fileencodings=utf-8: ファイルを読み込む際に試行するエンコーディングのリストをUTF-8のみに設定します。

変更後:

au BufRead,BufNewFile *.go set filetype=go fileencoding=utf-8 fileencodings=utf-8

変更点はBufReadPreBufReadに置き換えられた点のみです。

  • BufRead: ファイルがバッファに読み込まれた直後にトリガーされるイベント。

この変更により、Goファイルのファイルタイプ設定が、Vimが他の一般的なファイルタイプ検出ルールを適用する前に、より確実に完了するタイミングで行われるようになります。これにより、特に#includeディレクティブを持つCgoファイルで発生していた、Goファイルが誤ってconfファイルとして検出される問題が解決されます。

関連リンク

参考にした情報源リンク