人生リアルタイムアタック

当面はPython学習帳

Vimのテキストオブジェクトを本気出して纏めてみた

Vimでエディットするにあたり、""で囲まれた部分を''にしたいとか、囲まれた部分の内側を置換したいとか、いい加減テキストオブジェクトを使いこなしたいなと思ったので調べつつ憶えてみる。

Vimのコマンドは何らかの単語の頭文字であるケースが殆どなので、コマンドの意味も纏めてみた。

そもそもテキストオブジェクトとは

オブジェクト単位で選択 *object-select* *text-objects*
*v_a* *v_i*

次のものはビジュアルモードかオペレータコマンドの後でのみ使うことができる一連の コマンドを示しています。
"a" で始まるコマンドは "a" (1つの) まとまりをホワイトスペースを含めて選択します。
"i" で始まるコマンドはまとまりの "inner" (内部) をホワイトスペースを含まずに選択するか、もしくはホワイトスペースのみを選択します。
ですので、"inner" コマンドは常に "a" コマンドより少なくテキストを選択する ことになります。

:help text-objects より。

端的に言うと、 従来単語の先頭にカーソルをあわせてから cw としてた所を、
先頭にカーソルをあわせずとも caw で「単語全体を編集」をしたり、 ci' で「'で囲われた内部を編集」が可能とするナイスなオブジェクトのことである。

オペレータコマンドのおさらい

一応オペレータコマンドのおさらい。

コマンド 意味 操作
c change 変更
d delete 削除
y yank ヤンク
~ 大文字/小文字入れ替え
g~ 大文字/小文字入れ替え
gu 小文字にする
gU go Uppercase 大文字にする

他にもzfで折り畳みを作成するなどがあるけどテキストオブジェクトと組み合わせそうにはなさそうなので割愛。
詳細は :help operator を参照で。

テキストオブジェクトのaとiコマンド

コマンド 意味 対象
a an object まとまり(記号を含む)
i inner まとまりの内側(記号を含まない)

a + <移動コマンド> のように指定する。aw なら "a word", iwなら "inner word"となる。
移動コマンドの修飾語のような扱いになる。

aとiコマンドの後に利用可能な移動コマンド

コマンド 意味 対象
w word カーソル前後の単語
W WORD カーソル前後の単語(ホワイトスペース含む)
s sentence カーソル前後の文
p paragraph カーソル前後の段落
[ ] カーソル前後の[]block
( ) または b block カーソル前後の()block
< > カーソル前後の<>block
t tag カーソル前後のtag block. ここでいうタグとはhtmlの<div>...</div>など
{ } または B Block カーソル前後の{}block
" や ' や ` カーソル前後の " や ' や ` それぞれのquote block

移動コマンド単体では使い方が良く分からないと思うので次へどうぞ。

テキストオブジェクトの使い方

上述の オペレータコマンド + a/i + 移動コマンド の組み合わせで使うのが一般的なテキストオブジェクトの利用方法である。

以下に実際の使い方の一例。

コマンド 意味 対象
daw delete a word カーソル前後の単語を削除する
da( delete a block カーソル前後()に囲まれた部分を()も含めて削除する
di( delete inner block カーソル前後の()に囲まれた部分を削除する
ca( change a block カーソル前後()に囲まれた部分を()も含めて変更する
ci( change inner block カーソル前後の()に囲まれた部分を変更する
das delete a sentence カーソル前後の文を削除する
dat delete a tag block カーソル前後のタグを削除する

最もよく使うのは c との組み合わせだろう。
ci' のクォートに囲われた部分の変更を私は既に良く利用している。

s のsentenceはノーマルモードでは( , )で移動する単位のもの。
利用するのであれば日頃からVimの文の単位を理解しておきたいところ。

t がめっちゃ使えそう。と思ったけど、終端タグ </something> があるタグじゃないとダメなので ci< などと使い分けが求められる。
普段からhjkl以外の移動にも慣れておくと、テキストオブジェクトも有効に利用できそうなのでいろいろ使って慣れておきましょう。

Surround.vim

括弧やクォートやタグなどの、文字列を囲むものを簡単に操作するVim Plugin。
テキストオブジェクトとセットで語られることが多いのでこちらも纏めて取り上げる。

github.com

Surround.vim の使い方

<オペレータコマンド> + s + <対象の括弧/クォート/テキストオブジェクト> + (<置換, 挿入する括弧/クォート>) という形で利用する。
英語のSVO型とSVOO型のような形を意識して README.markdown を試すと理解が進む。

まずはじめに"で括られたテキストを用意する

"Hello world!"

cs"' とtypeすると、"を'に置換する

'Hello world!'

cs'<span> とtypeすると、'をspanタグに置換する

<span>Hello world!</span>

cst" とtypeすると、spanタグを"に置換する

"Hello world!"

ds" とtypeすると、"を削除する

Hello world!

ysiw] とtypeすると、inner wordを[]で囲う

[Hello] world!

cs]{ とtypeすると、[]を{}に置換する *1

{ Hello } world!

yssb もしくは yss)とtypeすると、文を()で囲う

({ Hello } world!)

ds{ds{ とtypeすると、括弧を削除する

Hello  world!

ysiw<em> とtypeすると、inner wordをemタグで囲う

<em>Hello</em>  world!

Vで行選択後、S<span class='info'> とtypeすると、行をspan.infoタグで囲う

<span class='info'>
<em>Hello</em>  world!
</span>

あ、これ慣れると最高なやつだ。

  • ccs + <変更対象の括弧> + <変更後の括弧> で括弧の変更
  • dds + <削除対象の括弧> で括弧の削除
  • yys + <括弧で囲う対象のテキストオブジェクト> + 括弧 でテキストオブジェクトを括弧で囲う
  • ビジュアルモードでの呼び出しは S
  • 他のオペレータコマンド ~ とかは使えない*2

を憶えれば基本はOK.

Surround.vim のカスタマイズ

let g:surround_<ASCII code> = "<% \r %"> と.vimrcに書くと yss<ASCII code> などで置換できるようになる。*3

もっと詳しくカスタマイズしたければ :help surround を読めばOK.

まとめ

テキストオブジェクトで括弧内の文字列操作、
Surroud.vimで括弧の操作が楽に操作できるんや!!

Vimテクニックバイブル ?作業効率をカイゼンする150の技

Vimテクニックバイブル ?作業効率をカイゼンする150の技

参考

*1:cs]}ならスペースなし

*2:というか括弧類に対して働くコマンドではない。

*3:ASCII codeを調べるには :echo char2nr("-")