Home > Vim Hacks

Vim Hacks Archive

Hack #138: ファイルタイプのエイリアスを作る

set filetype=c

と入力すると現在のバッファにシンタックスハイライトやftpluginなどの設定をロードすることができます。
また:setfiletypeというコマンドも用意されていて、これを使うと前述のファイルタイプがいくらか楽に指定できます。

:setf c

ただファイルタイプの中には「javascript」などといった長い名前のものがしばしばあります。
そこでautocmdを使い

autocmd FileType js setlocal ft=javascript

とすると

setf js

のように少ないタイプ数でファイルタイプの設定ができます。

他にもaltercmd.vimを使って更に短いsetfiletypeのエイリアスを作ったり

AlterCommand sf setf

マッピングで:setfを入力してしまうのもいいでしょう。

nnoremap gs :<C-u>setf<Space>

ファイルタイプの指定はコードを書く作業に取りかかる上でとても重要です。
素早くファイルタイプの指定ができるとコードを書く意欲が上がります。

tyru

Hack #137: タブとインデントの設定を理解する

Vim にはタブやインデントの挙動を制御するオプションが多数あり、細かい指定ができます。

本 Hack ではこれらに関するオプションについて簡単に紹介します。一部説明を省略している箇所もあります。より詳しい説明が知りたい場合は :help で各オプションの項目を見てみてください。

また、ここで紹介しているもので全てではありません。より高度なオプションについては省略しています。

'tabstop' 'ts'

バッファについてローカルなオプションです。

タブ文字が何文字分として表示されるかの設定です。

'expandtab' 'et'

バッファについてローカルなオプションです。

このオプションが on だと、インデントが生成される際やタブキーを押した際にタブ文字の代わりに同じ見た目になるようにスペースを挿入します。 インデントが生成される際とは、<>、Insert-mode での <C-d><C-t> でインデントを変更した際、新しい行を挿入した際、= でインデントを調節した際などが該当します。

本当のタブ文字を挿入したい場合は <C-v><Tab> とすることで入力できます。

以下のオプションの説明で「空白を挿入する」とあった場合、このオプションが on の場合はスペースを、off の場合はタブ文字(と、場合によっては合わせてスペース)を挿入することになります。

'shiftwidth' 'sw'

バッファについてローカルなオプションです。

インデントを変更する際に何文字分ずらすかの設定です。

これは 'tabstop' とは独立しています。つまり、'tabstop''shiftwidth' を別の値に設定することができます。

この場合を含み、'expandtab' が off の場合、タブ文字だけではインデントが行えない場合があります。その場合は、半端な部分はスペースになります。

" :set tabstop=8 shiftwidth=4 noexpandtab の場合
" わかりやすくするためにタブ文字を >------- で、スペースを _ で表示している
hoge
____hoge
>-------hoge
>-------____hoge

'softtabstop' 'sts'

バッファについてローカルなオプションです。

このオプションに 0 以外が設定されていると、 <Tab><BS> を入力した際にその文字数分空白を入力したり削除したりします。つまり、'tabstop' の値とは関係なくあたかもタブ文字がこのオプションの値の文字数であるかのように振舞います。

'smarttab' 'sta'

グローバルなオプションです。

このオプションが on のとき、行頭の連続した空白に限り、<Tab>'shiftwidth' 分だけ空白を挿入します。また、同様に行頭の空白の部分のみ、<BS>'shiftwidth' 分のスペースを削除します。これによりインデントがタブ文字かスペースかをあまり意識する必要がなくなります。

'autoindent' 'ai'

バッファについてローカルなオプションです。

新しい行を挿入する際に、新しい行のインデントを直前にいた行と同じになるようにします。

この自動で挿入されたインデントは、何も入力せずに Insert-mode の抜けたりさらに新しい行を作ったりした場合削除されます。 この動作を望まない場合は、新しい行を挿入した際に何かを入力してすぐ消すような Key mapping を定義するといいでしょう。

nnoremap o oX<C-h>
nnoremap O OX<C-h>
inoremap <CR> <CR>X<C-h>

'copyindent' 'ci'

バッファについてローカルなオプションです。

新しい行にインデントを自動挿入する際、既存行のインデント構造をコピーします。

これはつまり、既存行のインデントがタブ文字で構成されていれば 'expandtab' が on でも自動挿入されるインデントはタブ文字になるということです。既存行がタブ文字とスペースが混ざって構成されていた場合も、同じになるようにコピーされます。

'preserveindent' 'pi'

バッファについてローカルなオプションです。

現在行のインデント量を変更する際、すでにある部分に関してはインデント構造を保とうとします。

例えばタブ文字で構成されている行があり、その行を << でインデント量を減らそうとした場合、通常 'expandtab' が on の場合は行のインデントを構成する文字がスペースに変換されてしまいますが、このオプションが on の場合はタブ文字はそのままに保たれます。

thinca

Hack #136: Pythonインタフェースを使う(2)

前回はPythonインタフェースの基本を紹介しましたが、今回はもう少し突っ込んだ内容について紹介しようかと思います。

変数のコンテキスト

VimScriptからPythonを起動するとき、Pythonは呼ばれたVimScriptのコンテキストで実行されます。なので、以下の例のようにしてVimScriptとPython間で変数をやりとりすることができます。

" VimScript
let s:hoge = "s:hoge"

function Hoge(hoge)
    let hoge = "l:hoge"
    python <<EOM
print vim.eval('s:hoge') # s:hogeと表示
print vim.eval('a:hoge') # a:hogeと表示
print vim.eval('hoge')   # l:hogeと表示

vim.command('let s:hoge = "s:fuga"')
vim.command('let hoge = "l:fuga"')
EOM
    return hoge
endfunction

echo Hoge('a:hoge') " l:fugaと表示
echo s:hoge         " s:fugaと表示

注意点としては、前回vim.eval()のところでも述べたようにVimScriptの内容は全て文字列になるので数値で欲しい場合は、Python側でint(vim.eval("line('.')"))などとキャストする必要があるところです。他にもPythonにはboolean型がありますがVimScriptにはないなど微妙に落とし穴があるので、Python側のif文などでVimScriptの値を参照する際は気を付ける必要があります。また、:pyfileで読み込んだ外部ファイルの中でもこのコンテキストの扱いは有効です。例えば以下の通りです。

" VimScript
pyfile hoge.py
let s:fuga = 's:fuga'
python hoge("hoge")
" hoge.pyとする
def hoge(str):
    print vim.eval('s:fuga') + str # s:fugahogeと表示

また:pythonコマンドで生成したPythonの変数は全てグローバル変数となり、Vimの起動から終了まで全て同じコンテキストとなります。

" VimScript
python <<EOM
hoge = "hoge"
EOM

python <<EOM
print hoge # hogeと表示される
EOM

ユニコード文字の扱い

Pythonはスクリプト自体のエンコードを指定する方法としてマジックコメントを使うことができます。これは、スクリプトファイルの1行目か2行目に、coding:utf-8coding=utf-8などのように/coding[:=]文字コード名/で表される表現があればエンコードとして認識されるというものです。PEP 0263には.pyファイルをVimで編集する場合は、Vimのモードラインとしても有効になるように以下のように書く例が掲載されています。

# vim:set fileencoding=utf-8:

しかしモードラインで'fileencoding'は指定すべきでないので単に、

# coding=utf-8

などと書くべきです。VimScript内の:pythonコマンドではヒアドキュメント風の書き方を使った場合にだけこのマジックコメントを使うことができます。また、マジックコメントは各コマンドごとに書く必要があります。

" utf-8で保存されたVimScript、'encoding'がutf-8の環境
python <<EOM
print u"あいうえお".encode('utf-8') # スクリプトがasciiで書かれていると解釈され文字化けする
EOM

python <<EOM
# coding=utf-8
print u"あいうえお".encode('utf-8') # スクリプトがutf-8で書かれていると解釈されて文字化けしない
EOM

python <<EOM
print u"あいうえお".encode('utf-8') # 前のブロックのマジックコメントは反映されず文字化けする
EOM

ということなので、マルチバイト文字をやりとりする必要がある場合は基本的に:pythonコマンドで一行でスクリプトを渡す形式を使うことはできず、ヒアドキュメント風の使い方をすることになります。また、より汎用的にするには以下のように書くと良いでしょう。

" utf-8で保存されたVimScript、'encoding'は不明
python <<EOM
# coding=utf-8
VIM_ENCODING = vim.eval('&encoding')
print u"あいうえお".encode(VIM_ENCODING)
EOM

Vimから入力を受け取ってPythonに渡すときも同様にしてdecodeすれば文字化けせずにユニコード文字列を渡すことができます。

Pythonのimport

例えば、Pythonインタフェースを作ったプラグインを作っていて、Python部分が長くなるので外部に.pyファイルとして出しておきたい場合を考えます。そんなときは、通常は:pyfileを使えば良いのですが、これはグローバル空間でファイルの中身を実行するので、from module import *したときと同様に外部ファイルの関数や変数を全てグローバル空間に展開してしまいます。これを避けるための方法を考えてみます。

 " pytest.py
def func():
    print "hoge"
 " VimScript (:pyfileを使った例)
pyfile pytest.py
python <<EOM
func() # hogeと表示される
EOM
 " VimScript(:pyfileを使わない例)
let path = expand('%:p:h')
python <<EOM
import vim, sys
sys.path.append(vim.eval('path'))

import pytest # この.vimファイルと同じディレクトリにpytest.pyを置いておく
pytest.func() # hogeと表示される
EOM

このように、VimScript側でスクリプトの置いてあるディレクトリを取得し、sys.pathにパスを追加しておくことで、所望の.pyファイルをimportすることができます。

今回は以上です。前回と今回で説明した内容を理解すれば、Pythonインタフェースを利用したpluginも自在に書けるようになると思います。

tsukkee

Hack #135: ]で補完する

多くの方はTabキーを補完のために使うため、以下のような設定をしていると思います。

inoremap <Tab> <C-n>

Tabキーを打鍵し続けると、左手小指が破壊されます。公平のため、右手小指も使うべきではないでしょうか。Tabキーと対称な位置にあるキーは[または]です。後述する理由のため、]Tabキーのかわりに補完用のキーに設定してみましょう。

まずは素直に、先ほどのTabキーと同様の方法で設定します。

inoremap ] <C-n>

これは便利なのですが、本当に]を入力したいときに、<C-v>]と打鍵しなければならないのがつらいです。

解決法1

そもそも]を入力しないで済むように、自動で入力するようにします。

inoremap [ []<Left>

[を入力した時点で自動的に]が入力されるので、]を手動で入力する必要がなくなります。 大抵の場合は]は対応する[があってこそ意味があるので、この解決方法でうまくいくことでしょう。

解決法2

実際には、勝手に]が入力されてしまうのは直感に反するとして嫌悪する方が多いのではないでしょうか。私がまさにそうです。 すこし複雑ですが、以下のような対処法はどうでしょうか。

  1. 通常は]<C-n>として動作する
  2. カーソル位置より手前に閉じていない[があれば、]]として動作する

これを実現するには、~/.vimrcに以下を記述します。

inoremap <expr> ] searchpair('\[', '', '\]', 'nbW', 'synIDattr(synID(line("."), col("."), 1), "name") =~? "String"') ? ']' : "\<C-n>"

ちょっとややこしいので、具体例で動作を説明します。

カーソル位置を_とします。まず、

aaa[bbb_

この状態で]を打鍵すると、

aaa[bbb]_

となります。いっぽう、

aaa bbb_

この状態で]を打鍵すると、

aaa bbba
   |bbbb|
   |bbbc|
   |bbbd|
   +----+

このように補完のポップアップメニューが出てきます。

また、""で囲まれた部分は無視します。

"[".t_

この状態で]を打鍵すると、

"[".t]_

ではなく、補完がはじまります。

謝辞

thincaさんの添削により、オリジナルで32行だった実装が1行になりました。そのときの履歴はこちらを参照ください。 https://gist.github.com/24e46f72cc08e53c59a1

ujihisa

Hack #134: Vimをデフォルトの状態で起動する

問題

例えば何らかのプラグインが原因でVimの動作が怪しいといった状況になったときなど、 Vimをデフォルトの状態で起動したいことがあります。 vimrcや各種プラグインを一旦削除してから起動すれば可能ですが、 さすがにそれは面倒です。簡単に行う方法はないでしょうか。

解決方法

以下のオプションを指定してVimを起動します:

vim -u NONE

デフォルトの状態では'compatible'がオン (=可能な限りvi互換な挙動となる)のですが、 場合によっては'compatible'がオフの方が良い場合もあります。 その場合は以下のオプションを指定してVimを起動します:

vim -u NONE -N

解説

Vimには様々な起動オプションがあり、そのひとつとして vimrcのパスを指定する-u {vimrc}オプションがあります。 通常は~/.vimrcなどのファイルがロードされますが、 -uを指定することで別のファイルをロードさせることができます。 さらに-uには特殊な値としてNONEを指定でき、 これは「vimrcのロードは行なわず、プラグインのロードも行なわない」 という意味になります。つまりVimがデフォルトの状態で起動することになります。

-N'compatible'がオフの状態で起動するよう 指定するオプションです。 なお、-cで任意のコマンドを起動時に実行できるため、 -c "set nocompatible"としても同じことができますが、 -Nの方が簡潔です。

参考資料

kana

Hack #133: バイナリファイルを編集する

Vim はテキストエディタですが、バイナリファイルの簡単な編集もできます。

xxd

xxd は Vim に付属しているプログラムで、バイナリファイルを16進数のテキスト形式に変換、および、そのテキスト形式のファイルをバイナリファイルに逆変換することのできるプログラムです。Vim 付属のため Windows でも利用できます。 バイナリファイルを Vim に読み込む際と書き込む際にこのプログラムを使うことでテキストエディタ上でバイナリファイルの編集が可能になります。

ただし、xxd の逆変換機能はそこまで優れていないため、できるのは値の書き換え程度で、値の挿入や削除はできません。

設定

設定方法は :help hex-editing に載っているのでこちらを参照してもよいのですが、せっかくなので本 hack では少し違った設定方法を紹介します。

以下のファイルを ~/.vim/ftplugin/xxd.vim (Windows の場合は ~/vimfiles/ftplugin/xxd.vim) に置きます。

if !executable('xxd')
  finish
endif

let b:undo_ftplugin = (exists('b:undo_ftplugin') ? b:undo_ftplugin . ' | ' : '')
\ . 'setl bin< eol< | execute "au! ftplugin-xxd * <buffer>" | execute "silent %!xxd -r"'

setlocal binary noendofline
silent %!xxd -g 1
%s/\r$//e
augroup ftplugin-xxd
  autocmd! * <buffer>
  autocmd BufWritePre <buffer> let b:xxd_cursor = getpos('.')
  autocmd BufWritePre <buffer> silent %!xxd -r
  autocmd BufWritePost <buffer> silent %!xxd -g 1
  autocmd BufWritePost <buffer> %s/\r$//
  autocmd BufWritePost <buffer> setlocal nomodified
  autocmd BufWritePost <buffer> call setpos('.', b:xxd_cursor) | unlet b:xxd_cursor
augroup END

特定の拡張子に対して自動でバイナリ編集モードにしたい場合は、~/.vim/ftdetect/xxd.vim (Windows の場合は ~/vimfiles/ftdetect/xxd.vim) に以下のように書きます。

autocmd BufReadPost,BufNewFile *.bin,*.exe,*.dll setlocal filetype=xxd

この例では、bin, exe, dll の拡張子のファイルを開いた際にバイナリ編集モードになります。

解説

基本的な仕組みは :help hex-editing に載っているものと同じです。

バイナリ編集モードに移行した際、バッファ全体を xxd コマンドで変換して見やすい形式にします。 保存する際には、xxd -r で一旦バイナリ形式に戻してから保存し、保存後に再び xxd で見やすい形式に戻します。

加えて、変換時に移動してしまうカーソルの位置を保存、復元しています。

この方法の利点は、どんなファイルでも開いた後から

:setf xxd

とするだけでバイナリ編集モードへ移行できることです。ファイルタイプを設定するだけなので、特定のファイルをバイナリ編集モードに対応させるのも簡単です。

例えば、バイナリモードのファイル(vim -b file で開いた場合など)を自動的にバイナリ編集モードにするには vimrc で以下のようにします。

augroup xxd
  autocmd!
  autocmd BufReadPost * if &l:binary | setlocal filetype=xxd | endif
augroup END
thinca

Hack #132: Pythonインタフェースを使う(1)

VimにはRubyやPython、Perl、SchemeなどのVimScript以外の言語のインタフェースがあります.これらの言語にはVimScriptにはない強力なライブラリを持っているものも多く、ネットワーク通信やファイルシステムの操作など、VimScript単体では難しい処理を行う際に便利です。今回はその中でPythonインタフェースの使い方について簡単に解説したいと思います。

そもそもPythonインタフェースを使うには?

Vimを --enable-pythoninterp 付きでconfigureしてビルドする!だけではあんまりなので、それ以外の方法を一部紹介します。

  • Mac
    • MacVim-KaoriYaにはデフォルトでPythonインタフェースが組み込まれているので、これを使うのが一番簡単です。
    • MacPortsで+python(または+python26)でインストールするのでもOKです。
  • Windows
    • KaoriYa VimPythonのDLLが存在するとPythonインタフェースが使えます。詳しくは:help python-dynamicを参照してください。
  • Linuxなど
    • UbuntuとDebianではvim-pythonパッケージでPythonインタフェースを有効にできるそうです
    • 残念ながら筆者はその他の環境で簡単にPythonインタフェースを使う方法を知りません。Linuxの各ディストリビューションに含まれているVimの状況などご存知の方は、コメント欄などでお知らせいただけると幸いです。

Pythonインタフェースが使えるか確認する

以下のコマンドで1が返ればOKです。

:echo has('python')

VimScriptからPythonを呼ぶ

:pythonコマンドを使います。

" VimScript
:python print "hoge"; print "hoge"

:python <<EOM
print "fuga"
print "fuga"
EOM

といった感じで,そのまま引数にPythonスクリプトを渡すか,複数行のスクリプトを渡すときは2番目のようにヒアドキュメント風にすることでPythonを実行できます。Pythonはインデントが重要なので2番目の呼び方を用いるときには注意が必要です。ちなみに、print文などPythonからの標準出力は:echomsgで出力するのと同じ扱いで、エラーは:echoerrしたのと同じ扱いになります。また、input()やraw_input()などの標準入力からのインプットはサポートされていません。

" VimScript
function Hoge()
    python <<EOM
    print "hoge"
    EOM
enfcuntion " エラー!

上記のようについつい書きたくなりますが、これはエラーになります。Pythonは必ずインデントなしの状態で書き始めないといけませんし、EOMの前に空白があるとPythonブロックの終了と見なされません。正しくは、以下のように書きます。

" VimScript
function Fuga()
    python <<EOM
print "fuga"
EOM
endfunction

そのほか、Pythonの書かれたファイルを読み込んで実行する:pyfileコマンドもあります。

PythonからVimScriptを呼ぶ

Pythonからはvimモジュールを利用することで、VimScriptを呼ぶことができます。importしないと使えないので注意してください。

# Python
import vim

vimモジュールにはvim.command()とvim.eval()の二つの関数が用意されています。vim.command()は引数に渡されたVimのコマンドを実行します。例えば以下のように使います。

# Python
vim.command('echo "hoge"')
vim.command('let val = "fuga"')

vim.eval()は与えられたVimの式を評価して返します。配列もちゃんとPythonの配列にして返してくれます。ただし、数値であっても全て文字列として返されるので注意してください。例えば以下のような感じになります。

# Python
color_name = vim.eval('g:color_name')
bufnum, lnum, col, off = vim.eval('getpos(".")') # 例えば、("0", "3", "10", "0")のようになる

また,Vimのバッファを表すオブジェクトとしてvim.bufferが提供されています。vim.buffersが全てのバッファが入った配列で、vim.current.bufferが現在表示しているバッファになります。:help pythonにもありますが、おおよその使い方は以下の通りです。

# Python
import vim
b = vim.current.buffer # 現在のバッファ
print b.name           # バッファ名
print b.number         # bufnr()で得られる値,vim.buffersのインデックスはbufnr()とは異なるので注意
b[0] = "hoge"          # 1行目を変更する
b[:] = None            # バッファを空にする
b = vim.buffers[1]     # 1番目のバッファ(bufnr()が1というわけではない)
del b[:]               # これもバッファを空にする
b[0:0] = ["fuga"]      # 一番上に行を挿入
del b[2]               # 3行目を削除
b.append("hoge")       # 末尾に行を追加 
print len(b)           # バッファの行数を表示

vim.buffersで全てのバッファを得られることからわかるように、VimScript単体では難しい表示していない(アクティブでない)バッファの内容を取得したり、その中身を編集したりすることができます。また、vim.bufferを用いた編集もVimの'modifiable'などの影響を受けるので、set nomodifiableされたバッファに書き込もうとすると、vim.error例外が発生し編集できません。

その他vim.window,vim.rangeなどが提供されていますが、今回はこれらの詳細は省略します。詳しくは:help pythonを参照してください。

今回は主に:help pythonにも書かれている内容について説明しましたが、次の「Pythonインタフェースを使う」では、もう少し突っ込んだ内容について説明したいと思います。

tsukkee

Hack #131: Rubyで#{をラクに入力する

問題

Rubyでは文字列リテラルの中に#{}で囲まれた式を書くと展開されます。

puts "It is now #{Time.now}."
#=> It is now Wed Feb 17 16:28:18 -0800 2010.

しかしながら、毎日#{を何度も打鍵することは、あなたの指の骨に深刻なダメージを与えることでしょう。

様々な解決方法がありますが、著者が最も直感的と感じるのは以下の方法です。

  • {{ と打鍵すると自動的に#{と置き換えられる

すぐに思い浮かぶ解決方法は、iabbrevを用いて{{#{に置き換えることです。

iabbrev {{ #{

この方法はうまくいきません。{{のあとにスペースを打鍵する必要がありますが、Rubyの慣習では#{のあとにスペースをいれずすぐに式を書くことになっている場合が多いためです。

それならばiabbrevではなくinoremapだ、と思い付くのではないでしょうか。

inoremap {{ #{

この方法はうまくいきません。実際に試してみるとすぐに分かりますが、{を打鍵してすぐに{が画面にでてこないことにイライラする日々を送ることになります。Rubyでは#{よりもブロックとしての{を書くことの方が頻度は高く、メリットよりもデメリットの方が遥かに大きいのです。

解決

smartchrを使います。

smartchrをインストールし、~/.vim/ftplugin/ruby.vimに以下を記述します。

inoremap <expr> <buffer> {  smartchr#loop('{', '#{', '{{{')

これで、{を続けて打鍵していくと以下のようになります。

{
#{
{{{
{
#{
{{{
...

inoremapのときと違い、はじめの{が即座に画面に表示されます。

発展

他のRuby用ftpluginと共存させるため、筆者は~/.vim/ftplugin/ruby.vimではなく、~/.vim/ftplugin/ruby/ujihisa.vimに上記の設定を含めて記述しています。

http://github.com/ujihisa/config/blob/master/vim/ftplugin/ruby/ujihisa.vim

ujihisa

Hack #130: :grepをより便利に利用する

問題

Hack #129: 複数のファイルから検索する では:grepについて紹介しました。 色々と便利なコマンドなのですが、頻繁に使っていると次のような不満が出てきます:

:grepの引数は基本的に

:grep {pattern} {file} ...

なのですが、同じファイル郡に対して異なるパターンで:grepする というケースは少なくありません。例えば

:grep rebase *.[ch]

で検索した後で

:grep rebase_cmd *.[ch]

と検索しなおすとしましょう。全てのコマンドを入力しなおすと面倒ですから、 通常は入力履歴を<Up>/<Down>で参照して以前入力した コマンドを修正する形になります。

ここで、入力履歴を手繰るまではよいのですが、 パターンを修正するところが問題です。 修正するためには<Left><Left><Left>...などとしてパターンの箇所まで カーソルを移動しなければならないのですが、これが面倒です。 特に{file} ...の指定が長くなると面倒さが倍増します。 どうにかして簡単に修正することはできないでしょうか。

解決方法

以下の内容をvimrcに追加します:

command! -complete=file -nargs=+ Grep  call s:grep([<f-args>])
function! s:grep(args)
  execute 'vimgrep' '/'.a:args[-1].'/' join(a:args[:-2])
endfunction

これにより:grepの代わりに 以下のような:Grepコマンドが使えるようになります:

:Grep {file} ... {pattern}

:grepでの煩雑さは最初の引数が{pattern}であることが 原因なので、その逆で最後の引数が{pattern}であるコマンドがあれば パターンの修正は<Up><C-w><C-w>...だけで済みます。

参考資料

kana

Hack #129: 複数のファイルから検索する

時折、大量にあるテキストファイルから特定のテキストを検索したい場合があります。grep などのプログラムが有名ですが、やはり検索結果から直接該当のファイルにジャンプできると便利です。

:grep コマンド

:grep コマンドは、'grepprg' オプションで指定された外部プログラムを実行してテキストの検索を行い、結果を 'errorformat' オプションに従って解釈したあと、quickfix ウィンドウへ出力します。quickfix 上で結果を選択して <Enter> を押すことで目的のファイルの目的の行にジャンプすることができます。 各オプションにはデフォルトで適切な値が設定されており、通常はいじる必要はありません。

:grepadd と言うコマンドもあり、これは quickfix ウィンドウの中身を置き代えずに追記します。複数の grep の結果を見るのに便利です。

:vimgrep コマンド

:grep コマンドは外部のプログラムに依存するため、その実装によって挙動が異なることがあります。例えば、Windows では標準では findstr が使用されます。これは grep とはまったく異なるものなので、指定する引数も使える正規表現も違います。

そういう経緯もあってかどうかは知りませんが、Vim には :vimgrep と言う自力で grep を行う組み込みコマンドがあります。基本的な使い方は :grep と同じです。

:vimgrep /pattern/ {file}...
:vimgrepadd /pattern/ {file}...

pattern には Vim の正規表現が使えます。単純な単語の場合、前後の / は省略可能です。

{file} の部分に検索対象のファイルを指定します。指定にはワイルドカードが使えます(:help wildcard)。これは ** による再帰的な探索に対応しています。

:vimgrep /\<variable\>/ **/*.c

パターンの後ろにフラグを付けることで挙動を変更できます。

フラグ意味
g1 つの行に複数のマッチが見つかった場合、同じ行を複数回列挙します。
j通常、検索対象が見つかった場合は最初の候補にジャンプしますが、このジャンプを抑制します。
:vimgrep /\<variable\>/j **/*.c

コマンドの前に数字を置くことで、検索件数の上限を指定できます。これにより検索時間を短縮できます。例えば、最初に見つかった 1 件だけを表示するには以下のようにします。

:1vimgrep /\<variable\>/ **/*.c

'grepprg' に "internal" と設定すると、:grep で :vimgrep が使われるようになります。

set grepprg=internal

:vimgrep は挙動が統一されているので、様々な環境で同じように grep を行いたい場合に非常に便利です。

thinca

ホーム > Vim Hacks

Search
Feeds
Links
  • 公式
  • 勉強会
  • 情報
  • コミュニティ
  • Meta
    Etc
    Creative Commons License
    This blog is licensed under a Creative Commons License.

    Return to page top