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

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

このコミットは、Go言語のVimプラグインにおけるgofmtのエラー表示方法の改善に関するものです。具体的には、gofmtの出力するエラーをVimのロケーションリスト(location list)ではなく、クイックフィックスリスト(quickfix list)に表示するように変更しています。これにより、gofmtが返すエラーがVimの標準的なエラー表示メカニズムにより適切に統合され、ユーザーエクスペリエンスが向上します。

コミット

commit ee261b75e1a31ab7056a897e1b65fba3568cf9ba
Author: David Symonds <dsymonds@golang.org>
Date:   Wed Nov 27 19:32:15 2013 +1100

    misc/vim: send Fmt errors to the quickfix list instead of the location list.
    
    Output from gofmt is a list of errors, so they should appear in the error list.
    
    R=adg
    CC=golang-dev
    https://golang.org/cl/33760043
---
 misc/vim/ftplugin/go/fmt.vim | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n
diff --git a/misc/vim/ftplugin/go/fmt.vim b/misc/vim/ftplugin/go/fmt.vim
index 5f7976f5f6..359545bd40 100644
--- a/misc/vim/ftplugin/go/fmt.vim
+++ b/misc/vim/ftplugin/go/fmt.vim
@@ -57,7 +57,7 @@ function! s:GoFormat()\
         endif
         undo
         if !empty(errors)\
-            call setloclist(0, errors, \'r\')
+            call setqflist(errors, \'r\')
         endif
         echohl Error | echomsg \"Gofmt returned error\" | echohl None
     endif

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

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

元コミット内容

misc/vim: send Fmt errors to the quickfix list instead of the location list.

Output from gofmt is a list of errors, so they should appear in the error list.

R=adg
CC=golang-dev
https://golang.org/cl/33760043

変更の背景

この変更の背景には、Vimにおけるエラー表示の慣習とgofmtの出力形式の整合性があります。

gofmtはGo言語のコードフォーマッタであり、コードの書式がGoの標準スタイルに準拠しているかをチェックし、必要に応じて自動修正を行います。しかし、書式に問題がある場合や、構文エラーなどによりフォーマットできない場合には、エラーメッセージを生成します。これらのエラーメッセージは、通常、ファイル名、行番号、エラー内容といった形式でリストとして出力されます。

Vimには、このようなエラーや警告のリストを扱うための二つの主要な機能があります。

  1. ロケーションリスト (Location List): これはVimの各ウィンドウに固有のリストであり、特定のファイルやバッファに関連する情報を表示するのに適しています。例えば、現在のファイル内での検索結果や、特定のLSP (Language Server Protocol) クライアントからの診断情報などがこれに該当します。
  2. クイックフィックスリスト (Quickfix List): これはVimセッション全体で共有されるグローバルなリストであり、コンパイルエラーやプロジェクト全体にわたる検索結果など、より広範なエラーや警告を扱うのに適しています。

元の実装では、gofmtのエラーがロケーションリストに送られていました。しかし、gofmtの出力は「エラーのリスト」であり、これはVimのクイックフィックスリストが本来扱うべき種類の情報です。クイックフィックスリストは、コンパイラのエラー出力のように、複数のファイルにまたがる可能性のあるエラー群を効率的にナビゲートするために設計されています。

この不整合を解消し、gofmtのエラーをVimのより適切なメカニズムで表示することで、ユーザーがエラーをより直感的に、かつ効率的に処理できるようになることが、この変更の主な動機です。

前提知識の解説

このコミットを理解するためには、以下のVimの機能とGo言語のツールに関する知識が必要です。

Vimのリスト機能: クイックフィックスリストとロケーションリスト

Vimには、ファイル内の特定の場所(エラー、警告、検索結果など)のリストを管理するための強力な機能が二つあります。

  • クイックフィックスリスト (Quickfix List):

    • スコープ: Vimセッション全体でグローバルに一つだけ存在します。
    • 用途: コンパイルエラー、リンターの警告、grepコマンドによるプロジェクト全体の検索結果など、複数のファイルにまたがる可能性のある、またはプロジェクト全体に影響するエラーや警告のリストを管理するのに適しています。
    • 操作: :copenでクイックフィックスウィンドウを開き、:cnext:cprevでリスト内を移動します。setqflist()関数を使ってプログラム的にリストの内容を設定できます。
    • 利点: プロジェクト全体のエラーを一元的に管理し、迅速に修正作業を進めることができます。
  • ロケーションリスト (Location List):

    • スコープ: 各Vimウィンドウに固有のリストです。つまり、複数のウィンドウを開いている場合、それぞれのウィンドウが独立したロケーションリストを持つことができます。
    • 用途: 現在のバッファ(ファイル)内での検索結果、特定のLSPクライアントからの診断情報、特定のファイルに限定されたリンターの警告など、ウィンドウやバッファに特化した情報のリストを管理するのに適しています。
    • 操作: :lopenでロケーションリストウィンドウを開き、:lnext:lprevでリスト内を移動します。setloclist()関数を使ってプログラム的にリストの内容を設定できます。
    • 利点: 異なるウィンドウで異なる作業を行っている際に、それぞれの作業に関連するリストを独立して管理できるため、コンテキストの混同を防ぎます。

gofmt

gofmtは、Go言語のソースコードをGoの公式スタイルガイドに沿って自動的にフォーマットするツールです。Goのツールチェインに標準で含まれており、Goコミュニティではコードの整形に広く利用されています。

  • 機能:
    • Goのコードを標準的なスタイルに整形します。
    • 構文エラーがある場合など、フォーマットできない場合にはエラーメッセージを出力します。
  • 重要性: gofmtによって、Goのコードベース全体で一貫したコードスタイルが保たれ、可読性が向上し、コードレビューの負担が軽減されます。

Vimscript

VimscriptはVimエディタの内部スクリプト言語です。Vimの動作をカスタマイズしたり、新しい機能を追加したりするために使用されます。このコミットで変更されているfmt.vimファイルはVimscriptで書かれており、VimのGo言語用ファイルタイププラグインの一部です。

  • function! s:GoFormat(): Vimscriptで定義された関数で、s:はスクリプトローカルな関数であることを示します。この関数はGoファイルのフォーマット処理を担当しています。
  • call setloclist(0, errors, 'r'): setloclist()関数を呼び出し、errors変数の内容をロケーションリストに設定します。0は現在のウィンドウを指し、'r'はリストを置き換える(replace)ことを意味します。
  • call setqflist(errors, 'r'): setqflist()関数を呼び出し、errors変数の内容をクイックフィックスリストに設定します。'r'はリストを置き換えることを意味します。

技術的詳細

このコミットの技術的な核心は、VimのVimscript関数であるsetloclist()からsetqflist()への変更です。

misc/vim/ftplugin/go/fmt.vimファイルは、VimでGo言語のファイルを開いた際に、gofmtを実行してコードを整形するためのロジックを含んでいます。このスクリプトは、gofmtの実行結果を処理し、エラーが発生した場合にはそのエラー情報をVimのリスト機能に渡す役割を担っています。

変更前のコードでは、gofmtがエラーを返した場合、そのエラーリストはsetloclist(0, errors, 'r')というVimscriptの呼び出しによって、現在のウィンドウのロケーションリストに設定されていました。

しかし、gofmtのエラーは、単一のファイル内の特定の箇所に限定されるというよりは、コード全体のフォーマットに関する問題や、構文エラーなど、プロジェクト全体に影響を及ぼす可能性のある「エラーのリスト」として扱われるべきです。Vimの設計思想において、このような「エラーのリスト」はクイックフィックスリストに表示されるのが適切です。クイックフィックスリストは、コンパイラのエラー出力のように、複数のファイルにまたがるエラーを効率的にナビゲートし、修正するための標準的なインターフェースを提供します。

このコミットでは、この認識に基づき、setloclist()の呼び出しをsetqflist()に置き換えています。

-            call setloclist(0, errors, 'r')
+            call setqflist(errors, 'r')

この変更により、gofmtがエラーを検出した場合、そのエラーメッセージはVimのグローバルなクイックフィックスリストに表示されるようになります。これにより、ユーザーは:copenコマンドでクイックフィックスウィンドウを開き、:cnext:cprevといったコマンドを使って、gofmtによって報告されたすべてのエラーを効率的に巡回し、修正することができます。これは、特に大規模なGoプロジェクトで作業している場合や、複数のファイルにわたるフォーマットの問題を一度に解決する必要がある場合に、開発者のワークフローを大幅に改善します。

また、この変更は、Vimのリスト機能の適切な利用を促進するという点でも重要です。ロケーションリストはウィンドウ固有の情報を扱うのに適しているのに対し、クイックフィックスリストはセッション全体のエラー情報を扱うのに適しています。gofmtのエラーをクイックフィックスリストに送ることで、Vimの機能がその意図された目的に沿ってより効果的に活用されるようになります。

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

変更はmisc/vim/ftplugin/go/fmt.vimファイル内のs:GoFormat()関数にあります。

具体的には、以下の行が変更されました。

--- a/misc/vim/ftplugin/go/fmt.vim
+++ b/misc/vim/ftplugin/go/fmt.vim
@@ -57,7 +57,7 @@ function! s:GoFormat()\
         endif
         undo
         if !empty(errors)\
-            call setloclist(0, errors, \'r\')
+            call setqflist(errors, \'r\')
         endif
         echohl Error | echomsg \"Gofmt returned error\" | echohl None
     endif

コアとなるコードの解説

変更された行は、s:GoFormat()関数内でgofmtの実行後にエラー(errors変数に格納されている)が存在する場合の処理を定義しています。

  • 変更前:

    call setloclist(0, errors, 'r')
    

    この行は、gofmtが返したエラーのリストを、現在のVimウィンドウのロケーションリストに設定していました。0は現在のウィンドウを指し、'r'は既存のリストを新しいリストで「置き換える(replace)」ことを意味します。

  • 変更後:

    call setqflist(errors, 'r')
    

    この行は、gofmtが返したエラーのリストを、Vimセッション全体のクイックフィックスリストに設定するように変更されました。setqflist()はロケーションリストとは異なり、ウィンドウ指定の引数を必要としません。これは、クイックフィックスリストが常にグローバルなリストであるためです。'r'の引数は同様に、既存のリストを置き換えることを意味します。

この変更により、gofmtのエラーはVimのクイックフィックスウィンドウ(:copenで開く)に表示されるようになり、ユーザーは:cnext:cprevなどのクイックフィックスコマンドを使ってエラー間を移動できるようになります。これは、gofmtが生成するエラーが、コンパイルエラーやリンターの警告と同様に、プロジェクト全体にわたる問題として扱われるべきであるという設計思想に合致しています。

関連リンク

参考にした情報源リンク