Usr_29

Nvim :help ページは、このスクリプトから ソース を使用し、tree-sitter-vimdoc パーサーによって生成されています。


VIM ユーザーマニュアル - Bram Moolenaar 著
プログラム内を移動する
Vim の作者はコンピュータプログラマーです。そのため、Vim にはプログラム作成を支援する多くの機能が含まれていることは驚くべきことではありません。識別子が定義および使用されている場所を見つけるためにジャンプしたり、別のウィンドウで宣言をプレビューしたりできます。次の章にはさらに多くの機能があります。
29.1 タグの使用 29.2 プレビューウィンドウ 29.3 プログラム内を移動する 29.4 グローバル識別子を見つける 29.5 ローカル識別子を見つける
次の章: usr_30.txt プログラムの編集 前の章: usr_28.txt 折りたたみ 目次: usr_toc.txt

タグの使用

タグとは何でしょうか? それは識別子が定義されている場所です。例としては、C または C++ プログラムの関数定義があります。タグのリストはタグファイルに保存されます。Vim はこれを使用して、任意の場所からタグ、つまり識別子が定義されている場所に直接ジャンプできます。カレントディレクトリのすべての C ファイルのタグファイルを生成するには、次のコマンドを使用します。
ctags *.c
"ctags" は独立したプログラムです。ほとんどの Unix システムには既にインストールされています。まだお持ちでない場合は、Universal ctags を次の場所で見つけることができます: https://ctags.io
Universal ctags が推奨されます。Exuberant ctags はもはや開発されていません。
Vim で関数定義に移動したい場合は、次のコマンドを使用してジャンプできます。
:tag startlist
このコマンドは、関数 "startlist" が別のファイルにあっても見つけます。CTRL-] コマンドは、カーソル下の単語のタグにジャンプします。これにより、複雑な C コードを簡単に探索できます。たとえば、関数 "write_block" にいるとします。"write_line" を呼び出していることがわかりますが、"write_line" は何をしているのでしょうか? "write_line" の呼び出しにカーソルを置いて CTRL-] を押すと、この関数の定義にジャンプします。"write_line" 関数は "write_char" を呼び出します。その機能を理解する必要があります。そこで、"write_char" の呼び出しにカーソルを置いて CTRL-] を押します。これで "write_char" の定義に移動しました。
+-------------------------------------+
|void write_block(char **s; int cnt)  |
|{                                      |
|   int i;                              |
|   for (i = 0; i < cnt; ++i)              |
|      write_line(s[i]);              |
|}            |                              |
+-----------|-------------------------+
            |
     CTRL-] |
            |         +----------------------------+
            +--> |void write_line(char *s)    |
                 |{                              |
                 |   while (*s != 0)              |
                 |        write_char(*s++);     |
                 |}          |                      |
                 +--------|-------------------+
                          |
                   CTRL-] |
                          |    +------------------------------------+
                          +--> |void write_char(char c)                    |
                               |{                                    |
                               |    putchar((int)(unsigned char)c); |
                               |}                                    |
                               +------------------------------------+
":tags" コマンドは、通過したタグのリストを表示します。
:tags
# TO tag FROM line in file/text
1 1 write_line 8 write_block.c
2 1 write_char 7 write_line.c
>
それでは戻りましょう。CTRL-T コマンドは前のタグに移動します。上記の例では、"write_char" の呼び出しにある "write_line" 関数に戻ります。このコマンドは、いくつのタグをジャンプバックするかを示すカウント引数を取ります。前に進み、今は戻ってきました。もう一度前に進みましょう。次のコマンドはリストの一番上のタグに移動します。
:tag
カウントを前に付けて、その数のタグをジャンプフォワードできます。例: ":3tag"。CTRL-T もカウントを前に付けることができます。これらのコマンドを使用すると、CTRL-] でコールツリーを下り、CTRL-T でバックアップすることができます。":tags" を使用して、現在地を確認します。

ウィンドウを分割する

":tag" コマンドは、現在のウィンドウのファイルを新しい関数を含むファイルに置き換えます。しかし、古い関数と新しい関数の両方を見たい場合はどうでしょうか? ":split" コマンドの後に ":tag" コマンドを使用すると、ウィンドウを分割できます。Vim には、両方の操作を行うためのショートハンドコマンドがあります。
:stag tagname
現在のウィンドウを分割してカーソル下のタグにジャンプするには、次のコマンドを使用します。
CTRL-W ]
カウントが指定されている場合、新しいウィンドウはその行数の高さになります。

複数のタグファイル

多くのディレクトリにファイルがある場合、それぞれのディレクトリにタグファイルを作成できます。Vim は、そのディレクトリ内のタグにのみジャンプできます。より多くのタグファイルを見つけるには、'tags' オプションを設定して、関連するすべてのタグファイルを含めます。例:
:set tags=./tags,./../tags,./*/tags
これは、現在のファイルと同じディレクトリ、1つ上のディレクトリレベル、およびすべてのサブディレクトリにあるタグファイルを見つけます。これはかなりの数のタグファイルですが、それでも十分ではない場合があります。たとえば、"~/proj/src" のファイルを編集している場合、タグファイル "~/proj/sub/tags" は見つかりません。このような状況のために、Vim はタグファイルのディレクトリツリー全体を検索する機能を提供しています。例:
:set tags=~/proj/**/tags

1つのタグファイル

Vim がタグファイルを探す場所が多い場合、ディスクのガタガタという音が聞こえることがあります。少し遅くなるかもしれません。その場合は、1つの大きなタグファイルを生成する際にこの時間を費やす方が良いでしょう。一晩かけてこれを行うことができます。これには、前述の Universal または Exuberant ctags プログラムが必要です。ディレクトリツリー全体を検索するための引数を提供しています。
cd ~/proj
ctags -R .
これの良いところは、Universal/Exuberant ctags がさまざまなファイルタイプを認識することです。したがって、これは C や C++ プログラムだけでなく、Eiffel や Vim スクリプトでも機能します。これを調整するには、ctags のドキュメントを参照してください。これで、大きなタグファイルがどこにあるかを Vim に伝えるだけで済みます。
:set tags=~/proj/tags

複数の一致

関数が複数回定義されている場合(または複数のクラスのメソッド)、":tag" コマンドは最初の定義にジャンプします。現在のファイルに一致するものがある場合、それが最初に使用されます。同じタグの他の一致箇所にジャンプするには、次のようにします。
:tnext
これを繰り返して、さらに一致する箇所を探します。多数ある場合は、ジャンプするものを選択できます。
:tselect tagname
Vim は選択肢のリストを表示します。
# pri kind tag file
1 F f mch_init os_amiga.c
mch_init()
2 F f mch_init os_mac.c
mch_init()
3 F f mch_init os_msdos.c
mch_init(void)
4 F f mch_init os_riscos.c
mch_init()
選択肢の番号を入力してください (<CR> で中止)
これで、ジャンプしたい一致箇所の番号(最初の列)を入力できます。他の列の情報は、一致箇所がどこで定義されているかについてのヒントを提供します。
一致するタグ間を移動するには、次のコマンドを使用できます。
:tfirst 最初の一致に移動 :[count]tprevious [count] 個前の一致に移動 :[count]tnext [count] 個後の一致に移動 :tlast 最後の一致に移動
[count] を省略すると、1 が使用されます。

タグ名を推測する

コマンドライン補完は、長いタグ名を入力するのを避けるための良い方法です。最初の数文字を入力して <Tab> を押します。
:tag write_<Tab>
最初の一致が表示されます。それが望むものでない場合は、目的のものが見つかるまで <Tab> を押します。関数の名前の一部しかわからない場合があります。または、同じ文字列で始まり、異なる文字列で終わるタグが多数ある場合があります。その場合は、Vim にパターンを使用してタグを見つけるように指示できます。"block" を含むタグにジャンプしたいとします。最初に次のように入力します。
:tag /block
次に、コマンドライン補完を使用します。<Tab> を押します。Vim は "block" を含むすべてのタグを見つけ、最初の一致を使用します。タグ名の前の "/" は、Vim に続くものがリテラルのタグ名ではなく、パターンであることを示します。ここでは、検索パターンのすべての項目を使用できます。たとえば、"write_" で始まるタグを選択したいとします。
:tselect /^write_
"^" は、タグが "write_" で始まることを指定します。そうでない場合、タグ名の途中で一致が見つかる可能性があります。同様に、末尾の "$" は、パターンがタグの末尾まで一致することを保証します。
タグブラウザ
CTRL-] はカーソル下の識別子の定義に移動するため、識別子名のリストを目次として使用できます。例を次に示します。最初に識別子のリストを作成します(これには Universal または Exuberant ctags が必要です)。
ctags --c-types=f -f functions *.c
次に、ファイルなしで Vim を起動し、このファイルを Vim で垂直分割ウィンドウで編集します。
vim
:vsplit functions
ウィンドウにはすべての関数のリストが表示されます。他にもいくつかありますが、無視して構いません。":setlocal ts=99" を実行して少し整理します。このウィンドウで、マッピングを定義します。
:nnoremap <buffer> <CR> 0ye<C-W>w:tag <C-R>"<CR>
移動したい関数を含む行にカーソルを移動します。次に <Enter> を押します。Vim は別のウィンドウに移動し、選択した関数にジャンプします。
タグ名の大文字と小文字を区別しないようにするには、'tagcase' を "followic" のままにして 'ignorecase' を設定するか、'tagcase' を "ignore" に設定します。
'tagbsearch' オプションは、タグファイルがソートされているかどうかを示します。デフォルトでは、タグファイルがソートされていると想定されます。これにより、タグ検索がはるかに高速になりますが、タグファイルがソートされていない場合は機能しません。
'taglength' オプションを使用して、Vim にタグの有効な文字数を伝えることができます。

29.2 プレビューウィンドウ

関数呼び出しを含むコードを編集する場合、正しい引数を使用する必要があります。渡す値を知るには、関数がどのように定義されているかを確認します。タグメカニズムは、このために非常にうまく機能します。できれば、定義は別のウィンドウに表示されます。このために、プレビューウィンドウを使用できます。関数 "write_char" を表示するためのプレビューウィンドウを開くには、次のようにします。
:ptag write_char
Vim はウィンドウを開き、タグ "write_char" にジャンプします。その後、元の位置に戻ります。したがって、CTRL-W コマンドを使用する必要なく入力を続けることができます。関数の名前がテキストに表示されている場合、プレビューウィンドウでその定義を取得するには、次のようにします。
CTRL-W }
カーソル下の単語が定義されているテキストを自動的に表示するスクリプトがあります。CursorHold-example を参照してください。
プレビューウィンドウを閉じるには、次のコマンドを使用します。
:pclose
プレビューウィンドウで特定のファイルを編集するには、":pedit" を使用します。これは、たとえばヘッダーファイルを編集する場合に役立ちます。
:pedit defs.h
最後に、":psearch" を使用して、現在のファイルおよびインクルードされたファイルから単語を検索し、プレビューウィンドウに一致箇所を表示できます。これは、タグファイルがないライブラリ関数を使用する場合に特に役立ちます。例:
:psearch popen
これにより、プレビューウィンドウに "stdio.h" ファイルが表示され、popen() の関数プロトタイプが表示されます。
FILE        *popen __P((const char *, const char *));
プレビューウィンドウが開かれたときの高さを 'previewheight' オプションで指定できます。

29.3 プログラム内を移動する

プログラムは構造化されているため、Vim はその中の項目を認識できます。特定のコマンドを使用して移動できます。C プログラムには、次のような構造が含まれていることがよくあります。
#ifdef USE_POPEN
    fd = popen("ls", "r")
#else
    fd = fopen("tmp", "w")
#endif
ただし、実際にははるかに長く、ネストされている可能性があります。カーソルを "#ifdef" に置いて % を押します。Vim は "#else" にジャンプします。もう一度 % を押すと "#endif" に移動します。さらに % を押すと、再び "#ifdef" に戻ります。構造がネストされている場合、Vim は対応する項目を見つけます。これは、"#endif" を忘れないようにするための良い方法です。"#if" - "#endif" の内部にいる場合は、次のようにしてその開始位置にジャンプできます。
[#
"#if" または "#ifdef" を探していない場合、Vim はビープ音を鳴らします。次の "#else" または "#endif" にジャンプするには、次のようにします。
]#
これら2つのコマンドは、遭遇したすべての "#if" - "#endif" ブロックをスキップします。例:
#if defined(HAS_INC_H)
a = a + inc();
# ifdef USE_THEME
a += 3;
# endif
set_width(a);
最後の行にカーソルがある場合、"[#" は最初の行に移動します。"#ifdef"
"#endif" ブロックはスキップされます。

コードブロック内を移動する

C コードでは、ブロックは {} で囲まれています。これらは非常に長くなる可能性があります。外部ブロックの先頭に移動するには、"[[" コマンドを使用します。"]]" を使用して末尾を見つけます。これは、"{" と "}" が最初の列にあることを前提としています。[{ コマンドは現在のブロックの先頭に移動します。同じレベルの {} のペアをスキップします。"]}" は末尾にジャンプします。概要:
function(int a) +-> { | if (a) | +-> { [[ | | for (;;) --+ | | +-> { | | [{ | | foo(32); | --+ | | [{ | if (bar(a)) --+ | ]} | +-- | +-- break; | ]} | | | } <-+ | | ][ +-- foobar(a) | | } <-+ | } <-+
C++またはJavaで記述する場合、外側の{}ブロックはクラス用です。次のレベルの{}はメソッド用です。クラス内でメソッドの前の開始位置を見つけるには、"[m"を使用します。"]m"はメソッドの次の開始位置を見つけます。
さらに、"[]"は関数の終わりまで後方に移動し、"]]"は次の関数の開始位置まで前方に移動します。関数の終わりは、最初の列にある"}"によって定義されます。
int func1(void) { return 1; +----------> } | [] | int func2(void) | +-> { | [[ | if (flag) start +-- +-- return flag; | ][ | return 2; | +-> } ]] | | int func3(void) +----------> { return 3; }
対応する()、{}、[]の間を移動するために "%" を使用できることも忘れないでください。これは、それらが複数行離れている場合でも機能します。

ブレース内での移動

[( および ]) コマンドは、{} ペアではなく () ペアに対して動作することを除いて、[{ および ]} と同様に動作します。
[(
<-------------------------------- <-------
if (a == b && (c == d || (e > f)) && x > y)
--------------> -------------------------------->
])

コメント内での移動

コメントの先頭に戻るには "[/" を使用します。 "]/ "でコメントの末尾に移動します。これは、/* - */コメントに対してのみ機能します。
   +->          +-> /*
   |    [/ |    * A comment about      --+
[/ |          +--  * wonderful life.        | ]/
   |               */                      <-+
   |
   +--               foo = bar * 3;              --+
                                         | ]/
                /* a short comment */  <-+

29.4 グローバル識別子の検索

Cプログラムを編集していて、変数が"int"または"unsigned"として宣言されているかどうか疑問に思っているとします。これをすばやく見つける方法は、"[I"コマンドを使用することです。カーソルが"column"という言葉の上にあるとします。次のように入力します。
[I
Vimは、見つかった一致する行をリストします。現在のファイルだけでなく、すべてのインクルードされたファイル(およびそれらにインクルードされたファイルなど)も検索します。結果は次のようになります。
structs.h
 1:   29     unsigned     column;    /* column number */
タグまたはプレビューウィンドウを使用するよりも利点は、インクルードされたファイルが検索されることです。ほとんどの場合、これにより正しい宣言が見つかります。タグファイルが古くなっている場合や、インクルードされたファイルのタグがない場合にも有効です。ただし、"[I"が機能するためには、いくつかのことが正しく設定されている必要があります。まず、'include'オプションで、ファイルがどのようにインクルードされるかを指定する必要があります。デフォルト値はCおよびC++で機能します。他の言語の場合は、変更する必要があります。

インクルードされたファイルの検索

Vimは、'path'オプションで指定された場所でインクルードされたファイルを見つけます。ディレクトリが見つからない場合、一部のインクルードファイルは見つかりません。これは、次のコマンドで確認できます。
:checkpath
見つからなかったインクルードファイルが一覧表示されます。また、見つかったファイルによってインクルードされたファイルも一覧表示されます。出力例
--- パスに見つからないインクルードファイル ---
<io.h>
vim.h -->
<functions.h>
<clib/exec_protos.h>
"io.h"ファイルは現在のファイルにインクルードされていますが、見つかりません。"vim.h"は見つかるため、":checkpath"はこのファイルに入り、何がインクルードされているかを確認します。"vim.h"にインクルードされている"functions.h"と"clib/exec_protos.h"ファイルは見つかりません。
注: Vimはコンパイラではありません。"#ifdef"ステートメントを認識しません。これは、"#if NEVER"の後に来ても、すべての"#include"ステートメントが使用されることを意味します。
見つからなかったファイルを修正するには、'path'オプションにディレクトリを追加します。これを知るのに適した場所はMakefileです。"-I/usr/local/X11"などの"-I"項目を含む行を探します。このディレクトリを追加するには、次のように使用します。
:set path+=/usr/local/X11
サブディレクトリが多数ある場合は、"*"ワイルドカードを使用できます。例
:set path+=/usr/*/include
これにより、"/usr/local/include"と"/usr/X11/include"のファイルが見つかります。
インクルードファイルのネストされたツリー全体を持つプロジェクトで作業する場合、"**"項目が役立ちます。これは、すべてのサブディレクトリを検索します。例
:set path+=/projects/invent/**/include
これは、次のディレクトリにあるファイルを見つけます
/projects/invent/include
/projects/invent/main/include
/projects/invent/main/os/include
など
さらに多くの可能性があります。詳細については、'path'オプションを確認してください。実際にどのインクルードファイルが見つかったかを確認するには、次のコマンドを使用します。
:checkpath!
インクルードされたファイル、それらがインクルードするファイルなどの(非常に長い)リストが表示されます。リストを少し短くするために、Vimは以前に見つかったファイルに対して「(既にリストされています)」と表示し、そこに含まれるインクルードされたファイルは再びリストしません。
一致へのジャンプ
"[I"は、テキストが1行だけのリストを生成します。最初の項目をよく見たい場合は、次のコマンドでその行にジャンプできます。
[<Tab>
CTRL-I<Tab>を押すのと同じであるため、"[ CTRL-I"も使用できます。
"[I"が生成するリストの各行の先頭には番号が付いています。最初の項目以外にジャンプしたい場合は、最初に番号を入力します。
3[<Tab>
リストの3番目の項目にジャンプします。CTRL-Oを使用して、開始位置に戻ることができることに注意してください。
[i は最初の一致のみをリストします ]I はカーソルより下の項目のみをリストします ]i はカーソルより下の最初の項目のみをリストします

定義された識別子の検索

"[I"コマンドは任意の識別子を見つけます。"#define"で定義されたマクロのみを見つけるには、次のように使用します。
[D
これも、インクルードされたファイルを検索します。'define'オプションは、"[D"の項目を定義する行がどのようなものかを指定します。CまたはC++以外の言語で動作するように変更できます。"[D"に関連するコマンドは次のとおりです。
[d は最初の一致のみをリストします ]D はカーソルより下の項目のみをリストします ]d はカーソルより下の最初の項目のみをリストします

29.5 ローカル識別子の検索

"[I"コマンドはインクルードされたファイルを検索します。現在のファイルのみを検索し、カーソル下の単語が使用されている最初の場所にジャンプするには、次のようにします。
gD
ヒント:定義に移動します。このコマンドは、ローカルに宣言された(C用語では「static」)変数または関数を見つけるのに非常に役立ちます。例(カーソルが「counter」上にある場合)
   +->   static int counter = 0;
   |
   |     int get_counter(void)
gD |     {
   |             ++counter;
   +--             return counter;
         }
検索をさらに制限し、現在の関数内のみを検索するには、次のコマンドを使用します。
gd
これは、現在の関数の先頭に戻り、カーソル下の単語の最初の出現箇所を見つけます。実際には、最初の列の "{" の上の空行まで逆方向に検索します。そこから、識別子を前方に検索します。例(カーソルが「idx」上にある場合)
        int find_entry(char *name)
        {
   +->            int idx;
   |
gd |            for (idx = 0; idx < table_len; ++idx)
   |                if (strcmp(table[idx].name, name) == 0)
   +--                    return idx;
        }
次の章: usr_30.txt プログラムの編集
著作権:manual-copyright を参照してください vim:tw=78:ts=8:noet:ft=help:norl
メイン
コマンドインデックス
クイックリファレンス