Up: 目次   [Index]


さまざまな Tips

*tips.txt*      For Vim バージョン 8.1.  Last change: 2009 Nov 07


		  VIMリファレンスマニュアル	  by Bram Moolenaar

Vim を使ふときのヒントとアイデア

これは、多くのユーザーにとつて便利だらうと思ふことの一部です。wiki にはもつと多くの tips があります。http://www.vim.org

ユーザーマニュアルも參照してください。ユーザーマニュアルにはたくさんの tips が含まれてゐます |usr_toc.txt|。

|C-editing|C のプログラムを編輯する
|ident-search|識別子が使はれてゐる場所を檢索する
|xterm-screens|xterm でのスクリーンの切り替へ
|scroll-insert|插入モードでスクロールを行ふ
|scroll-smooth|スムーズにスクロールさせる
|type-mistakes|ありがちなタイプミスを修正する
|count-items|單語や行などの數を數へる
|restore-position|カーソルの位置を戾す
|rename-files|ファイルをリネームする
|change-name|複數ファイル中の名前を置換する
|speed-up|外部コマンドの實行速度を速くする
|useful-mappings|便利なマッピング
|gzip-helpfile|ヘルプファイルを壓縮する
|shell-window|ウィンドウでシェルコマンドを實行する
|hex-editing|バイナリ編輯
|autocmd-<>|自動コマンドで <> 表記を使ふ
|match-parens|對應する括弧を强調する

C のプログラムを編輯する

Vim には C のプログラムファイルを編輯するのを手助けする機能がたくさんあります。詳細をジャンプして確認できるやうにタグつきで機能のあらましを紹介しませう。

|usr_29.txt|ユーザーマニュアルの「プログラム內の移動」
|usr_30.txt|ユーザーマニュアルの「プログラムの編輯」
|C-indenting|テキストをタイプ中、自動的に行をインデントします。
|=|數行をインデントし直します。
|format-comments|コメントを自動的にフォーマットします。
|:checkpath|再歸的にインクルードされるファイルをすべて表示します。
|[i|カーソルの下にある單語と同じものを現在のファイルとインクルードされるファイルから探します。
|[_CTRL-I|"[i" でマッチした場所にジャンプします。
|[I|カーソルの下にある單語と同じものを現在のファイルとインクルードされるファイルから探し出しその行のリストを表示します。
|[d|カーソルの下の單語の定義を現在のファイルとインクルードされるファイルから探します
|CTRL-]|カーソルの下のタグにジャンプします。(例、函數の定義)
|CTRL-T|CTRL-] コマンドの前に戾ります。
|:tselect|マッチしたタグのリストから 1 つ選びます。
|gd|カーソルの下のローカル變數の宣言にジャンプする。
|gD|カーソルの下のグローバル變數の宣言にジャンプする。
|gf|カーソルの下のファイル名にジャンプする。
|%|對應する (), {}, [], /* */, #if, #else, #endif に移動する。
|[/|前のコメントが始まる場所に移動する。
|]/|次のコメントが終はる場所に移動する。
|[#|前の閉ぢられてゐない #if, #ifdef, #else に移動する。
|]#|次の閉ぢられてゐない #else, #endif に移動する。
|[(|前の閉ぢられてゐない ’(’ に移動する。
|])|次の閉ぢられてゐない ’)’ に移動する。
|[{|前の閉ぢられてゐない ’{’ に移動する。
|]}|次の閉ぢられてゐない ’}’ に移動する。
|v_ab|「ブロック("[("から"])"まで)」を括弧を含めて選擇する。
|v_ib|「ブロック("[("から"])"まで)の內部」を選擇する。
|v_aB|「ブロック("[{"から"]}"まで)」を括弧を含めて選擇する。
|v_iB|「ブロック("[{"から"]}"まで)の內部」を選擇する。

識別子が使はれてゐる場所を檢索する

|tags| が函數や變數の定義された場所へのジャンプに使へることはすでにわかりましたが、ときどき函數や變數が使はれてゐる場所にジャンプしたいことがあります。これは 2 つの方法で實現することができます:

  1. |:grep| を使ふ方法。この方法はほとんどの Unix システムでうまく動作しますが遲いですし (全てのファイルを讀むため)、1 つのディレクトリの中だけしか檢索できません。
  2. ID ユーティリティを使ふ方法。この方法は速いですし複數のディレクトリを檢索できます。この方法は位置を記憶するためにデータベースを使用します。いくつかのプログラムを新たに入れる必要があります。そして、データベースを最新に保つことが要求されます。

GNU id-tools と Vim を連動させる。

必要なもの:

次の行を .vimrc に追加してください。

map _u :call ID_search()<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

これを使ふには、單語上にカーソルを置いて、"_u" とタイプすれば Vim は單語を含んだファイルを讀みこみます。同じファイルで次に單語が出てくるところを檢索するには "n" をタイプします。"_n" で次のファイルに行きます。

この方法は id-utils-3.2 を使つて動作を確認しました (id-utlis-3.2 は id-tools アーカイブの名前です。近くの gnu-ftp-mirror から入手してください。)

[このアイデアは Andreas Kutschera さんから頂いたものです]

xterm でのスクリーンの切り替へ

(comp.editors で質問に答へて Juergen Weigert 氏が投稿したもの)

:> もう 1 つの質問は Vim を終了させた後にスクリーンがそのまま殘つてゐることに關してです。例へばいままで見てゐた (編輯していた) 內容がスクリーンに殘つてゐますよね。そして前に行つた ls などのコマンドの出力が消えてしまふのです(例へばスクロールバッファからなくなつてしまふ)。Vim や他の vi 風のエディタでもどうにかして前の畫面を復元する方法があるとは思ふのですが、どのやうにすれば實現できるのかわかりません。敎へていただけると嬉しいです。それでは。

:どなたか詳しい方が答へて下さると思ひます。Vim も vi も xterm の設定をみて同じことをそれぞれやつてゐると思ふのですが。

これらは必ずしも同じ動作をするとは限りません、といふのはこれは termcap と terminfo の問題であるかもしれないからです。個々のタイプのターミナルの屬性を記述するデータベースには termcap と terminfo といふ 2 つのデータベースがあるといふことを知つておいてください。エントリが異なつてゐて、かつ質問にあつたプログラムのどれかが 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 します。といふわけで、これらの 2 つの變數が上記のコントロールシーケンスを設定する正しい場所です。

xterm の termcap エントリ (/etc/termcap にあります) と xterm の terminfo エントリ (infocmp -C xterm として入手します) とを比べてみてください。雙方に次のやうなエントリが含まれてゐる必要があります。

:te=\E[2J\E[?47l\E8:ti=\E7\E[?47h:

追伸:
もしなんらかの違ひを見つけた場合、だれかが (システム管理者かな?) termcap と terminfo データベースを繼續的にチェックするやうにした方がよいです。

Note1:
feature.h で定義される FEAT_XTERM_SAVE をつけて Vim を再コンパイルすると內藏の xterm は上記の "te" と "ti" エントリを含むやうになります。

Note2:
スクリーンのスイッチを行はないやうにし、termcap の變更も行ひたくない場合次の行を .vimrc に加へてください。

:set t_ti= t_te=

插入モードでスクロールを行ふ

插入モードでスクリーンの外の部分を見たい場合、CTRL-X CTRL-ECTRL-X CTRL-Y を使ふことでスクリーンをスクロールさせることができます。|i_CTRL-X_CTRL-E|

これを簡單に行ふには次のマッピングをすることができます:

:inoremap <C-E> <C-X><C-E>
:inoremap <C-Y> <C-X><C-Y>

(文字通り入力するには、’<’ フラグが ’cpoptions’ にないことを確認してください) しかしこれを行ふとカーソルの上/下の行のテキストをコピーする機能が使へなくなります。|i_CTRL-E|.

カーソルの周りの前後を常に見渡せるやうに ’scrolloff’ オプションの値を大きい値に設定するのもよいです。’scrolloff’ の値がウィンドウの高さの半分以上に設定されてゐるとカーソルが常にスクリーンの中央にあることになりテキストはカーソルの上下移動にあはせてスクロールすることになります。

スムーズにスクロールさせる

もう少しスムーズにスクロールさせたい場合、次のマッピングを使ふこともできます:

: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>

(文字通り入力するには、’<’ フラグが ’cpoptions’ にないことを確認してください)

ありがちなタイプミスを修正する

しよつちゆう閒違つてタイプする單語がいくつかあれば、短縮入力を修正するのに利用しませう。例へば:

:ab teh the
:ab fro for

單語や行などの數を數へる

カレントバッファの中になんらかのパターンがどのくらゐの回數現れるのかを數へるには、substitute コマンドを使ひ、實際に置換するのを避けるためにフラグ ’n’ をつけます。報告される數がそのアイテムの數です。例:

:%s/./&/gn文字
:%s/\i\+/&/gn單語
:%s/^//n
:%s/the/&/gn"the" (どこかしら)
:%s/\<the\>/&/gn"the" (單語一致)

’hlsearch’ をリセットするか、":nohlsearch" をしたくなるかもしれません。マッチが1個もないときにエラーになつてほしくなければフラグ ’e’ をつけます。

別の方法としては、ビジュアルモードで |v_g_CTRL-G| を使ひます。

複數のファイルから檢索したければ |:vimgrep| を使ひます。

バイト數を數へるにはこれを使つてください。

文字列を選擇してください (ブロック選擇も使へます)
"y" でコピーしてください
そして、strlen() を使ひます

:echo strlen(@")

改行は 1 バイトとして數へられます。

カーソルの位置を戾す

ときにはファイルのどこかに變更を加へて、テキストをスクロールすることなくカーソルを元の位置に戾すやうなマッピングを書きたくなることがあります。ファイルに書いた日附を變更する例をあげます:

: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()| を參照してください。

ファイルをリネームする

例へば以下のやうなファイルを含むディレクトリがあるとします(ディレクトリはランダムに選び出したものです :-):

 buffer.c
 charset.c
 digraph.c
 ...

そして *.c を *.bla にリネームしたい場合次のやうなコマンドを實行します:

$ vim
:r !ls *.c
:%s/\(.*\).c/mv & \1.bla
:w !sh
:q!

複數ファイル中の名前を置換する

スクリプトファイルを使つて複數ファイル中の名前を置換する例です:

以下のやうに置換コマンドと :update コマンドを含む "subs.vim" といふファイルを作成します:

:%s/Jones/Smith/g
:%s/Allen/Peter/g
:update

Vim で置換したい全ファイルを開き、各引數に對してこのスクリプトを實行します:

vim *.let
argdo source subs.vim

|:argdo| も參照。

外部コマンドの實行速度を速くする

いくつかの狀況では外部コマンドの實行速度が非常に遲くなる場合があります。これは Unix でのワイルドカード展開が行はれた場合もさうです。いくつかのスピードアップする方法を紹介しませう。

もし .cshrc (もしくは他のファイル、使つてゐるシェルによります) が非常に長いならばそれを對話的に使ふ部分とさうでない用途 (セカンダリーシェルとよく呼ばれます) の部分にわけるべきです。Vim から ":!ls" のやうなコマンドを實行する場合、對話的に行ふ必要はありませんよね (例へば、プロンプトを出させたり)。次の行の後にそれらをおくやうにしてください。

if ($?prompt == 0) then
    exit 0
endif

もう 1 つの方法は ’shell’ オプションに "-f" フラグをつける方法です、例へば:

:set shell=csh\ -f

(オプションの中にスペースを含めるにはバックスラッシュが必要です)

かうすると csh が .cshrc ファイルを讀み込まないやうにすることができます。しかしかうすることでなんらかが動作しない場合もあるかもしれません。

便利なマッピング

ここでいくつか好んで使はれるマッピングを紹介します。

:map ' `

シングル引用符の動作をバック引用符の動作のやうにします。カーソルをマークがある行の最初の非空白文字に移動させるのではなく、マークがある桁位置に移動させます。

コマンドラインでのキーバインドを Emacs スタイルにします:

" 行頭へ移動
:cnoremap <C-A>     <Home>
" 一文字戾る
:cnoremap <C-B>     <Left>
" カーソルの下の文字を削除
:cnoremap <C-D>     <Del>
" 行末へ移動
:cnoremap <C-E>     <End>
" 一文字進む
:cnoremap <C-F>     <Right>
" コマンドライン履歷を 1 つ進む
:cnoremap <C-N>     <Down>
" コマンドライン履歷を 1 つ戾る
:cnoremap <C-P>     <Up>
" 前の單語へ移動
:cnoremap <Esc><C-B>    <S-Left>
" 次の單語へ移動
:cnoremap <Esc><C-F>    <S-Right>

Note:
これを利用するには ’cpoptions’ から ’<’ フラグを外しておく必要があります。|<>|

このマッピングはブレットリストのフォーマットを整へるものです。それぞれのリストのエントリの前後に空行がある必要があります。式が使はれてゐるのはマッピングを部分的に解說するコメントを入れるためです。

: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                           |" マッピングを決定する

(<> 表記法 |<>|。これらは文字どほりにタイプするといふことに注意してください。^W は "^" "W" で CTRL-W ではありません。’cpoptions’ に ’<’ がなければ Vim にコピー/ペーストすることができますよ。)

最後のコメントは |" で始まつてゐることに注意してください、これは ":execute" コマンドが直接のコメントを受け付けないからです。

また ’textwidth’ を 0 以外の値にしておく必要があります。例へば:

:set tw=70

最初の行からインデントすることになりますが次のやうなマッピングでも同じことができます (Note: このマッピングは多くのスペースを含む長い 1 つの行です):

       :map _f :set ai<CR>}{a                               <Esc>WWmmkD`mi<CR><Esc>kkddpJgq}'mJO<Esc>j

補足:
「タブ幅を 8、端末の幅を 80 桁にして表示すると、:map と <Esc> の行頭が揃ふ」といふお話しらしいけど、タブ嫌ひやねん。

これら 2 つのマッピングは空行 (;b) もしくは空白文字のみからなる行 (;n) の連續を 1 行にします。

:map ;b   GoZ<Esc>:g/^$/.,/./-j<CR>Gdd
:map ;n   GoZ<Esc>:g/^[ <Tab>]*$/.,/[^ <Tab>]/-j<CR>Gdd

ヘルプファイルを壓縮する

ディスクスペースに空きがあまりない人はヘルプファイルを壓縮することができます。壓縮した後でもヘルプファイルを閱覽することはできます。ヘルプファイルへのアクセスは少し遲くなります。また "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| も參照してください。

ウィンドウでシェルコマンドを實行する

|terminal| を參照。

別の方法は、"splitvt" プログラムを使つて端末のスクリーンもしくはウィンドウの表示を分割するこです。このプログラムはたぶんどこかの ftp サーバーで見つけることができると思ひます。このプログラムに詳しいのは Sam Lantinga <slouken@cs.ucdavis.edu> です。

また別の方法は "window" コマンドを利用する方法で、このコマンドは BSD Unix システムにあります。このコマンドは複數のウィンドウをオーバーラップさせることができます。それか "screen" プログラムを使ふかです。これは www.uni-erlangen.de で見つけることができ、このプログラムでウィンドウの積み重ねをすることができます。

バイナリ編輯

ユーザーマニュアルの |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

自動コマンドで <> 表記を使ふ

<> 表記は :autocmd の引數として使つても正しく解釋されません。特殊な文字を入力するのを避けるには、<> 表記をするための自己破壞的なマッピング行つてそれから自動コマンドの中でそのマッピングを呼び出すことで實現することもできます。例:

 " この方法はファイル名を自動的にメニューリストに追加するものです。
 " 自己破壞的なマッピングを使つてゐます!
 " 1. ファイル名に含まれる 'dots' を \. に變更するためにバッファの 1 つの行を使
 "    います。
 " 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 つのよりよい方法は ":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| を參照)、さうすると <> 表記は使ひませんので、ここでの例としてそれを使ふのは不適切です。

對應する括弧を强調する

この例はいくつかの高度なトリックを紹介してゐます。

これはスクリプトローカル變數を使つてゐるので、Vim script ファイル中に書かなければなりません。カーソルが文字列やコメントの中にないならば、文字列やコメントはスキップして檢索します。構文强調が有效になつてゐる必要があります。

これより若干高度なバージョンがプラグイン |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

  let c_lnum = line('.')
  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 [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

autocmd CursorMoved,CursorMovedI * call s:Highlight_Matching_Paren()
autocmd InsertEnter * match none

Up: 目次   [Index]