Usr_40

Nvim の :help ページは、生成されたもので、ソースtree-sitter-vimdoc パーサーを使って生成しています。


VIM ユーザーマニュアル - Bram Moolenaar 著
新しいコマンドを作成する
Vim は拡張可能なエディタです。頻繁に使用するコマンドのシーケンスを新しいコマンドにすることができます。既存のコマンドを再定義することもできます。自動コマンドを使用すると、コマンドを自動的に実行できます。
40.1 キーマッピング 40.2 コマンドラインコマンドの定義 40.3 自動コマンド
次の章: usr_41.txt Vim スクリプトを書く 前の章: usr_32.txt Undo ツリー 目次: usr_toc.txt

キーマッピング

単純なマッピングはセクション 05.3 で説明しました。原則は、あるキーストロークのシーケンスが別のキーストロークのシーケンスに変換されるということです。これは単純ですが、強力なメカニズムです。最も単純な形式は、1つのキーがキーのシーケンスにマップされることです。<F1>を除くファンクションキーはVimで定義された意味がないため、これらをマップするのに適しています。例
:map <F2> GoDate: <Esc>:read !date<CR>kJ
これは3つのモードがどのように使われるかを示しています。「G」で最後の行に移動した後、「o」コマンドは新しい行を開き、挿入モードを開始します。テキスト「Date: 」が挿入され、<Esc>で挿入モードを抜けます。<>内の特殊キーの使用に注意してください。これはアングルブラケット表記と呼ばれます。キー自体を押すのではなく、別々の文字として入力します。これによりマッピングが読みやすくなり、問題なくテキストをコピー&ペーストできます。「:」文字でVimはコマンドラインに移動します。":read !date"コマンドは"date"コマンドの出力を読み取り、現在の行の下に追加します。":read"コマンドを実行するには<CR>が必要です。この実行時点で、テキストは次のようになります。
日付
金 6月 15 12:54:34 CEST 2001
ここで、「kJ」はカーソルを上に移動し、行を結合します。マッピングに使用するキーを決定するには、map-which-keysを参照してください。

マッピングとモード

":map"コマンドは、ノーマルモードのキーの再マッピングを定義します。他のモードのマッピングを定義することもできます。たとえば、":imap"は挿入モードに適用されます。これを使用して、カーソルの下に日付を挿入できます。
:imap <F2> <CR>Date: <Esc>:read !date<CR>kJ
これはノーマルモードでの<F2>のマッピングによく似ていますが、開始が異なるだけです。ノーマルモードの<F2>のマッピングはまだ存在します。したがって、各モードで同じキーを異なるようにマップできます。このマッピングは挿入モードで開始されますが、ノーマルモードで終了することに注意してください。挿入モードで続行する場合は、マッピングに「a」を追加します。
マップコマンドと、どのモードで動作するかの概要を以下に示します
:map ノーマル、ビジュアル、オペレータ待ち :vmap ビジュアル :nmap ノーマル :omap オペレータ待ち :map! 挿入とコマンドライン :imap 挿入 :cmap コマンドライン
オペレータ待ちモードは、"d"や"y"などの演算子文字を入力し、移動コマンドまたはテキストオブジェクトを入力することが予想される場合です。したがって、"dw"を入力すると、"w"はオペレータ待ちモードで入力されます。
コマンドd<F7>がCプログラムブロック(中括弧 {} で囲まれたテキスト)を削除するように、<F7>を定義したいとします。同様に、y<F7>はプログラムブロックを名前のないレジスタにヤンクします。したがって、必要なのは、<F7>が現在のプログラムブロックを選択するように定義することです。これは、次のコマンドで実行できます
:omap <F7> a{
これにより、<F7>は、タイプしたように、オペレータ待ちモードで選択ブロック "a{" を実行します。キーボードでa {を入力するのが少し難しい場合に、このマッピングは役立ちます。

マッピングのリスト

現在定義されているマッピングを表示するには、引数なしで":map"を使用します。または、動作するモードを含むバリアントのいずれかを使用します。出力は次のようになります。
_g :call MyGrep(1)<CR>
v <F2> :s/^/> /<CR>:noh<CR>``
n <F2> :.,$s/^/> /<CR>:noh<CR>``
<xHome> <Home> <xEnd> <End>
リストの最初の列は、マッピングが有効なモードを示しています。これは、ノーマルモードの場合は「n」、挿入モードの場合は「i」などです。空白は、":map"で定義されたマッピングに使用され、ノーマルモードとビジュアルモードの両方で有効です。マッピングをリストする際の1つの便利な目的は、<>形式の特殊キーが認識されているかどうかを確認することです(これは色がサポートされている場合にのみ機能します)。たとえば、<Esc>がカラーで表示されている場合、それはエスケープ文字を表します。他のテキストと同じ色の場合、それは5文字です。

再マッピング

マッピングの結果は、その中の他のマッピングについて検査されます。たとえば、上記の<F2>のマッピングは次のように短縮できます。
:map <F2> G<F3>
:imap <F2> <Esc><F3>
:map <F3>  oDate: <Esc>:read !date<CR>kJ
ノーマルモードでは、<F2>は最後の行に移動し、<F3>が押されたかのように動作するようにマップされます。挿入モードでは、<F2><Esc>で挿入モードを停止し、<F3>も使用します。次に、<F3>は実際の作業を行うようにマップされます。
Exモードをほとんど使用せず、「Q」コマンドをテキストのフォーマットに使用したいとします(これはVimの古いバージョンではそうでした)。このマッピングはそれを行います
:map Q gq
ただし、まれにExモードをどうしても使用する必要がある場合があります。「gQ」をQにマップして、Exモードに移動できるようにしましょう。
:map gQ Q
ここで何が起こるかというと、「gQ」と入力すると、「Q」にマップされます。ここまでは順調です。しかし、その後「Q」が「gq」にマップされるため、「gQ」を入力すると「gq」になり、Exモードにはまったく移動できません。キーが再度マップされないようにするには、":noremap"コマンドを使用します
:noremap gQ Q
これで、Vimは「Q」が適用されるマッピングについて検査されないことを認識します。すべてのモードに同様のコマンドがあります
:noremap ノーマル、ビジュアル、オペレータ待ち :vnoremap ビジュアル :nnoremap ノーマル :onoremap オペレータ待ち :noremap! 挿入とコマンドライン :inoremap 挿入 :cnoremap コマンドライン

再帰マッピング

マッピングがそれ自体をトリガーすると、永遠に実行されます。これは、アクションを無制限に繰り返すために使用できます。たとえば、最初の行にバージョン番号が含まれるファイルのリストがあるとします。これらのファイルをvim *.txtで編集します。現在、最初のファイルを編集しています。このマッピングを定義します。
:map ,, :s/5.1/5.2/<CR>:wnext<CR>,,
ここで「,,」を入力します。これによりマッピングがトリガーされます。最初の行の "5.1" を "5.2" に置き換えます。次に、":wnext" を実行してファイルを書き込み、次のファイルを編集します。マッピングは「,,」で終わります。これにより、同じマッピングが再度トリガーされ、置換などが実行されます。これは、エラーが発生するまで続きます。この場合、置換コマンドが "5.1" の一致を見つけられないファイルである可能性があります。次に、「5.1」を挿入する変更を行い、再度「,,」を入力して続行できます。または、リストの最後のファイルであるため、":wnext" が失敗します。マッピングが途中でエラーが発生すると、マッピングの残りの部分は破棄されます。CTRL-C はマッピングを中断します(MS-Windows では CTRL-Break )。
マッピングの削除
マッピングを削除するには、":unmap" コマンドを使用します。ここでも、マッピングが適用されるモードは、使用されるコマンドによって異なります。
:unmap ノーマル、ビジュアル、オペレータ待ち :vunmap ビジュアル :nunmap ノーマル :ounmap オペレータ待ち :unmap! 挿入とコマンドライン :iunmap 挿入 :cunmap コマンドライン
ノーマルモードとオペレータ待ちモードでは動作するが、ビジュアルモードでは動作しないマッピングを定義するトリックがあります。最初に3つのモードすべてに対して定義してから、ビジュアルモードに対して削除します。
:map <C-A> /---><CR>
:vunmap <C-A>
5つの文字 "<C-A>" は、単一のキー CTRL-A を表すことに注意してください。
すべてのマッピングを削除するには、:mapclear コマンドを使用します。さまざまなモードのバリエーションは、これで推測できます。このコマンドには注意してください。元に戻すことはできません。

特殊文字

":map" コマンドの後に別のコマンドを続けることができます。|文字は2つのコマンドを区切ります。これは、|文字をマップコマンド内で使用できないことも意味します。含めるには、<Bar>(5文字)を使用します。例
:map <F8> :write <Bar> !checkin %:S<CR>
同じ問題が、末尾に空白があることに注意する必要があるという追加事項付きで、":unmap" コマンドにも適用されます。これら2つのコマンドは異なります
:unmap a | unmap b
:unmap a| unmap b
最初のコマンドは、末尾にスペースがある「a 」をマッピング解除しようとします。
マッピング内でスペースを使用する場合は、<Space>(7文字)を使用します。
:map <Space> W
これにより、スペースバーは空白で区切られた単語を前方に移動します。
マッピングの直後にコメントを入れることはできません。これは、「"」文字がマッピングの一部と見なされるためです。|"を使用できます。これにより、コメント付きの新しい空のコマンドが開始されます。例
:map <Space> W|     " Use spacebar to move forward a word

マッピングと省略形

省略形は、挿入モードのマッピングによく似ています。引数は同じように処理されます。主な違いは、トリガーされる方法です。省略形は、単語の後に単語以外の文字を入力するとトリガーされます。マッピングは、最後の文字を入力するとトリガーされます。もう1つの違いは、省略形に入力する文字は入力時にテキストに挿入されることです。省略形がトリガーされると、これらの文字は削除され、省略形が生成するもので置き換えられます。マッピングの文字を入力するとき、トリガーする最後の文字を入力するまで何も挿入されません。'showcmd'オプションが設定されている場合、入力した文字はVimウィンドウの最後の行に表示されます。マッピングがあいまいな場合は例外です。次の2つのマッピングを実行したとします。
:imap aa foo
:imap aaa bar
ここで、「aa」と入力すると、Vimは最初のマッピングを適用するか2番目のマッピングを適用するかを認識しません。別の文字が入力されるのを待ちます。それが「a」の場合、2番目のマッピングが適用され、「bar」になります。たとえば、スペースの場合、最初のマッピングが適用され、「foo」になり、その後にスペースが挿入されます。

追加...

<script>キーワードを使用して、マッピングをスクリプトローカルにすることができます。:map-<script>を参照してください。
<buffer>キーワードを使用して、マッピングを特定のバッファーローカルにすることができます。:map-<buffer>を参照してください。
<unique>キーワードを使用して、既存のマッピングが存在する場合、新しいマッピングの定義を失敗させることができます。それ以外の場合、新しいマッピングは古いマッピングを上書きするだけです。:map-<unique>を参照してください。
キーを何もしないようにするには、<Nop>(5文字)にマップします。これにより、<F7>キーはまったく何も行いません
:map <F7> <Nop>| map! <F7> <Nop>
<Nop>の後にスペースは入れないでください。

40.2 コマンドラインコマンドの定義

Vimエディターでは、独自のコマンドを定義できます。これらのコマンドは、他のコマンドラインモードコマンドと同様に実行できます。コマンドを定義するには、":command"コマンドを使用します。以下に例を示します。
:command DeleteFirst 1delete
これで、":DeleteFirst"コマンドを実行すると、Vimは":1delete"を実行し、最初の行を削除します。
注: ユーザー定義コマンドは大文字で始まる必要があります。":Next"は使用できません。アンダースコアは使用できません!数字は使用できますが、推奨されません。
ユーザー定義コマンドを一覧表示するには、次のコマンドを実行します。
:command
組み込みコマンドと同様に、ユーザー定義コマンドも省略できます。コマンドを他のコマンドと区別するのに十分な文字数だけを入力する必要があります。コマンドライン補完を使用して、フルネームを取得できます。

引数の数

ユーザー定義コマンドは、一連の引数を取ることができます。引数の数は、-nargsオプションで指定する必要があります。たとえば、:DeleteFirstコマンドは引数を取らないため、次のように定義できます。
:command -nargs=0 DeleteFirst 1delete
ただし、引数がゼロの場合はデフォルトであるため、"-nargs=0"を追加する必要はありません。-nargsのその他の値は次のとおりです。
-nargs=0 引数なし -nargs=1 引数1つ -nargs=* 任意の数の引数 -nargs=? ゼロまたは1つの引数 -nargs=+ 1つ以上の引数

引数の使用

コマンド定義内では、引数は<args>キーワードで表されます。例:
:command -nargs=+ Say :echo "<args>"
次のように入力すると
:Say Hello World
Vimは「Hello World」と表示します。ただし、二重引用符を追加すると、機能しません。例:
:Say he said "hello"
特殊文字を文字列に変換し、式として使用できるように適切にエスケープするには、"<q-args>"を使用します。
:command -nargs=+ Say :echo <q-args>
これで、上記の":Say"コマンドは、次の実行になります。
:echo "he said \"hello\""
<f-args>キーワードには、関数呼び出し引数として使用するのに適した形式を除いて、<args>キーワードと同じ情報が含まれています。例:
:command -nargs=* DoIt :call AFunction(<f-args>)
:DoIt a b c
次のコマンドを実行します。
:call AFunction("a", "b", "c")

行範囲

一部のコマンドは、引数として範囲を取ります。Vimにそのようなコマンドを定義していることを伝えるには、-rangeオプションを指定する必要があります。このオプションの値は次のとおりです。
-range 範囲が許可されます。デフォルトは現在の行です。 -range=% 範囲が許可されます。デフォルトはファイル全体です。 -range={count} 範囲が許可されます。その最後の数値は、デフォルトが{count}である単一の数値として使用されます。
範囲が指定されている場合、キーワード<line1><line2>は、範囲内の最初と最後の行の値を取得します。たとえば、次のコマンドは、指定された範囲をファイル "save_file" に書き出すSaveItコマンドを定義します。
:command -range=% SaveIt :<line1>,<line2>write! save_file

その他のオプション

その他のオプションとキーワードの一部を次に示します。
-count={number} コマンドは、デフォルトが{number}であるカウントを取ることができます。結果のカウントは、<count>キーワードを通じて使用できます。 -bang !を使用できます。存在する場合、<bang>を使用すると、!になります。 -register レジスターを指定できます。(デフォルトは名前のないレジスターです。)レジスターの指定は、<reg>(別名<register>)として使用できます。 -complete={type} 使用されるコマンドライン補完のタイプ。可能な値のリストについては、":command-completion"を参照してください。 -bar コマンドの後に|と別のコマンド、または"とコメントを続けることができます。 -buffer コマンドは、現在のバッファでのみ使用できます。
最後に、<lt>キーワードがあります。これは文字<を表します。言及した<>項目の特別な意味をエスケープするために使用します。

再定義と削除

同じコマンドを再定義するには、!引数を使用します。
:command -nargs=+ Say :echo "<args>"
:command! -nargs=+ Say :echo <q-args>
ユーザーコマンドを削除するには、":delcommand"を使用します。これは、コマンドの名前である単一の引数を取ります。例:
:delcommand SaveIt
すべてのユーザーコマンドを削除するには
:comclear
注意してください、これは元に戻すことはできません!
この詳細については、リファレンスマニュアル: user-commandsを参照してください。

40.3 自動コマンド

自動コマンドとは、ファイルの読み取りや書き込み、バッファの変更などのイベントに応じて自動的に実行されるコマンドです。自動コマンドを使用することで、たとえば圧縮ファイルを編集するようにVimをトレーニングできます。これは、gzipプラグインで使用されています。自動コマンドは非常に強力です。注意して使用すれば、多くのコマンドの入力を避けるのに役立ちます。不注意に使用すると、多くの問題を引き起こす可能性があります。
ファイルを書き込むたびに、ファイルの末尾の日付スタンプを置き換えたいとします。まず、関数を定義します。
:function DateInsert()
:  $delete
:  read !date
:endfunction
この関数は、バッファがファイルに書き込まれる直前に毎回呼び出されるようにする必要があります。これにより、そのようになります。
:autocmd BufWritePre *  call DateInsert()
"BufWritePre"は、この自動コマンドがトリガーされるイベントです。バッファをファイルに書き込む直前(pre)。"*"は、ファイル名と一致するパターンです。この場合は、すべてのファイルと一致します。このコマンドを有効にすると、":write"を実行するときに、Vimは一致するBufWritePre自動コマンドがあるかどうかを確認して実行し、その後、":write"を実行します。 :autocmdコマンドの一般的な形式は次のとおりです。
:autocmd [group] {events} {file-pattern} [++nested] {command}
[group]名はオプションです。コマンドの管理と呼び出しに使用されます(詳細については後述します)。{events}パラメーターは、コマンドをトリガーするイベントのリスト(コンマ区切り)です。 {file-pattern}は、通常はワイルドカードを含むファイル名です。たとえば、"*.txt"を使用すると、名前が ".txt" で終わるすべてのファイルに自動コマンドが使用されます。オプションの[++nested]フラグは、自動コマンドのネストを許可し(下記参照)、最後に、{command}は実行するコマンドです。
自動コマンドを追加すると、既存の自動コマンドは残ります。自動コマンドを複数回追加することを避けるには、この形式を使用する必要があります。
:augroup updateDate
:  autocmd!
:  autocmd BufWritePre *  call DateInsert()
:augroup END
これにより、新しい自動コマンドを定義する前に、:autocmd!で以前に定義された自動コマンドがすべて削除されます。グループについては後で説明します。

イベント

最も便利なイベントの1つはBufReadPostです。これは、新しいファイルが編集された後にトリガーされます。オプション値を設定するためによく使用されます。たとえば、"*.gsm"ファイルがGNUアセンブリ言語であることを知っているとします。構文ファイルを正しく取得するには、次の自動コマンドを定義します。
:autocmd BufReadPost *.gsm  set filetype=asm
Vimがファイルの種類を検出できる場合、'filetype'オプションが設定されます。これにより、Filetypeイベントがトリガーされます。特定のタイプのファイルが編集されたときに何かを行うためにこれを使用します。たとえば、テキストファイルの略語のリストをロードするには
:autocmd Filetype text  source ~/.config/nvim/abbrevs.vim
新しいファイルの編集を開始するときに、Vimにスケルトンを挿入させることができます。
:autocmd BufNewFile *.[ch]  0read ~/skeletons/skel.c
イベントの完全なリストについては、autocmd-eventsを参照してください。

パターン

{file-pattern}引数は、実際にはファイルパターンのコンマ区切りリストにすることができます。例:*.c,*.hは ".c" および ".h" で終わるファイルと一致します。通常のファイルワイルドカードを使用できます。最もよく使用されるものの概要を次に示します。
* 任意の文字を任意の回数一致させます ? 任意の文字を1回一致させます [abc] 文字a、b、またはcと一致します . ドットと一致します a{b,c} "ab" と "ac" と一致します
パターンにスラッシュ(/)が含まれている場合、Vimはディレクトリ名を比較します。スラッシュがない場合、ファイル名の最後の部分のみが使用されます。たとえば、"*.txt" は "/home/biep/readme.txt" と一致します。パターン "/home/biep/*" も一致します。しかし、"home/foo/*.txt" は一致しません。スラッシュを含めると、Vimはファイル("/home/biep/readme.txt")のフルパスと相対パス(たとえば、"biep/readme.txt")の両方に対してパターンを照合します。
注: MS-Windowsなど、バックスラッシュをファイル区切り文字として使用するシステムで作業する場合は、自動コマンドでもスラッシュを使用します。これにより、バックスラッシュには特別な意味があるため、パターンを簡単に記述できます。また、自動コマンドを移植可能にします。

削除

自動コマンドを削除するには、定義時と同じコマンドを使用しますが、最後に{command}を省略し、!を使用します。例:
:autocmd! FileWritePre *
これにより、"FileWritePre"イベントの "*"パターンを使用するすべての自動コマンドが削除されます。

一覧表示

現在定義されているすべての自動コマンドを一覧表示するには、次を使用します。
:autocmd
特にファイルタイプの検出を使用すると、リストが非常に長くなる可能性があります。コマンドの一部のみを一覧表示するには、グループ、イベント、および/またはパターンを指定します。たとえば、すべてのBufNewFile自動コマンドを一覧表示するには
:autocmd BufNewFile
パターン "*.c" のすべての自動コマンドを一覧表示するには
:autocmd * *.c
イベントに "*" を使用すると、すべてのイベントが一覧表示されます。cprogramsグループのすべての自動コマンドを一覧表示するには
:autocmd cprograms

グループ

自動コマンドを定義するときに使用される{group}項目は、関連する自動コマンドをグループ化します。たとえば、これにより、特定のグループ内のすべての自動コマンドを削除できます。特定のグループに対して複数の自動コマンドを定義する場合は、":augroup"コマンドを使用します。たとえば、Cプログラムの自動コマンドを定義しましょう。
:augroup cprograms
:  autocmd BufReadPost *.c,*.h :set sw=4 sts=4
:  autocmd BufReadPost *.cpp   :set sw=3 sts=3
:augroup END
これは次と同じです。
:autocmd cprograms BufReadPost *.c,*.h :set sw=4 sts=4
:autocmd cprograms BufReadPost *.cpp   :set sw=3 sts=3
"cprograms" グループ内のすべての自動コマンドを削除するには
:autocmd! cprograms

ネスト

一般に、自動コマンドイベントの結果として実行されるコマンドは、新しいイベントをトリガーしません。FileChangedShellイベントに応答してファイルを読み取っても、たとえば構文を設定する自動コマンドはトリガーされません。イベントをトリガーするには、"++nested"フラグを追加します。
:autocmd FileChangedShell * ++nested  edit

自動コマンドの実行

イベントが発生したかのように見せかけて自動コマンドをトリガーすることができます。これは、1つの自動コマンドに別の自動コマンドをトリガーさせる場合に便利です。例
:autocmd BufReadPost *.new  execute "doautocmd BufReadPost " . expand("<afile>:r")
これは、新しいファイルが編集されたときにトリガーされる自動コマンドを定義します。ファイル名の末尾は ".new" でなければなりません。":execute"コマンドは、式評価を使用して新しいコマンドを作成し、実行します。ファイル "tryout.c.new" を編集すると、実行されるコマンドは次のようになります。
:doautocmd BufReadPost tryout.c
expand()関数は、自動コマンドが実行されたファイル名を表す "<afile>" 引数を受け取り、":r" でファイル名のルートを取得します。
":doautocmd" は現在のバッファで実行されます。":doautoall" コマンドは、すべてのバッファで実行されることを除いて、"doautocmd" と同様に機能します。

ノーマルモードコマンドの使用

自動コマンドによって実行されるコマンドは、コマンドラインコマンドです。ノーマルモードコマンドを使用する場合は、":normal"コマンドを使用できます。例
:autocmd BufReadPost *.log normal G
これは、*.logファイルを編集開始したときに、カーソルをそのファイルの最終行にジャンプさせます。":normal"コマンドの使用は少しトリッキーです。まず、その引数がすべての引数を含む完全なコマンドであることを確認してください。"i"を使って挿入モードに入る場合は、挿入モードから抜けるために<Esc>も必要です。 "/"を使って検索パターンを開始する場合は、それを実行するために<CR>が必要です。":normal"コマンドは、それ以降のすべてのテキストをコマンドとして使用します。したがって、|やそれに続く別のコマンドは使用できません。この問題を回避するには、":normal"コマンドを":execute"コマンドの中に入れます。これにより、印刷できない文字も便利な方法で渡すことができます。例:
:autocmd BufReadPost *.chg execute "normal ONew entry:\<Esc>" |
        \ 1read !date
これは、長いコマンドを複数行に分割するためにバックスラッシュを使用する方法も示しています。これは、Vimスクリプトで使用できます(コマンドラインでは使用できません)。
オートコマンドで、ファイル内を移動し、元の位置に戻るような複雑な処理を行いたい場合は、ファイル上のビューを復元したい場合があります。例については、restore-positionを参照してください。

イベントの無視

オートコマンドをトリガーしたくない場合があります。'eventignore'オプションには、完全に無視されるイベントのリストが含まれています。たとえば、次のコマンドは、ウィンドウの出入りのイベントを無視します。
:set eventignore=WinEnter,WinLeave
すべてのイベントを無視するには、次のコマンドを使用します。
:set eventignore=all
通常の動作に戻すには、'eventignore'を空にします。
:set eventignore=
次の章:usr_41.txt Vimスクリプトを書く
著作権:manual-copyrightを参照してください。vim:tw=78:ts=8:noet:ft=help:norl
メイン
コマンドインデックス
クイックリファレンス