POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

FeedlyRSSTwitterFacebook
Marco Hinz

本記事は、原著者の許諾のもとに翻訳・掲載しております。

(訳注: 2016/2/26、記事タイトルを変更いたしました。)

vim-galore


特定のトピックについての記述をご希望ですか? Issue を立てるか、 Twitter で私までお知らせください!ありがとう!


はじめに

基礎

使用方法

  • オフラインでのヘルプ
  • オフラインでのヘルプ(代替案)
  • オンラインでのヘルプ
  • クリップボード
    • クリップボードの使用法(Windows、OS X)
    • クリップボードの使用法(Linux、BSD他)
  • ファイルを開いたときのカーソルの位置を元に戻す
  • バックアップ/スワップ/アンドゥ/viminfoファイル
  • リモートファイルの編集
  • プラグインの管理
  • ブロックの挿入
  • 外部プログラムの実行とフィルタの使用
  • matchit

ヒント

  • 適切なnとNの振る舞い
  • 適切なコマンドライン履歴
  • 適切なCTRL-L
  • ビープ音とビジュアルベルを無効にする
  • 現在の行を動かす
  • 空行を追加する
  • マクロを編集する
  • ヘッダやソースファイルにジャンプする
  • GUIのフォントサイズを変更する
  • モードに応じてカーソルスタイルを変更する
  • セレクションを横に移動させた時に見失わない
  • 保存時にファイルをリロードする
  • スマートなカーソルライン
  • より速いキーワード補完

コマンド

  • :global – マッチする全ての行でコマンドを実行する
  • :normalと:execute – スクリプトの夢のチーム
  • :redir – メッセージのリダイレクト

デバッグ

  • 一般的なヒント
  • 起動時間のプロファイル
  • ランタイムでのプロファイル
  • verbose
  • Vimスクリプトのデバッグ
  • 構文ファイルのデバッグ

その他

  • その他の資料
  • Vimのディストリビューション
  • 標準プラグイン
  • CapsLockをCtrlにマップする
  • イースターエッグ
  • なぜナビゲーションはhjklなのか?

Quirks

  • 小さいファイルの編集が遅い
  • 大きいファイルの編集が遅い
  • NULに使われる改行
  • 括弧付きペースト(なぜいつも”paste”を設定しなくてはならないのか)
  • ターミナルでEscを使った時の遅延

カラースキームのリスト

プラグインのリスト

Neovim


マーク機能

ファイルの中の位置、つまり行番号と列番号を記憶するためにマークを使用します。

マーク

設定者

用途

a z

ユーザ

ファイル内でローカル。つまり、ファイル1つに対してのみ有効。小文字のマークへのジャンプは、現在のファイル内へのジャンプを意味する。

A Z

ユーザ

グローバル。つまり、ファイル間で有効。 ファイルマーク とも呼ばれる。ファイルマークへのジャンプは、別のバッファに切り替えることになる。

0 9

viminfo

0 は、viminfoファイルが最後に書かれた時の位置。つまり、Vimプロセスが終わった時の位置。 1 は最後から2番目のVimプロセスが終わった時の位置ということになる。これ以降も同様。

モーションを記述するには ' / g' もしくは ` / g` をマークの前に付けます。

mm を使えば、現在の位置をマーク”m”で記憶できます。ファイルの中であちこち移動したあとでも、 'm (空白ではない最初のところ)もしくは `m (その列)を使えばジャンプして元の位置に戻ることができます。Viminfoファイルに指定しておけば、Vimを終了したあとも小文字のマークは記憶されたままになります。 `:h viminfo-' を見てください。

mM を使えば、ファイルマーク”M”で現在の位置が記憶できます。 'M もしくは `M を通して別のバッファに移ったり、元のものに戻ったりできます。

他のモーションは以下のとおりです。

モーション ジャンプ先
'[ , `[ 直前に変更またはヤンクされたテキストの最初の行、もしくは文字。
'] , `] 直前に変更またはヤンクされたテキストの最後の行、もしくは文字。
'< , `< 最後にビジュアル選択された部分の初めの行、もしくは文字。
'> , `> 最後にビジュアル選択された部分の終わりの行、もしくは文字。
'' , `` 最新のジャンプの前の位置。
'" , `" 現在のバッファが最後に終了した時の位置。
'^ , `^ 最後に行った挿入を終えた位置。
'. , `. 最後の変更が加えられた位置。
'( , `( 現在の文章の始まり。
') , `) 現在の文章の終わり。
'{ , `{ 現在のパラグラフの始まり。
'} , `} 現在のパラグラフの終わり。

マークは 範囲 でも使うことができます。おそらく見かけたことがあって、どんな意味だろうと疑問に思ったことのある人が多いのではないでしょうか。ビジュアルモードでテキスト選択して : を実行すると、 :'<,'> がコマンドラインにプリペンドされます。つまり、ビジュアル選択された部分を示す範囲(レンジ)が、次のコマンドに与えられます。

:marks を使用すれば、全てのマークがリスト化できます。全てを :h mark-motions で読み込んでください。

補完

Vimは様々な種類の挿入モード補完を提供します。もし複数の一致候補があれば、ポップアップメニューが表示され、選択するよう誘導してくれます。

一般的に補完の対象となるものは、タグ、インポートしたモジュール/ライブラリの関数、ファイル名、ディレクトリ名、同じバッファに存在する単語などです。

Vimは補完のそれぞれの種類のマッピングを提供しています。全てが、 <c-x> で始まっています(挿入モードでこれらを使うのを忘れないでください)。

マッピング 種類 関連するヘルプ
<c-x><c-l> 全ての行 :h i^x^l
<c-x><c-n> 現在のファイルのキーワード :h i^x^n
<c-x><c-k> 'dictionary' オプションからのキーワード :h i^x^k
<c-x><c-t> 'thesaurus' オプションからのキーワード :h i^x^t
<c-x><c-i> 現在のファイルと、インクルードされているファイルからのキーワード :h i^x^i
<c-x><c-]> タグ :h i^x^]
<c-x><c-f> ファイルネーム :h i^x^f
<c-x><c-d> 定義とマクロ :h i^x^d
<c-x><c-v> Vimコマンド :h i^x^v
<c-x><c-u> ユーザ定義( 'completefunc' で特定される) :h i^x^u
<c-x><c-o> オムニ補完 ( 'omnifunc' で特定される) :h i^x^o
<c-x>s スペル提案 :h i^Xs

ユーザ定義補完とオムニ補完の違いが分からない人もいるでしょうが、技術的にはこの2つは同じことをします。両方とも、現在の位置を調べて、提案のリストを返すという関数を使います。ユーザ定義補完は、ユーザの個人的な目的のためにユーザによって定義される補完のことです。(サプライズ!)これは何にでも使えますね。オムニ補完はファイルタイプ固有の目的で、構造体メンバやクラスメソッドを補完したりします。そして、しばしばファイルタイププラグインで設定されます。

また、Vimは 'complete' オプションを設定することで、複数の種類を一度に補完することもできます。デフォルトのままではオプションの種類が多いので、自分の好みに合わせて減らすのを忘れないでください。 <c-n> (次)か、 <c-p> (前)のどちらかを使用することで、この補完をトリガさせることができます。そしてこれは、ポップアップメニューでエントリを選択するときに使うキーでもあります。他の例は、 :h i^n :h 'complete' を見てください。

ポップアップメニューの動作を設定するには、 :h 'completeopt' を確認しましょう。デフォルトはまあまあマトモですが、私は”noselect”を追加するほうが好きです。

関連するヘルプ:

:h ins-completion
:h popupmenu-keys
:h new-omni-completion

モーション/オペレータ/テキストオブジェクト

モーションはカーソルを動かします。 h / j / k / l /のことは分かりますよね。もしくは w / b 。さらに、 / もモーションです。また、回数を使うこともできます。 2?the<cr> は、最後から2番目に使われた”the”にジャンプすることを意味します。

:h navigation と下記の記述をみて、使用できるモーションを確認してみてください。

オペレータ は、ある範囲のテキストに対して動作します。例えば、 d ~ gU > などです。他にもたくさんあります。これらは、ノーマルモードかビジュアルモードでしか使えません。ノーマルモードでは、オペレータはモーションのすぐあとにきます。例えば >j などです。ビジュアルモードでは、オペレータは単純に、選択範囲上で機能します。例えば Vjd です。

モーションと同様、オペレータも数を使うことができます。例えば 2gUw は、現在の単語と2番目に出てくる単語を大文字にするという意味です。モーションとオペレータは両方とも数を数えられるので、 2gU2w も機能し、 gU2w を2回繰り返すことができます。

:h operator を見て、使用できるオペレーションを確認してみてください。 ~ をオペレータとして機能させるには :set tildeop を使用してください。

テキストオブジェクト は、モーションが1つの方向にしか機能しないのに対して、多方面のエリアで機能します。実際に、単語全体、文章全体、カッコ間の全てなどのオブジェクト上で機能します。

テキストオブジェクトは、ノーマルモードではカーソルを動かすのには使えません。なぜなら、どんなに優秀なカーソルでも2カ所に同時に飛ぶことはできないからです。しかし、ビジュアルモードでは使うことができます。なぜなら、オブジェクトの一方は、すでに選択され、カーソルはもう一方のほうへジャンプすればいいからです。

テキストオブジェクトは、オブジェクトを意味する文字に続いて、 i (innerの頭文字)もしくは a (aroundの頭文字)のどちらかから始めます。 i であれば、そのオブジェクトだけに機能し、 a であればそのオブジェクトと続く空白にも機能します。例えば、 diw であれば現在の単語だけを削除し、 ci( であれば、カッコ内の全てを変更します。

テキストオブジェクトも数を数えることができます。例えば、 ((( ))) で、カーソルが一番内側のカッコ上もしくはそのカッコの間にあるとすると、 d2a( は内側の2組のカッコと、その間にある全てを削除します。

:h text-objects を見て、使用できるテキストオブジェクトを確認してみてください。

Autocmd

多くの場合、Vimはイベントを発行します。イベントに入るにはautocmdを使用します。

もしautocmdがなかったら、Vimを使うことはないでしょう。ユーザが気付かなくても、autocmdは常時使用されています。信じられませんか? では、 :au とタイプしてみてください。出力を見て圧倒されないでくださいね。これは全部、現時点で有効になっているautcmdです。

利用可能な全イベントの概要を簡単に見るには、 :h {event} とタイプし、詳細を見るには、 :h autocmd-events-abc とタイプします。

典型例として、ファイルタイプ特定の設定を行う例を挙げます。

autocmd FileType ruby setlocal shiftwidth=2 softtabstop=2 comments-=:#

でも、どうしてバッファには、ここにRubyのコードが含まれていることが分かるのでしょうか? それは、別のautocmdがそれを検出し、それに従ってファイルタイプを設定し、その設定がさらに FileType イベントをトリガしたからです。

誰もが最初にvimrcに追加するものの1つは、 filetype on です。これは単に、起動時に filetype.vim が読み込まれ、世の中のほぼ全てのファイルタイプにautocmdを設定することを意味します。

勇気があるなら、 :e $VIMRUNTIME/filetype.vim を見てみましょう。文字列”Ruby”が見つかれば、Vimが単にファイル拡張子 .rb を使ってRubyファイルを探していることが分かります。

注:同じイベントのautocmdは、作成された順序で実行されます。 :au で、正確な順序が表示されます。

au BufNewFile,BufRead *.rb,*.rbw  setf ruby

BufNewFile イベントと BufRead イベントは、この場合、VimのCソースにハードコードされていて、 :e やそれに似たコマンドを通してファイルを開くたびに発行されます。その後、 filetype.vim から何百ものファイルタイプが全てテストされます。

簡単に言えば、Vimはイベントとautcmdを多用しますが、そのイベントドリブン・システムに入ってカスタマイズするための簡潔なインターフェイスを開示する、ということです。

チェンジリストとジャンプリスト

最近の100回の変更の位置が チェンジリスト に保持されます。同じ行内の小さな変更は1つにまとめられますが、チェンジリストに保持される位置は最後に加えた変更の位置になります(行の途中に何かを追加した場合)。

ジャンプを行うと、ジャンプする前の位置が ジャンプリスト に記憶されます。ジャンプリストには100件までのエントリがあります。各ウィンドウについて、それぞれのジャンプリストがあります。ウィンドウを分割すると、ジャンプリストがコピーされます。

ジャンプは、 ' ` G / ? n N % ( ) [[ ]] { } :s :tag L M H のいずれかのコマンドか、新しいファイルの編集を始めるコマンドです。

リスト 全エントリのリスト表示 戻る 進む
ジャンプリスト :jumps [count]<c-o> [count]<c-i>
チェンジリスト :changes [count]g; [count]g,

全てのエントリのリストを表示すると、現在の位置がマーカ > を使って示されます。通常は、最新の位置である第1の位置の下に示されます。

Vimを再起動した後も両方のリストを残しておきたい場合は、viminfoファイルと :h viminfo-' を使用する必要があります。

注:最後にジャンプする前の位置も マーク として保持され、 `` または '' を使ってそこにジャンプすることができます。

関連するヘルプ:

:h changelist
:h jumplist

Undoツリー

テキストの状態に加えた最新の変更が記憶されます。変更を元に戻すには undo を使い、戻した変更をやり直すには redo を使います。

重要なことは、最近の変更を保持するデータ構造は キュー ではなく、 ツリー(木構造) だということです。変更はツリー内のノードであり、(トップノード以外の)ノードにはそれぞれ親ノードがあります。各ノードは変更されたテキストと時刻に関する情報を保持します。枝は、任意のノードから始まってトップノードにまでさかのぼる一連のノードです。変更をundoしてから他のものを挿入すると、新しい枝が生成されます。

ifoo<esc>
obar<esc>
obaz<esc>
u
oquux<esc>

現在、3本の線があって、ツリーは次のようになります。

     foo(1)
       /
    bar(2)
   /      \
baz(3)   quux(4)

undoツリーには、4つの変更が保持されています。数字は、ノードが作成された 時刻 を表します。

このツリーを辿るには、2つの経路があります。それぞれ、 枝方向時間方向 と呼びましょう。

Undo (u) とredo (<c-r>) は、枝方向に働いて、現在の枝を上り下りします。 u は、テキスト状態をノード”bar”に戻します。もう一度 u を行うと、テキスト状態はさらにノード”foo”に戻されます。次に <c-r> でノード”bar”の状態に逆戻りして、その次の <c-r> ではノード”quux”の状態になります(枝方向のコマンドを使って、ノード”baz”には行けません)。

これとは異なり、 g- g+ は時間方向に働きます。よって、 g-
では u のようにノード”bar”の状態には戻らず、時系列的に直前の状態であるノード”baz”に戻ります。もう一度 g- を行うと、状態はノード”bar”に戻り、以下同様に続きます。このように、 g- g+ は単純に時間の中で進んだり戻ったりします。

コマンド/マッピング 動作
[count]u , :undo [count] [count]回の変更をundoする。
[count]<c-r> , :redo [count]回の変更をredoする。
U 最後に変更した行の中の全ての変更をundoする。
[count]g- , :earlier [count]? 以前のテキスト状態に[count]回戻る。”?”は、”s”、”m”、”h”、”d”、”f”のいずれかを指定できる。例えば、 :earlier 2d は、2日前からのテキスト状態に進む。 :earlier 1f は、最後にファイル保存したときの状態に進む。
[count]g+ , :later [count]? 上と同じで、逆方向。

undoツリーはメモリ内に保持され、Vimの終了時に消去されます。永続的なundoを可能にする方法については、 Handling backup, swap, undo, and viminfo files を参照してください。

undoツリーが分からなくなったときには、ツリーを視覚化するために undotree が役立ちます。

関連するヘルプ:

:h undo.txt
:h usr_32

quickfixリストとlocationリスト

アクションが位置のリストを返す必要がある時には、 quickfix リストまたは location リストがいつも使用できます。この場合、location(位置)は、ファイル、行番号、列番号(オプション)です。

例としては、コンパイラエラーをquickfixリストにまとめたり、外部grepツールの一致結果をlocationリストにまとめたりすることなどがあります。

この内容を空白のバッファに入れるだけで、エントリを閲覧するための優れた統一インターフェースが得られるという、大きな利点があります。

quickfixリストは常に1つしかありませんが、各ウィンドウにはそれぞれ専用のlocationリストがあります。どちらのタイプのリストも同じような感じですが、ナビゲーションに使うコマンドは少し異なります。

よく使うコマンド:

動作 Quickfix Location
ウィンドウを開く :copen :lopen
ウィンドウを閉じる :cclose :lclose
次のエントリ :cnext :lnext
前のエントリ :cprevious :lprevious
最初のエントリ :cfirst :lfirst
最後のエントリ :clast :llast

この他、全てのコマンドについては、 :cc を参照してください。

昔ながらの grep を使って、現在のディレクトリ内のファイルで、あるクエリを再帰的に検索し、結果をquickfixファイルに書き込みましょう。

:let &grepprg = 'grep -Rn $* .'
:grep! foo
<grep output - hit enter>
:copen

文字列”foo”を含むファイルがあったとすれば、今、そのファイルがウィンドウに表示されているはずです。

マクロ

Vimでは、タイプ入力された文字を レジスタ記録 することができます。ある作業を素早く自動的に行うための素晴らしいツールです(手の込んだ作業には、 Vim scripting を使うべきです)。

  • q の後に、例えば q などレジスタを指定して、記録を開始します(コマンドラインは、”recording @q”を使ってこれを表します)。
  • もう一度 q とタイプすると、記録が終了します。
  • マクロを実行するには、 [count]@q を使います。
  • 最後に使ったマクロを繰り返すには、 [count]@@ を使います。

例1

1行挿入して、それを10回繰り返すマクロ。

qq
iabc<cr><esc>
q
10@q

(マクロを使わずに同じことができます: oabc<esc>10

例2

全ての行の前に行番号を追加します。まず、最初の行に手入力で”1.”を追加します。 <c-a> を使用して、 ^A と表示されるカーソルの下の番号をインクリメントします。

qq
0yf jP0^A
q
1000@q

1000@q を使う場合は、ファイル内の行数が1000行を超えないことを願うだけですが、 *再帰 マクロ* を使えば、マクロが適用できる行がなくなるまでマクロが実行されます。

qq
0yf jP0^A@q
q
@q

(マクロを使わずに同じことができます: :%s/^/\=line('.') . '. ' )

マクロを使わずに同じことをする方法をご紹介しましたが、ほとんどの場合、マクロを使わない方法は簡単な例でしか機能しません。複雑な自動化には、マクロが非常に効果的です。

併せて Quickly edit your macros も参照してください。

関連するヘルプ:

:h recording
:h 'lazyredraw'

カラースキーム

カラースキームは、Vimのスタイルを設定する方法です。Vimには多くの構成要素があり、それぞれを別々の前景色と背景色、太字などのその他の属性を使ってカスタマイズすることができます。カラースキームは次のように設定することができます。

:highlight Normal ctermbg=1 guibg=red

こうすると、エディタの背景が赤色になります。詳細については、 :h :highlight を参照してください。

つまり、カラースキームは、主として :highlight コマンドの集合です。

実際には、ほとんどのカラースキームは2つのカラースキームなのです。上の例は、 ctermbg guibg を使って色を設定します。前者の定義は、Vimがxtermなどの端末エミュレータ内で起動された場合にのみ使用されます。後者は、gVimのようなグラフィカル環境で使用されます。

あるカラースキームを端末エミュレータ内で実行中のVimで使ったらスクリーンショットと同じ色に見えないという場合は、そのカラースキームはGUI向けの色しか定義していない可能性があります。

私は、GUIには gruvbox 、端末には janah を使っています。

その他のカラースキーム

折り畳み

どんなテキストにも(あるいはソースコードにも)何らかの構造があります。構造があるということは、テキストが論理的にいくつかの範囲に分割されているということです。折り畳みの機能を使えば、分割されたテキストの1つの範囲を「折り畳んで」1行にして、短い説明を表示させることができます。このような折り畳みと呼ばれる行範囲で使えるコマンドはたくさんあります。折り畳みは入れ子にできます。

Vimの折り畳みの方法はいくつかに区別されます。

‘foldmethod’ 使い方
diff diffウィンドウ内で使用して、未変更のテキストを折り畳む
expr foldexpr を使って、要するに折り畳みのメソッドを新規に作成します
indent インデントの数で折り畳みのレベル(深さ)を決めて折り畳みます
manual zf zF :fold を使って手動で折り畳みます
marker テキスト(多くはコメント)内のマーカーに基づいて折り畳みます
syntax 構文により折り畳みます 例: if ブロックの折り畳み

注:折り畳みの機能はリソースを大量に使います! もしパフォーマンスの低下(タイピング時の遅延)があれば、 FastFold のページを参照して、Vimが折り畳みを不要時にアップデートしないようにしてください。

関連するヘルプ:

:h usr_28
:h folds

セッション

ビュー :h :mkview )を保存すると、ウィンドウの設定(とそれに関連したオプションやマッピング)が保存されるので、後で復元して作業を再開することことができます。( :h :loadview

セッション は全てのウィンドウのビューとグローバルな設定を保存します。基本的にはVimのインスタンスのスナップショットが作成され、セッションファイルに保存されます。

これで プロジェクト を完全に保存できますし、プロジェクト間の切り替えも簡単に行えます。

それでは試してみましょう! ウインドウとタブをいくつか開いて、 :mksession! Foo.vim を実行してください。ファイル名を省略した場合は、 Session.vim に保存されます。ファイルはカレントディレクトリに保存されます。カレントディレクトリは :pwd で確認してください。Vimを再起動して :source Foo.vim を実行したら、ほらこの通り、バッファリスト、ウィンドウのレイアウト、マッピング、作業ディレクトリ他が全てセッション保存前と同じ状態です。

ただ、セッションファイルはVimコマンドの集合体に過ぎない、ということは気に留めて、いつでも :vs Foo.vim を見てください。

'sessionoptions' を設定すれば、セッションのどの部分を保存するかVimに指定できます。

関連するヘルプ:

:h Session
:h 'sessionoptions'

局所性

ここまでに挙げたグローバルな概念の多くには、相対するローカルな概念があります。

[TABLE]

また、変数にはいろいろなスコープがありますが、 Vim scripting の中に説明があります。

監修者
監修者_古川陽介
古川陽介
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
複合機メーカー、ゲーム会社を経て、2016年に株式会社リクルートテクノロジーズ(現リクルート)入社。 現在はAPソリューショングループのマネジャーとしてアプリ基盤の改善や運用、各種開発支援ツールの開発、またテックリードとしてエンジニアチームの支援や育成までを担う。 2019年より株式会社ニジボックスを兼務し、室長としてエンジニア育成基盤の設計、技術指南も遂行。 Node.js 日本ユーザーグループの代表を務め、Node学園祭などを主宰。