C editing with VIM HOWTO Siddharth Heroor 芳賀靖史 - 日本語訳 yasufumi.haga@nifty.com Revision History Revision v1.0 2001年1月14日 Revised by: sh 第2版。間違いをいくつか修正。 Revision v0.1 2000年12月4日 Revised by: sh 初版。フィードバック待ってます。 この文書は、C 言語やC++, Javaといった構文が似た他の言語で書いたファイル を編集する際の入門編となるものです。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Table of Contents 1. はじめに 2. 動きまわる 2.1. w, e, および b のキーストローク 2.2. {, }, [[ と ]] のキーストローク 2.3. % キーストローク 3. C のファイルの中の勝手な位置にジャンプ 3.1. ctags 3.2. マーク 3.3. gd キーストローク 4. 単語の自動補完 5. 自動的な整形 5.1. 桁数の制限 5.2. コードを自動的にインデントする 5.3. 注釈 6. 複数のファイルを編集する 7. Quickfix 8. 著作権 9. 参考文献 10. 日本語版謝辞 1. はじめに この文書の目的は C 言語で書いてあるファイルをVIMで編集する時に利用でき る、編集オプションをVIMの初心者ユーザーに紹介することです。この文書では コマンドやキーストロークをいくつか紹介しますが、こういったものを使えば 、VIMで C 言語のファイルを編集する際の、プログラマの生産性を上げるのに 役立つことでしょう。 この文書の内容は、VIMをどう使えば C 言語のファイルが編集できるのかを解 説することです。でもその内容の大半は vi にも適用できるものだし、さらに 、ここで C 言語のファイル編集に関して触れているものは C++ や Java, そし て他の似た言語にも大なり小なり適用できるものです。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2. 動きまわる 2.1. w, e, および b のキーストローク ファイルの中を動きまわるにはw, e そして b といったキーが使えます。VIMで は C 言語のプログラムにある様々なトークンが識別できます。 以下のような C のコードを考えてみます。 Figure 1. C プログラムの一部 [moving1] カーソルが if 文の先頭の位置にあるとします。 w を一回押すとカーソルが最 初の (にジャンプします。もう一度 w をタイプすると、そのカーソルは NULL に移ります。その次はカーソルが == トークンに移動するでしょう。それ以降 のキーストロークでは、次のように移動します。 x... )... &&... y... >... z... そして最後に )... です。 e は w と似ていますが、現在カーソルがある場所の言葉の最後に移るのであっ て、その次の言葉の最初には移らない点だけが違います。 b はwとは正反対で、カーソルは逆方向に動きます。だから b のキーストロー クを使えば後ろ向きに移動できます。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.2. {, }, [[ と ]] のキーストローク { と } は段落から段落へと移動するのに使います。 C 言語を編集している時 には、これらのキーは意味が若干違ってきます。 C 言語では段落というのを空 行で分けられた行の塊だと見なすのです。 例 Figure 2. もう一つの C プログラムの一部 [moving2] 上の例では段落が二つ現れています。ある段落から別の段落へは簡単に移動で きます。{ と } というキーを使えばいいのです。{ はカーソルが段落を追って 上の方に移動していき、}はカーソルが段落を追って下の方に移動していきます 。 人にはそれぞれコーディングスタイルがあり、ステートメントの論理的な集ま りを、一つ以上の空行で分けて分類しています。 例 Figure 3. 別の C プログラムの一部 [moving3] { と } キーはこういった状況では非常に役立つものです。ある「段落」から別 の段落へととても簡単に移動できるのです。 役に立つもう一つ別のキーの組が[[ と ]] のキーです。これらのキーを使うと 最初の桁にある直前の { やあるいは次の { にジャンプできます。 例 Figure 4. C のコードの次の一部 [moving4] foo() を編集していたとして、今度は bar() を編集したいとしましょう。ここ で単に ]] とタイプしてください。するとカーソルは bar() 関数の左括弧 "{" に移るはずです。逆方向は若干違ってきます。bar() の中ほどにいたとして、 [[ とタイプすると、カーソルは最初の "{" 、つまり bar() 自身の最初、に移 動するのです。 foo() の最初に移るにはもう一度 [[ とタイプしなければなり ません。でも何回もキーを打つ代わりに、 2[[ とタイプすれば、最少のキース トロークでカーソルを直前の関数の最初にもっていけるのです。 同じようなキーストロークの、もう一つ別の組が ][ と [] です。][ だとカー ソルは最初の桁にある、次の } に移ります。 foo() を編集していたとして foo() の最後に行きたいとします。その場合は ][ でそこに行けます。同様に 、bar() の編集中に foo() の最後に行きたい場合は、[] がカーソルをそこに もっていきます。 キーストロークの覚え方ですが、分けて考えればいいのです。最初のキースト ロークは上がるか下がるかを示しています。 [が上がりで、 ] が下がりです。 次のキーストロークは一致する括弧のタイプを示しています。直前のキースト ロークと同じならカーソルは { に移動するはずでしょうし、キーストロークが 違えば、カーソルは } に移動するでしょう。 ]], ][, [[ および [] のキーストロークで注意することは、これらが最初の桁 にある括弧と一致するということです。もし最初の桁にあるかどうかに関係な く、上方向や下方向にある括弧すべてを見つけたいとしても、それはできませ ん。でもVIMのドキュメントには回避策が書かれています。全ての括弧を見つけ るにはキーストロークをマップしなければなりません。マッピングの時間を節 約する、お奨めのマッピングは次のとおりです。 :map [[ ?{w99[{ :map ][ /}b99]} :map ]] j0[[%/{ :map [] k$][%?} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.3. % キーストローク % はカーソルのところにあるものに一致するものを見つけるのに使います。カ ーソルのところにあるものは、小括弧でも、中括弧、大括弧でもかまいません 。% キーを押せば、カーソルは対応する一致した括弧へジャンプするでしょう 。 数ある中でも、% キーストロークは #if, #ifdef, #else #elif および #endif と一致するものを見つけるのに使えます。 このキーストロークは他人が書いたコードを確認する際に非常に役立つもので す。 Figure 5. 次の C のコードの一部 [moving5] 上記のコードをチェックする場合には括弧が正しいこともチェックします。% はある括弧から(対応する括弧まで)ジャンプするのに使えます。その逆も同 じです。このように、どの左括弧がどの右括弧に対応するのかを見つけたり、 その情報を使ってコードを確認するのに使うのです。 同じように、% はある { から対応する } にジャンプするのにも使えます。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3. C のファイルの中の勝手な位置にジャンプ 3.1. ctags タグというのは、場所の情報を保持する類のものです。これは C 言語を理解し たりそのファイルを編集したりする場合に非常に役立つものです。またある関 数が呼ばれている場所からその定義場所にジャンプしたり、そこから戻ったり する場合にもとても役立ちます。 以下を例にとります。 Figure 6. タグの例 [tags] 今 foo() を編集中に関数 bar() まで行くとしましょう。さて、bar() が何を しているのかを知るにはタグを利用します。この関数の定義にジャンプして、 それから後で戻ってきます。必要なら bar() の中で呼んでいる別の関数にジャ ンプして、戻ってくることもできます。 タグを使うには、最初にすべてのソースファイルで ctags プログラムを実行し なければなりません。このプログラムは tags というファイルを生成します。 この tags というファイルにはすべての関数定義を指しているポインターが入 っており、VIMはその関数定義の場所に行くのにこのファイルを使います。 ジャンプして行き来するのに使う実際のキーストロークは、 CTRL-] と CTRL-T になります。 foo() の中の bar() をコールしている場所で CTRL-] を打つと 、カーソルを bar() の最初にもっていきます。 hitting CTRL-T を打てば、 bar() からfoo() へジャンプして戻れます。 ctags は次のようにして呼び出します。 ┌──────────────────────────────────┐ │ $ ctags options file(s) │ │ │ └──────────────────────────────────┘ 現在のディレクトリにある *.c ファイル全部から tags ファイルを作る場合、 する必要があるのは以下のことだけです。 ┌──────────────────────────────────┐ │ $ ctags *.c │ │ │ └──────────────────────────────────┘ 別々のサブディレクトリに C のファイルがあるようなソースツリーの場合には 、そのソースツリーの一番上で -R オプションを付けて ctags を呼びます。す るとそのソースツリーにあるすべての関数のタグが入った tags ファイルがで きます。例えば以下のようにします。 ┌──────────────────────────────────┐ │ $ ctags -R *.c │ │ │ └──────────────────────────────────┘ ctags には他にもたくさんのオプションが使えます。これらのオプションの説 明は ctags の man ファイルにあります。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.2. マーク マークというのはタグと同じような、場所の情報を保持するものですが、マー クはファイル中のどの場所にでも設定できるし、関数や enum (列挙型)に限 定されるものでもありません。さらに、マークはユーザーが手動で設定しなけ ればなりません。 マークを設定しても、同じものが目に見える形で現れるわけではありません。 マークというのはVIMが覚えているファイルの中の場所というだけなのです。次 のコードを考えてみます。 Figure 7. マークの例 [marks] 今 x++; の行を編集中に他の行を編集し、そのあとまたこの行に戻ってきたい としましょう。この場合、m' というキーストロークでこの x++; の行にマーク を設定できるし、 '' を打てば、後でこの同じ行に戻ってこれます。 VIMではマークは複数設定できます。これらのマークは a-z や A-Z それに 1-0 といったレジスタに格納されます。マークを設定して、その同じものをあるレ ジスタ、例えば j に格納するには mj と打てば済みます。このマークに戻って くるには、 'j と打てば済みます。 複数のマークを使うと、まとまったコードの中で行ったり来たりする際に本当 に役立ちます。同じ上記の例を使いましょう。 x++; で一つマークして、 y=x; でもう一つ、そしてそれらの間をジャンプしたり、あるいは他の場所にジャン プして、それからジャンプして戻りたいことがあるかもしれません。 マークは複数のファイルにまたがってもかまいません。そういったマークを使 うには大文字のレジスタ、つまり A-Z のレジスタを使わなければなりません。 小文字のレジスタはファイルの中だけで使うもので、ファイルをまたがること はありません。言い換えれば、ある foo.c というファイルの中でマークをレジ スタ "a" に設定し、それから別のファイルに移動して 'a と打っても、カーソ ルは直前の場所には戻らないのです。別のファイルにカーソルをもっていくよ うなマークがしたければ、大文字のレジスタを使う必要があるでしょう。例え ば、 ma の代わりに mA を使うんです。複数のファイルを編集するについては 、後のセクションで論じます。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.3. gd キーストローク 次のコードのひとまとまりを考えます。 Figure 8. 三番目の例 [gd] y と z がなんだったかを、なぜだか忘れてしまい、大至急それらが定義してあ る場所に行きたいとします。一つの方法は y とか z を後方検索することです 。でもVIMにはもっと簡単で素早い解決方法があります。gd というキーストロ ークは "Goto Declaration (宣言へ行く)" の略になってます。カーソルを "y" において gd と打つと、カーソルをその宣言、つまり struct Y y; にもっ ていくんです。 gDも似たようなキーストロークです。これはカーソルの位置にある変数をグロ ーバル宣言してある場所まで、カーソルをもっていきます。だから、 x の宣言 に行きたければ、必要なことは gD と打つだけで、これでカーソルは x の宣言 に移動するでしょう。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4. 単語の自動補完 次のコードを考えます。 Figure 9. 自動補完の例 [auto] A_Very_Long_Function_Name() という関数は、何度も何度もタイプするので、 まったく癪の種になることがあります。でもまだ挿入モードにいる間でも、そ の前後にある単語を探して、単語を自動補完できるのです。Another_Function () という関数の中で A_Very... とタイプし、CTRL-P と打ってもいいでしょう 。最初に一致した単語が最初に表示されます。この場合は A_Very_Long_Variable_Name かもしれません。正しく補完するためにもう一度 CTRL-P と打ち、次に一致する単語まで検索が続きます。その単語が A_Very_Long_Function_Name です。正しい単語が見つかったら、ただちにタイ プを続けられます。この過程の間はずっとVIMが挿入モードのままでいます。 CTRL-P と似たものに CTRL-N というキーストロークがあります。これは後方検 索の代わりに前方検索を行なうものです。これらのキーストロークは両方とも 、ファイルの先頭かファイルの最後に行き当たるまで検索を続けます。 CTRL-P や CTRL-N は CTRL-X モードというモードの一部になっています。 CTRL-X モードは挿入モードのサブモードです。だから挿入モードにいるときは 、このモードに入れるわけです。 CTRL-X モードを抜けるには CTRL-X, CTRL-P および CTRL-N 以外のキーストロークを何か打てばいいです。いったんCRTL-X モードを抜けたら、挿入モードに戻ります。 CRTL-X モードを使えば、さまざまな方法で自動補完ができるようになります。 ファイル名を自動補完することさえできます。ヘッダーファイルをインクルー ドしなければならない時に、これは特に役立ちます。 CTRL-X モードを使えば 、次のようなやり方で foo.h というファイルがインクルードできます。 #include "f CTRL-X CTRL-F" そう、CTRL-X CTRL-Fです。わかってる、わかってるって。emacsみたいだって いうんでしょ ;-) CTRL-Xモードではできることが他にもあります。そんなもの の一つが辞書補完です。これを使うと単語の一覧が入ったファイルを指定して 、それを使って補完するようにできるんです。ディフォルトだとこの辞書オプ ションは設定されていません。設定するには :set dictionary=file というコ マンドを使います。大抵は C 言語のキーワードや typedef そして #define な んかをこの辞書ファイルに置いておけます。同じように、 C++ や Java のプロ グラマなら、クラス名を加えるのに惹かれるかもしれません。 辞書ファイルのフォーマットは単純です。 1 行に一つ補完したい単語を書いて おくだけです。だから、 C 言語の辞書ファイルというのはたぶんこんなような ものになるんでしょう。 Figure 10. 辞書ファイルのサンプル [dict] 辞書補完を使うには、 CTRL-X CTRL-K と打つ必要があります。補完は CTRL-P や CTRL-N のキーストロークに似ています。だから、えーっと、 "typedef" と タイプするなら、 CTRL-X CTRL-K と打つだけでよくて、すると、パッと出てき て、名前の補完が完了です。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5. 自動的な整形 5.1. 桁数の制限 桁数を80桁とか75桁とか、何であれ、制限しなければならないことがよくあり ます。次のコマンドを使えば、きわめて容易にこの設定ができてしまいます。 ┌──────────────────────────────────┐ │ :set textwidth=80 │ │ │ └──────────────────────────────────┘ これを自動的にするには、たんに自分の .vimrc にこのコマンドを置いてくだ さい。 テキスト幅を制限する他に、ある桁でテキストを折り返したいこともあるでし ょう。それは自分が使っている端末がそう規定しているからそうなっていたり 、あるいはたんにそういうように自分で選んだからかもしれません。こんな場 合に使うコマンドが次のコマンドです。 ┌──────────────────────────────────┐ │ :set wrapwidth=60 │ │ │ └──────────────────────────────────┘ 上記のコマンドは60桁でテキストを折り返すようにします。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.2. コードを自動的にインデントする C でコーディングしている間は、内側のコードの塊をインデントすることがよ くあります。コーディング中にこれを自動化するために、VIMには cindent と いうオプションがあります。これを設定するには、次のコマンドを使うだけで す。 ┌──────────────────────────────────┐ │ :set cindent │ │ │ └──────────────────────────────────┘ cindent を設定すれば、コードは自動的にきれいになります。このコマンドを 自動的に実行する場合は、自分の .vimrc に加えるだけでいいです。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.3. 注釈 VIMでは注釈を自動整形できるようにもなっています。注釈は三つの部分に分け ることができます。つまり最初の部分、真中の部分、そして最後の部分です。 例えば、自分のコーディングスタイルに必要な条件だからということで、注釈 を次のスタイルにする必要があるかもしれません。 /* * これは注釈です */ このような場合は次のコマンドが使えます。 ┌──────────────────────────────────┐ │ :set comments=sl:/*,mb:*,elx:*/ │ │ │ └──────────────────────────────────┘ 読者のために、このコマンドを解読してみましょう。このコマンドには三つの 部分があります。最初は sl:/* という部分です。これは三つにわかれた注釈が /* で始まることを VIM に教えています。次は注釈の真中の部分が * だと VIM に告げています。注釈の最後の部分は、二つのことを VIM に教えています。一 つはこのコマンドが */ で終らねばならないこと、そしてもう一つは / を打つ と自動的に注釈を完成させねばならないことです。 もう一つ別の例をあげてみましょう。自分のコーディング指針が次のようだと しましょう。 /* ** これは注釈です */ このような状況では、注釈をつけるのに次のコマンドが使えます。 ┌──────────────────────────────────┐ │ :set comments=sl:/*,mb:**,elx:* │ │ │ └──────────────────────────────────┘ 注釈を挿入するには、 /* とタイプし enter キーを打つだけです。次の行には 自動的に ** が入っているはずです。注釈を書き終ったらもう一度 enter キー を打つだけで、もう一つ別の ** が挿入されます。でも注釈を終えるには **/ じゃなくて */ が欲しいですね。VIMはここでもまことに賢いんです。最後の * を削除して / に置き換える必要がないんです。代わりに / とだけ打って下さ い。そうすれば VIMはそれが注釈の終りだと認識し、自動的にその行を ** か ら */ へ変えるはずです。 もっと知りたいことがあれば、次のコマンドを打って下さい。 :h comments ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6. 複数のファイルを編集する 一度に二つ以上のファイルを編集する必要があるというのはよくあることです 。例えば、ヘッダーファイルを編集していて、同時にソースファイルも編集す ることがあるかもしれません。一度に二つ以上のファイルを編集するには、次 のコマンドを使って VIM を起動します。 ┌──────────────────────────────────┐ │ $ vim file1 file2 ... │ │ │ └──────────────────────────────────┘ これで最初のファイルが編集でき、以下のコマンドを使えば次のファイルに移 ることができます。 ┌──────────────────────────────────┐ │ :n │ │ │ └──────────────────────────────────┘ 戻る場合は次のコマンドを使えばできます。 ┌──────────────────────────────────┐ │ :e# │ │ │ └──────────────────────────────────┘ 二つのファイルを同時に見ることができて、さらにその二つを切替えることが できれば、コーディング中役立つかもしれません。言い換えれば、画面を分割 して上の方にヘッダーファイルが見えて下の画面ではソースファイルが見えれ ば、役立つだろうということです。VIMにはそんな画面を分割するコマンドがあ るんです。これを起動するにはたんに次のようにします。 :split 同じファイルが両方のウィンドウに表示されると思います。ここでどんなコマ ンドを実行しても、それが影響するのはその時に使っているウィンドウだけで す。だから、次のコマンドを使えば、別のウィンドウにある別のファイルが編 集できるんです。 :e file2 このコマンドを実行した後は、二つのファイルが見えるようになっているのが わかるでしょう。一つのウィンドウには最初のファイルが表示されていて、他 のウィンドウには二番目のファイルが表示されています。この二つのファイル を切り替えて使うには、 CTRL-W CTRL-W というキーストロークを使わなければ なりません。ウィンドウの分割についてもっと知りたければ、そこで help コ マンドを実行すればいいです。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 7. Quickfix C 言語でコーディングしている場合、編集 - コンパイル - 編集というサイク ルがよくあります。(この文書を読んでいる)読者なら、これまでに説明した コマンドなどを使って、C 言語のファイルを編集し、ファイルを保存し、その コードをコンパイルし、そしてエラーの箇所に行き、また編集を始めるのが普 通でしょう。こんなときに、Quickfixというモードを使えば、 VIMはこのサイ クル時間を若干節約するのを助けてくれます。基本的には、コンパイラのエラ ーをファイルに保存しておいて、次のコマンドを使ってVIMでこのファイルをオ ープンする必要があります。 ┌──────────────────────────────────┐ │ │ │ $ vim -q コンパイラのエラーを保存したファイル │ │ │ └──────────────────────────────────┘ VIMは自動的にエラーの情報が入っているこのファイルをオープンして、カーソ ルを最初のエラーの位置にもっていきます。 このやり方には近道があります。 "make" というコマンドを使えば、自動的に コードをコンパイルして、最初に発生したエラーの位置に行ってくれます。 make コマンドを起動するには次のようにタイプします。 ┌──────────────────────────────────┐ │ :make │ │ │ └──────────────────────────────────┘ 実は、このコマンドはシェルで make をコールして、最初のエラー箇所に行く んです。でもコンパイルに make ではなく cc のようなコマンドを使っている 場合は、この make コマンドを使う時に実行したいコマンドを makeprg という 変数に設定しなければなりません。例えば次のようにです。 :set makeprg=cc\ foo.c makeprg を設定しておけば、実際に make コマンドを呼び出せるし、 Quickfix モードが動き出すことでしょう。 最初のエラーを修正したら、次にやることはその次のエラーの箇所に行ってそ れを修正することでしょう。次のエラーの箇所に行くには以下のコマンドを使 います。 :cn そこから戻るには、次のコマンドを使います。 :cN 例を使って実際にやってみることにしましょう。以下のコードを考えてくださ い。 Figure 11. 即効ファイルプログラムのリスト [quickfix_prog] 見ればわかりますが、5行目にエラーがあります。このファイルは test.c とい う名前で保存されていて、makeprg は以下のコマンドを使って設定してありま す。 ┌──────────────────────────────────┐ │ :set makeprg=gcc\ test.c │ │ │ └──────────────────────────────────┘ 次に、 make コマンドは :make というコマンドを使って起動します。すると gcc がエラーを出し、 make コマンドの出力が以下のようなものになります。 Figure 12. :make コマンドで出たエラー [make_error] RETURN を押すと、カーソルは6行目に移動します。 今度は :cn コマンドがカーソルを4行目にもっていきます。 直前のエラー箇所に戻るには、 :cN コマンドが使えます。これでカーソルは6 行目に戻ることでしょう。 5行目のエラーを修正して "return 1;" を追加したら、もう一度 :make を実行 します。するとその出力は次のようになります。 Figure 13. エラー無し [make_no_error] これはほんのわずかな一例です。でもこのQuickfixを使ってコンパイル時間に 関する問題が解決できるし、うまくいけば編集 - コンパイル - 編集のサイク ルも削減できるのです。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8. 著作権 Copyright (c) 2000,2001 Siddharth Heroor. 本文書の複製、配布、ないしは変更は、 Free Software Foundation 発行のバ ージョン 1.1 ないしそれ以降のすべてのバージョンのフリー文書利用許諾契約 書(GNU Free Documentation License)の条件下で許可する。ただし、変更不 可能部分が無いこと、表表紙が無いこと、および裏表紙が無いこと。フリー文 書利用許諾契約書の複製は以下のサイトで取得できる。 http://www.gnu.org/ copyleft/fdl.html ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9. 参考文献 VIM に関するより多くの情報は以下のサイトから取得できるし、 VIM もそこか らダウンロードできる。 http://www.vim.org ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10. 日本語版謝辞 校正をしていただいた佐野さん、高城さんには、この場を借りて御礼申し上げ ます。また、初参加の私の些細な質問にも、丁寧にお答え下さった中野さん、 高橋さん、アドバイスをいただいた中谷さんにも御礼申し上げます。