vim-jp / vimdoc-ja / usr_40

usr_40 - Vimドキュメント

メインヘルプファイルに戻る
usr_40.txt    For Vim バージョン 8.2.  Last change: 2020 Sep 02

                     VIM USER MANUAL - by Bram Moolenaar

                             新しいコマンドを作る


Vim は拡張可能なエディタです。よく使う操作を一つにまとめて新しいコマンドを作成
したり、既存のコマンドを再定義したりできます。自動コマンドを使うと、コマンドを
自動的に実行できます。

40.1  キーマッピング
40.2  コマンドラインコマンドを定義する
40.3  自動コマンド

次章: usr_41.txt  Vim script 書法
前章: usr_32.txt  undo ツリー
目次: usr_toc.txt

==============================================================================
40.1  キーマッピング

05.3 で簡単なマップを説明しました。マップの原理は、キー操作を他のキー操作に
変換するというものです。単純ですが強力な仕組みです。
典型的な使い方は、一つのキーを複数のキーにマップする方法です。ファンクション
キー (<F1>以外) には機能が割り当てられていないので、それらのキーを使うとよいで
しょう。例:

        :map <F2> GoDate: <Esc>:read !date<CR>kJ

このマップでは三つのモードが使われています。"G" で最後の行にジャンプし、"o" で
新しい行を開いて挿入モードを開始、"Date: " というテキストを入力してから <Esc>
で挿入モードを抜けます。
特殊キーを <> で囲んで表記していますが、これは括弧表記というものです。特殊キー
を押すのではなく、見たまま文字どおり入力してください。この表記を使ったマップは
読むのが簡単で、そのままコピー&ペーストして使うことができます。
さて、":" でコマンドラインモードに入ります。":read !date" コマンドは、"date"
コマンドの出力を読み込んで、現在行の下に追加します。<CR> は ":read" コマンドを
実行するために必要です。
この時点で、テキストは次のようになっています:

        Date: 
        Fri Jun 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 プログラムのブロック ({}で囲まれたテキスト) を削除
できるように、あるいは、y<F7> でブロックをヤンクできるようにしたい場合は、<F7>
をマップしてプログラムブロックを選択できるようにする必要があります。次のように
します:

        :omap <F7> a{

オペレータ待機モードで <F7> を押すと "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" で定義されたマップには空白が使われます。空白の場
合はノーマルモードとビジュアルモードで使えます。
この一覧を見れば、<> 表記で書いた特殊キーが正しく認識されているかを確認できま
す (カラー表示がサポートされている場合に限る)。例えば、<Esc> が色付きで表示さ
れていれば、それはエスケープ文字です。他のテキストと同じ色で表示されている場合
は、それは "<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

これで、マップされた "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         コマンドライン

例えば、ビジュアルモードを除き、ノーマルモードとオペレータ待機モードだけでマッ
プを定義したいような場合は次のトリックが使えます。最初に三つのモードでマップを
定義し、ビジュアルモードのマップだけを削除します:

        :map <C-A> /---><CR>
        :vunmap <C-A>

"<C-A>" は CTRL-A キーとして解釈されます。

すべてのマップを削除するには :mapclear コマンドを使います。他のコマンドと同
様に、これにもモード別のコマンドが用意されています。マップの削除はアンドゥでき
ないので注意してください。


特殊文字
--------

":map" コマンドの後ろには他のコマンドを続けて書くことができます。その場合は |
文字でコマンドを区切ります。そのため、マップの中では | 文字が使えません。この
文字を使いたい場合は <Bar> (5文字) を使ってください。例:

        :map <F8> :write <Bar> !checkin %:S<CR>

同じ問題は ":unmap" コマンドにもあります。":unmap" の場合はさらに末尾のスペー
スにも注意しなければなりません。以下の二つのコマンドは動作が違います:

        :unmap a | unmap b
        :unmap a| unmap b

一つ目のコマンドは "a " (スペース付き) のマップを削除します。

マップの中でスペースを使いたい場合は <Space> (7文字) を使ってください:

        :map <Space> W

このマップはスペースキーを押すと、次の単語 (空白区切り) に移動します。

マップコマンドの末尾にはコメントを付けられません。なぜなら、" 文字はマップの一
部として処理されてしまうからです。代わりに |" を使ってください。これは、新しい
空のコマンドを開始して、そのコマンドにコメントをつけます。例:

        :map <Space> W|     " 次の単語に移動するのにスペースバーを使う


マップと短縮入力
----------------

挿入モードのマップは短縮入力とよく似ています。引数は同じ方法で処理されます。主
な違いは実行されるタイミングです。短縮入力は単語の後で単語以外の文字を入力した
ときに実行されます。マップはマップ文字列の最後の文字を入力したときに実行されま
す。
違いは他にもあります。短縮入力では入力した文字がすぐに挿入されます。短縮入力が
実行されると元の文字が削除されて指定された文字列に置換されます。マップされた文
字を入力したときは最後の文字を入力してマップが実行されるまで何も挿入されませ
ん。'showcmd' オプションがオンに設定されている場合は、入力途中の文字がウィンド
ウ下部に表示されます。
マップがあいまいな場合は少し違う動作になります。例えば、次の二つのマップがある
とき:

        :imap aa foo
        :imap aaa bar

"aa" と入力した時点では、一つ目のマップを適用すべきか、それとも二つ目のマップ
を使うべきか、判断できません。その場合は、他の文字が入力されるまで待機状態にな
ります。"a" を入力すると二つ目のマップが適用されて "bar" が挿入されます。他の
文字、例えばスペース、を入力すると一つ目のマップが適用されて "foo" が挿入さ
れ、さらにスペースが挿入されます。


さらに...
---------

<script> キーワードを使うと、スクリプトローカルなマップを定義できます。