VIM REFERENCE MANUAL by Bram Moolenaar
Vim を使うときのヒントとアイディア *tips*
これは、多くのユーザーにとって便利だろうと思うこの一部です。wiki には
もっと多くの tips があります。http://www.vim.org
ユーザーマニュアルも参照してください。ユーザーマニュアルにはたくさんのtipsが含
まれています|usr_toc.txt|。
C のプログラムを編集する |C-editing|
識別子が使われている場所を検索する |ident-search|
xterm でのスクリーンの切り替え |xterm-screens|
挿入モードでスクロールさせる |scroll-insert|
スムーズにスクロールさせる |scroll-smooth|
ありがちなタイプミスを修正する |type-mistakes|
単語や行の数を数える |count-items|
カーソルの位置を戻す |restore-position|
ファイルをリネームする |rename-files|
複数ファイル中の名前を置換する |change-name|
外部コマンドの実行速度を速くする |speed-up|
便利なマッピング |useful-mappings|
ヘルプファイルを圧縮する |gzip-helpfile|
ウィンドウでシェルコマンドを実行する |shell-window|
16進編集 |hex-editing|
オートコマンドで <> 表記を使う |autocmd-<>|
対応する括弧を強調する |match-parens|
==============================================================================
C のプログラムを編集する *C-editing*
Vim には C のプログラムファイルを編集するのを手助けする機能がたくさんあります。
詳細をジャンプして確認できるようにタグつきで機能のあらましを紹介しましょう。
|usr_29.txt| ユーザーマニュアルの「プログラム内の移動」
|usr_30.txt| ユーザーマニュアルの「プログラムの編集」
|C-indenting| テキストをタイプ中、自動的に行をインデントします。
|=| 数行をインデントし直します。
|format-comments| コメントを自動的にフォーマットします。
|:checkpath| 再帰的にインクルードされるファイルをすべて表示します。
|[i| カーソルの下にある単語と同じものを現在のファイルとイン
クルードされるファイルから探します。
|[_CTRL-I| "[i" でマッチした場所にジャンプします。
|[I| カーソルの下にある単語と同じものを現在のファイルとイン
クルードされるファイルから探し出しその行のリストを表示
します。
|[d| カーソルの下の単語の定義を現在のファイルとインクルード
されるファイルから探します
|CTRL-]| カーソルの下のタグにジャンプします。(例、関数の定義)
|CTRL-T| CTRL-]コマンドの前に戻ります。
|:tselect| マッチしたタグのリストから一つ選びます。
|gd| カーソルの下のローカル変数の宣言にジャンプする。
|gD| カーソルの下のグローバル変数の宣言にジャンプする。
|gf| カーソルの下のファイル名にジャンプする。
|%| 対応する(),{},[],/* */, #if, #else, #endifに移動する。
|[/| 前のコメントが始まる場所に移動する。
|]/| 次のコメントが終わる場所に移動する。
|[#| 前の閉じられていない #if, #ifdef, #else に移動する。
|]#| 次の閉じられていない #else, #endif に移動する。
|[(| 前の閉じられていない '(' に移動する。
|])| 次の閉じられていない ')' に移動する。
|[{| 前の閉じられていない '{' に移動する。
|]}| 次の閉じられていない '}' に移動する。
|v_ab| 「ブロック("[("から"])"まで)」を括弧を含めて選択する。
|v_ib| 「ブロック("[("から"])"まで)の内部」を選択する。
|v_aB| 「ブロック("[{"から"]}"まで)」を括弧を含めて選択する。
|v_iB| 「ブロック("[{"から"]}"まで)の内部」を選択する。
==============================================================================
識別子が使われている場所を検索する *ident-search*
|tags|が関数や変数の定義された場所へのジャンプに使えることはすでにわかりました
が、ときどき関数や変数が使われている場所にジャンプしたいことがあります。これ
は二つの方法で実現することができます:
1. |:grep|を使う方法。この方法はほとんどの Unix システムでうまく動作しますが遅
いですし(全てのファイルを読むため)、一つのディレクトリの中だけしか検索でき
ません。
2. ID ユーティリティを使う方法。この方法は速いですし複数のディレクトリを検索で
きます。この方法は位置を記憶するためにデータベースを使用します。いくつかの
プログラムを新たに入れる必要があります。そして、データベースを最新に保つこ
とが要求されます。
GNU id-tools と Vim を連動させる。
必要なもの:
- The GNU id-toolsがインストールされていること(IDを生成するにはmkidが必要でマ
クロを使うのにlidが必要です)。
- 現在のディレクトリに "ID" と呼ばれる識別子データベースファイルがあること。
シェルコマンド"mkid file1 file2 .."で作成可能です。
次の行を .vimrc に追加してください。
map _u :call ID_search()<Bar>execute "/\\<" . g:word . "\\>"<CR>
map _n :n<Bar>execute "/\\<" . g:word . "\\>"<CR>
map _n :n<Bar>execute "/\\<" . g:word . "\\>"<CR>
function! ID_search()
let g:word = expand("<cword>")
let x = system("lid --key=none ". g:word)
let x = substitute(x, "\n", " ", "g")
execute "next " . x
endfun
let g:word = expand("<cword>")
let x = system("lid --key=none ". g:word)
let x = substitute(x, "\n", " ", "g")
execute "next " . x
endfun
これを使うには、単語上にカーソルを置いて、"_u"とタイプすればvimは単語を含んだ
ファイルを読みこみます。同じファイルで次に単語が出てくるところを検索するには
"n"をタイプします。"_n"で次のファイルに行きます。
この方法は id-utils-3.2 を使って動作を確認しました (id-utlis-3.2 は id-tools
アーカイブの名前です。近くの gnu-ftp-mirror から入手してください。)
[このアイディアはAndreas Kutscheraさんから頂いたものです]
==============================================================================
xterm でのスクリーンの切り替え *xterm-screens* *xterm-save-screen*
(comp.editors で質問に答えて Juergen Weigert 氏が投稿したもの)
:> もう一つの質問は vim を終了させた後にスクリーンがそのまま残っている
:> ことに関してです。例えばいままで見ていた(編集していた)内容がスクリ
:> ーンに残っていますよね。そして前に行った ls などのコマンドの出力が
:> 消えてしまうのです(例えばスクロールバッファからなくなってしまう)。
:> vim や他の vi 風のエディタでもどうにかして前の画面を復元する方法が
:> あるとは思うのですが、どのようにすれば実現できるのかわかりません。
:> 教えていただけると嬉しいです。それでは。
:
:どなたか詳しい方が答えて下さると思います。vim も vi も xterm の設定を
:みて同じことをそれぞれやっていると思うのですが。
これらは必ずしも同じ動作をするとは限りません、というのはこれは termcapと
terminfo の問題であるかもしれないからです。個々のタイプのターミナルの属性を記
述するデータベースには termcap と terminfoという二つのデータベースがあるという
ことを知っておいてください。エントリーが異なっていて、かつ質問にあったプログラ
ムのどれかが termcapを使っていて他のものがterminfo を使っていた場合、違う動作
をすることになりえます。
(|+terminfo| も参照してください)
この問題の場合、^[[?47h と ^[[?47l というコントロールシーケンスが答えになりま
す。これらはxtermのメインスクリーンバッファともう一方のバッファを切り替えるの
に用いられます。簡単に動作させてみるには次のコマンドを打ってみてください、
echo -n "^[[?47h"; vim ... ; echo -n "^[[?47l"
あなたが望む動作はこれかもしれません。 (ここで ^[ は ESC キャラクターを意味します。このあとデータベースではこの記号の代わりに \E を使っていることがわかるで
しょう)
起動時に vim は termcap の ti 変数(terminfo の場合: smcup) の値をecho し、終了
時には te 変数(terminfo の場合: rmcup) の値をターミナルに echo します。という
わけで、これらの二つの変数が上記のコントロールシーケンスを設定する正しい場所で
す。
xterm の termcap エントリー(/etc/termcap にあります) と xterm のterminfo エン
トリー(infocmp -C xterm として入手します)とを比べてみてください。双方に次のよ
うなエントリーが含まれている必要があります。
:te=\E[2J\E[?47l\E8:ti=\E7\E[?47h:
追伸: もしなんらかの違いを見つけた場合、だれかが(システム管理者かな?) termcap
と terminfo データベースを継続的にチェックするようにした方がよいです。
注1: feature.h で定義される FEAT_XTERM_SAVE をつけて Vim を再コンパイルすると
内蔵の xterm は上記の "te" と "ti" エントリーを含むようになります。
注2: スクリーンのスイッチを行わないようにし、termcap の変更も行いたくない場合
次の行を .vimrc に加えてください。
:set t_ti= t_te=
==============================================================================
挿入モードでスクロールを行う *scroll-insert*
挿入モードでスクリーンの外の部分を見たい場合、CTRL-X CTRL-E と CTRL-X CTRL-Y
を使うことでスクリーンをスクロールさせることができます。
|i_CTRL-X_CTRL-E|
これを簡単に行うには次のマッピングをすることができます:
:inoremap <C-E> <C-X><C-E>
:inoremap <C-Y> <C-X><C-Y>
(文字通り入力するには、'<'フラグが'cpoptions'にないことを確認してください):inoremap <C-Y> <C-X><C-Y>
しかしこれを行うとカーソルの上/下の行のテキストをコピーする機能が使えなくなり
ます。
|i_CTRL-E|.
カーソルの回りの前後を常に見渡せるように 'scrolloff' オプションの値を大きい値
に設定するのもよいです。'scrolloff' の値がウィンドウの高さの半分以上に設定さ
れているとカーソルが常にスクリーンの中央にあることになりテキストはカーソルの
上下移動にあわせてスクロールすることになります。
==============================================================================
スムーズにスクロールさせる *scroll-smooth*
もう少しスムーズにスクロールさせたい場合、次のマッピングを使うこともできます:
:map <C-U> <C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y>
:map <C-D> <C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E>
:map <C-D> <C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E>
(文字通り入力するには、'<'フラグが'cpoptions'にないことを確認してください)
==============================================================================
ありがちなタイプミスを修正する *type-mistakes*
しょっちゅう間違ってタイプする単語がいくつかあれば、略記を修正するのに利用しま
しょう。例えば:
:ab teh the
:ab fro for
:ab fro for
==============================================================================
単語や行などの数を数える *count-items*
カレントバッファの中になんらかのパターンがどのくらいの回数現れるのかを数えるに
は、substituteコマンドを使い、実際に置換するのを避けるためにフラグ'n'をつけま
す。報告される数がそのアイテムの数です。例:
:%s/./&/gn 文字
:%s/\i\+/&/gn 単語
:%s/^//n 行
:%s/the/&/gn "the"(どこかしら)
:%s/\<the\>/&/gn "the"(単語一致)
:%s/\i\+/&/gn 単語
:%s/^//n 行
:%s/the/&/gn "the"(どこかしら)
:%s/\<the\>/&/gn "the"(単語一致)
'hlsearch'をリセットするか、":nohlsearch"をしたくなるかもしれません。
マッチが1個もないときにエラーになってほしくなければフラグ'e'をつけます。
別の方法としては、ビジュアルモードで|v_g_CTRL-G|を使います。
複数のファイルから検索したければ|:vimgrep|を使います。
これは'modifiable'オプションがオフのときは機能しません。代わりにビジュアルモー
ドで|v_g_CTRL-G|を使ってください。
*count-bytes*
バイト数を数えるにはこれを使ってください。
文字列を選択してください(ブロック選択も使えます)
"y"でコピーしてください
そして、strlen()を使います
:echo strlen(@")
改行は1バイトとして数えられます。==============================================================================
カーソルの位置を戻す *restore-position*
ときにはファイルのどこかに変更を加えて、テキストをスクロールすることなくカーソ
ルを元の位置に戻すようなマッピングを書きたくなることがあります。ファイルに書い
た日付を変更する例をあげます:
:map <F2> msHmtgg/Last [cC]hange:\s*/e+1<CR>"_D"=strftime("%Y %b %d")<CR>p'tzt`s
位置を記憶する:
ms 's'マークにカーソルの位置を記録します
H ウィンドウに表示された最初の行に移動します
mt その行を't'マークに記録します
位置を元に戻す:
't 先程のウィンドウに表示された最初の行に移動します
zt その行がウィンドウの最初に表示されるようにスクロールします
`s 最初の位置に戻ります
より高度なことについては |winsaveview()| と |winrestview()| を参照してくださ
い。
==============================================================================
ファイルをリネームする *rename-files*
例えば以下のようなファイルを含むディレクトリがあるとします(ディレクトリはラン
ダムに選び出したものです :-):
buffer.c
charset.c
digraph.c
...
そして *.c を *.bla にリネームしたい場合次のようなコマンドを実行します:
$ vim
:r !ls *.c
:%s/\(.*\).c/mv & \1.bla
:w !sh
:q!
:r !ls *.c
:%s/\(.*\).c/mv & \1.bla
:w !sh
:q!
==============================================================================
複数ファイル中の名前を置換する *change-name*
スクリプトファイルを使って複数ファイル中の名前を置換する例です:
以下のように置換コマンドと :update コマンドを含む "subs.vim" というファ
イルを作成します:
:%s/Jones/Smith/g
:%s/Allen/Peter/g
:update
:%s/Allen/Peter/g
:update
Vim で置換したい全ファイルを開き、各引数に対してこのスクリプトを実行
します:
vim *.let
argdo source subs.vim
argdo source subs.vim
|:argdo| も参照。
==============================================================================
外部コマンドの実行をスピードアップする *speed-up*
いくつかの状況では外部コマンドの実行速度が非常に遅くなる場合があります。これは
Unix でのワイルドカード展開が行われた場合もそうです。いくつかのスピードアップ
する方法を紹介しましょう。
もし .cshrc (もしくは他のファイル、使っているシェルによります)が非常に長いなら
ばそれを対話的に使う部分とそうでない用途(セカンダリーシェルとよく呼ばれます)の
部分にわけるべきです。Vim から ":!ls" のようなコマンドを実行する場合、対話的に
行う必要はありませんよね(例えば、プロンプトを出させたり)。次の行の後にそれらを
おくようにしてください。
if ($?prompt == 0) then
exit 0
endif
exit 0
endif
もう一つの方法は 'shell' オプションに "-f" フラグをつける方法です、例えば:
:set shell=csh\ -f
(オプションの中にスペースを含めるにはバックスラッシュが必要です)
こうすると csh が .cshrc ファイルを読み込まないようにすることができます。しか
しこうすることでなんらかが動作しない場合もあるかもしれません。
==============================================================================
便利なマッピング *useful-mappings*
ここでいくつか好んで使われるマッピングを紹介します。
*map-backtick*
:map ' `
シングル引用符の動作をバック引用符の動作のようにします。カーソルをマークがある行の最初の非空白文字に移動させるのではなく、マークがある桁位置に移動させます。
*emacs-keys*
コマンドラインでのキーバインドを Emacs スタイルにします:
" 行頭へ移動
:cnoremap <C-A> <Home>
" 一文字戻る
:cnoremap <C-B> <Left>
" カーソルの下の文字を削除
:cnoremap <C-D> <Del>
" 行末へ移動
:cnoremap <C-E> <End>
" 一文字進む
:cnoremap <C-F> <Right>
" コマンドライン履歴を一つ進む
:cnoremap <C-N> <Down>
" コマンドライン履歴を一つ戻る
:cnoremap <C-P> <Up>
" 前の単語へ移動
:cnoremap <Esc><C-B> <S-Left>
" 次の単語へ移動
:cnoremap <Esc><C-F> <S-Right>
:cnoremap <C-A> <Home>
" 一文字戻る
:cnoremap <C-B> <Left>
" カーソルの下の文字を削除
:cnoremap <C-D> <Del>
" 行末へ移動
:cnoremap <C-E> <End>
" 一文字進む
:cnoremap <C-F> <Right>
" コマンドライン履歴を一つ進む
:cnoremap <C-N> <Down>
" コマンドライン履歴を一つ戻る
:cnoremap <C-P> <Up>
" 前の単語へ移動
:cnoremap <Esc><C-B> <S-Left>
" 次の単語へ移動
:cnoremap <Esc><C-F> <S-Right>
NOTE: これを利用するには 'cpoptions' から '<' フラグを外しておく必要がありま
す。|<>|
*format-bullet-list*
このマッピングはブレットリストのフォーマットを整えるものです。それぞれのリスト
のエントリーの前後に空行がある必要があります。式が使われているのはマッピングを
部分的に解説するコメントを入れるためです。
:let m = ":map _f :set ai<CR>" " 'autoindent' をセット
:let m = m . "{O<Esc>" " アイテムの上に空行を挿入
:let m = m . "}{)^W" " ブレットの後のテキストに移動
:let m = m . "i <CR> <Esc>" " インデントの為のスペースを挿入
:let m = m . "gq}" " ブレットの後のテキストを整形
:let m = m . "{dd" " 空行を削除
:let m = m . "5lDJ" " ブレットの後にテキストを置く
:execute m |" マッピングを決定する
:let m = m . "{O<Esc>" " アイテムの上に空行を挿入
:let m = m . "}{)^W" " ブレットの後のテキストに移動
:let m = m . "i <CR> <Esc>" " インデントの為のスペースを挿入
:let m = m . "gq}" " ブレットの後のテキストを整形
:let m = m . "{dd" " 空行を削除
:let m = m . "5lDJ" " ブレットの後にテキストを置く
:execute m |" マッピングを決定する
(<> 表記法 |<>|。これらは文字どおりにタイプするということに注意してください。
^W は "^" "W" で CTRL-W ではありません。'cpoptions' に '<' がなければ Vim にコ
ピー/ペーストすることができますよ。)
最後のコメントは |" で始まっていることに注意してください、これは ":execute" コ
マンドが直接のコメントを受け付けないからです。
また 'textwidth' を 0 以外の値にしておく必要があります。例えば:
set tw=70
最初の行からインデントすることになりますが次のようなマッピングでも同じことがで
きます (Note: このマッピングは多くのスペースを含む長い一つの行です):
:map _f :set ai<CR>}{a <Esc>WWmmkD`mi<CR><Esc>kkddpJgq}'mJO<Esc>j
*collapse*
これら2つのマッピングは空行(;b)もしくは空白文字のみからなる行(;n)の連続を1行に
します。
:map ;b GoZ<Esc>:g/^$/.,/./-j<CR>Gdd
:map ;n GoZ<Esc>:g/^[ <Tab>]*$/.,/[^ <Tab>]/-j<CR>Gdd
:map ;n GoZ<Esc>:g/^[ <Tab>]*$/.,/[^ <Tab>]/-j<CR>Gdd
==============================================================================
ヘルプファイルを圧縮する *gzip-helpfile*
ディスクスペースに空きがあまりない人はヘルプファイルを圧縮することができます。
圧縮した後でもヘルプファイルを閲覧することはできます。ヘルプファイルへのアクセ
スは少し遅くなります。また "gzip" プログラムが必要です。
(1) すべてのヘルプファイルを圧縮するには: "gzip doc/*.txt"
(2) "doc/tags" を編集して ".txt" を ".txt.gz" にします。
:%s=\(\t.*\.txt\)\t=\1.gz\t=
(3) 次の行を vimrc に追加します:
set helpfile={dirname}/help.txt/gz
{dirname}はヘルプファイルのある場所です。|gzip|プラグインがファイルの解凍をし
ます。それともし圧縮された "doc" ディレクトリと同じ場所に他のVim ファイルがな
い場合、$VIMRUNTIME が他の Vim ファイルがある場所になるようにしておかなければ
なりません。|$VIMRUNTIME|も参照してください。
==============================================================================
ウィンドウでシェルコマンドを実行する *shell-window*
Vim の中のウィンドウでシェルを起動できるかという質問がいままでに何度かありまし
た。答えは、できないです。もしこれを実装しようとすればかなりおおくのコードを加
えなければなりません、これが実装しない理由です。つまるところ、Vim はエディター
なのです、エディターとしてではない作業を実行するようには考えられていません。し
かしながら、同じようなことを実行するには "splitvt" プログラムを使って端末のス
クリーンもしくはウィンドウの表示を分割することができます。このプログラムはたぶ
んどこかの ftp サーバーで見つけることができると思います。このプログラムに詳し
いのは Sam Lantinga <slouken@cs.ucdavis.edu> です。もう一つの方法は "window"
コマンドを利用する方法で、このコマンドは BSD Unix システムにあります。このコマ
ンドは複数のウィンドウをオーバーラップさせることができます。それか "screen" プ
ログラムを使うかです。これは www.uni-erlangen.de で見つけることができ、このプ
ログラムでウィンドウの積み重ねをすることができます。
==============================================================================
16進編集 *hex-editing* *using-xxd*
ユーザーマニュアルの|23.4|を参照してください。
もしそのファイルがバイナリファイル特有の拡張子(exe、binなど)をしているときは、
あなたの<.vimrc>に次のオートコマンドを加えることで、変換の過程を自動化しておく
こともできます。"*.bin"をあなたの編集したいファイルの拡張子の、カンマで区切ら
れたリストに変えてください:
" vim -b : edit binary using xxd-format!
augroup Binary
au!
au BufReadPre *.bin let &bin=1
au BufReadPost *.bin if &bin | %!xxd
au BufReadPost *.bin set ft=xxd | endif
au BufWritePre *.bin if &bin | %!xxd -r
au BufWritePre *.bin endif
au BufWritePost *.bin if &bin | %!xxd
au BufWritePost *.bin set nomod | endif
augroup END
augroup Binary
au!
au BufReadPre *.bin let &bin=1
au BufReadPost *.bin if &bin | %!xxd
au BufReadPost *.bin set ft=xxd | endif
au BufWritePre *.bin if &bin | %!xxd -r
au BufWritePre *.bin endif
au BufWritePost *.bin if &bin | %!xxd
au BufWritePost *.bin set nomod | endif
augroup END
==============================================================================
オートコマンドで <> 表記を使う *autocmd-<>*
<> 表記は :autocmd の引数として使っても正しく解釈されません。特殊な文字を入力
するのを避けるには、<> 表記をするための自己破壊的なマッピング行ってそれからオー
トコマンドの中でそのマッピングを呼び出すことで実現することもできます。例:
*map-self-destroy*
" この方法はファイル名を自動的にメニューリストに追加するものです。
" 自己破壊的なマッピングを使っています!
" 1. ファイル名に含まれる 'dots' を \. に変更するためにバッファーの一つの
" 行を使います。
" 2. それをレジスター '"' に格納します。
" 3. その名前をバッファーメニューリストに追加します。
" 警告: この方法にはいくらか副作用があります。現在のレジスターの内容を上書
" きしたり "i" コマンドへのマッピングをすべて削除してしまったりします。
"
autocmd BufNewFile,BufReadPre * nmap i :nunmap i<CR>O<C-R>%<Esc>:.g/\./s/\./\\./g<CR>0"9y$u:menu Buffers.<C-R>9 :buffer <C-R>%<C-V><CR><CR>
autocmd BufNewFile,BufReadPre * normal i
" 自己破壊的なマッピングを使っています!
" 1. ファイル名に含まれる 'dots' を \. に変更するためにバッファーの一つの
" 行を使います。
" 2. それをレジスター '"' に格納します。
" 3. その名前をバッファーメニューリストに追加します。
" 警告: この方法にはいくらか副作用があります。現在のレジスターの内容を上書
" きしたり "i" コマンドへのマッピングをすべて削除してしまったりします。
"
autocmd BufNewFile,BufReadPre * nmap i :nunmap i<CR>O<C-R>%<Esc>:.g/\./s/\./\\./g<CR>0"9y$u:menu Buffers.<C-R>9 :buffer <C-R>%<C-V><CR><CR>
autocmd BufNewFile,BufReadPre * normal i
もう一つのよりよい方法は ":execute" コマンドを使う方法です。文字列の中ではバッ
クスラッシュを前置することで <> 表記が使えます。それまであったバックスラッシュ
は \\ という風に2回重ねるのを忘れないでください。また '"' の前にもバックスラッ
シュを前置しなければなりません。
autocmd BufNewFile,BufReadPre * exe "normal O\<C-R>%\<Esc>:.g/\\./s/\\./\\\\./g\<CR>0\"9y$u:menu Buffers.\<C-R>9 :buffer \<C-R>%\<C-V>\<CR>\<CR>"
実際のバッファメニューではユーザー定義関数を使うべきですが(|:function|を参照)、
そうすると<>表記は使いませんので、ここでの例としてそれを使うのは不適切です。
==============================================================================
対応する括弧を強調する *match-parens*
この例はいくつかの高度なトリックを紹介しています。
- 自動コマンドイベント|CursorMoved|の使い方
- |searchpairpos()|を使って対応する括弧を見つける方法
- |synID()|を使ってカーソルが文字列やコメントの中にあるかを判定する方法
- |:match|を使ってなにかを強調する方法
- |pattern|を使ってファイルの特定の位置にマッチさせる方法
これはスクリプトローカル変数を使っているので、Vimスクリプトファイル中に書かな
ければなりません。カーソルが文字列やコメントの中にないならば、文字列やコメント
はスキップして検索します。構文強調が有効になっている必要があります。
これより若干高度なバージョンがプラグイン|matchparen|の中で使われています。
let s:paren_hl_on = 0
function s:Highlight_Matching_Paren()
if s:paren_hl_on
match none
let s:paren_hl_on = 0
endif
function s:Highlight_Matching_Paren()
if s:paren_hl_on
match none
let s:paren_hl_on = 0
endif
let c_lnum = line('.')
let c_col = col('.')
let c_col = col('.')
let c = getline(c_lnum)[c_col - 1]
let plist = split(&matchpairs, ':\|,')
let i = index(plist, c)
if i < 0
return
endif
if i % 2 == 0
let s_flags = 'nW'
let c2 = plist[i + 1]
else
let s_flags = 'nbW'
let c2 = c
let c = plist[i - 1]
endif
if c == '['
let c = '\['
let c2 = '\]'
endif
let s_skip ='synIDattr(synID(line("."), col("."), 0), "name") ' .
\ '=~? "string\\|comment"'
execute 'if' s_skip '| let s_skip = 0 | endif'
let plist = split(&matchpairs, ':\|,')
let i = index(plist, c)
if i < 0
return
endif
if i % 2 == 0
let s_flags = 'nW'
let c2 = plist[i + 1]
else
let s_flags = 'nbW'
let c2 = c
let c = plist[i - 1]
endif
if c == '['
let c = '\['
let c2 = '\]'
endif
let s_skip ='synIDattr(synID(line("."), col("."), 0), "name") ' .
\ '=~? "string\\|comment"'
execute 'if' s_skip '| let s_skip = 0 | endif'
let [m_lnum, m_col] = searchpairpos(c, '', c2, s_flags, s_skip)
if m_lnum > 0 && m_lnum >= line('w0') && m_lnum <= line('w$')
exe 'match Search /\(\%' . c_lnum . 'l\%' . c_col .
\ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
let s:paren_hl_on = 1
endif
endfunction
exe 'match Search /\(\%' . c_lnum . 'l\%' . c_col .
\ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
let s:paren_hl_on = 1
endif
endfunction
autocmd CursorMoved,CursorMovedI * call s:Highlight_Matching_Paren()
autocmd InsertEnter * match none
autocmd InsertEnter * match none
vim:tw=78:ts=8:ft=help:norl: