rengbang.vimにフォーマット指定とコマンドライン確認版コマンドを追加しました

Vim

rengbang.vimにフォーマット指定とコマンドライン確認版コマンドを追加したのでご紹介します。

はじめに

rengbang.vimは、Vimで連番を入力するためのVim pluginです。

以下のブログでご紹介しています。

Vimで連番を入力するためのVim pluginを作った

連番入力時のフォーマットを指定可能に

rengbang.vimで連番入力する際、001.,002.のような連番を入力したい時がちょくちょくあって、 Lingrでもthincaさんからご要望いただいたので追加しました。

以下にようにRengBangコマンドの第5引数に%03d.\ と指定することで、 001.のような連番入力が可能です。

" フォーマットに%03d\ と指定することで001., 002. のように連番入力できます。
:RengBang \(\d\+\)  0  1  0  %03d.\ 

RengBang10

なお、内部でprintf関数を使っているので、フォーマットはprintf関数の フォーマットで指定する必要があります。

printf関数のフォーマットが使えるので、例えば16進数で連番入力したい場合は 以下のようにすることも出来ます。

" フォーマットに%04Xと指定することで16進数で連番入力できます。
:RengBang \(\d\+\)  0  1  0  %04X.

RengBang16

コマンドラインでパラメータを指定できるコマンド追加

以前からRengBangコマンドの引数が多く、入力しづらくてどうにかしたいと 思っていました。

上記フォーマット指定追加により、引数が5個になり、フォーマットを指定するためには、 (他の引数の指定が不要でも)第4引数まで指定が必須で入力しづらく、これはもう駄目だと思い、 別インターフェース(RengBangConfirm)を用意することにしました。

RengBangConfirmコマンドは引数を指定せずに実行するコマンドで、 実行するとコマンドラインでパラメータの入力を確認します。 この際、デフォルト値が入力されている状態で確認するため、 変更の必要がなければそのまま<Enter>を押すだけですむため、 RengBangよりも入力が楽です。

以下のgifアニメのように動作します。

RengBangConfirm

フォーマットだけ変更したい場合は、4回<Enter>をタイプ してフォーマットだけ変更して実行できます。

また、パターンだけ入力したい場合は、1つ目の確認でパターンを入力した後、 <Esc>をタイプすることで、その後のパラメータの確認をスキップ(デフォルト値使用) することもできます。

パラメータ確認の順番のカスタマイズ

RengBangConfirmの追加でパラメータの入力は大分楽になったのですが、 5番目に確認するフォーマットは、他のパラメータよりも使用頻度が高そうなので 確認順番をカスタマイズできるようにしました。

以下の様に変数に確認したい順番を指定することでカスタマイズ可能です。

" デフォルトのRengBangConfirmでの確認の順番の設定
let g:rengbang_default_confirm_sequence = [
  \ 'pattern',
  \ 'start',
  \ 'step',
  \ 'usefirst',
  \ 'format',
  \ ]
" 以下の様にRengBangConfirmでの確認の順番を配列で指定できます。(formatを3番目に変更)
let g:rengbang_default_confirm_sequence = [
  \ 'pattern',
  \ 'start',
  \ 'format',
  \ 'step',
  \ 'usefirst',
  \ ]
" デフォルト値から変更しないパラメータは省略することもできます。
let g:rengbang_default_confirm_sequence = [
  \ 'pattern',
  \ 'start',
  \ 'format',
  \ ]

.vimrcに書いておくことで常に指定した順番で確認するようになります。

上記2番目の設定をした上でのRengBangConfirmの動作は以下です。

RengBangConfirmCustom

一応補足しておくと、g:rengbang_default_confirm_sequenceでのカスタマイズ はRengBangConfirmコマンドの確認順番のみ変更します。 RengBangコマンドなどの他のコマンドの引数の順番を変えるわけではありません。 (少なくとも今のところは。要望があれば変更するかも)

終わりに

自分の作業用に作っているVim pluginですが、興味があれば試してみてください。

Happy Vim Life!

Vimmerなら2013年中に試しておきたい海外産Vim plugin 8選

Vim

この記事はVim Advent Calendar 2013の15日目の記事です。
14日目はjoker1007さんによるwebapi-vimとBufWriteCmdでWeb上のリソースをVimで編集するでした。

本記事では、2013年中に試しておきた海外産Vim pluginを8個ご紹介します。

はじめに

なんで海外産限定なの?

理由は以下のとおりです。

  • 日本産のVim pluginは入れている人が多く日本語での情報も多い(vimrc読書会に参加した感覚として)
  • Vim Advent Calendar 2012が1年続いたこともあり、興味深い日本産Vim pluginが多すぎる…

海外でそこそこ流行っていても日本ではあまり知られていないVim pluginが多いのでもったいなーと思ったので、本記事を書こうと考えました。

ちなみに、今回ご紹介するのは今年私が見つけたVim pluginに限定しています。このため、海外産でも昔からある有名な plugin(surround.vimsyntastic.vimなどなど)についてはご紹介していません。

なお、海外産Vim pluginは日本産と比較すると、以下のようにあまりお行儀のよろしくないVim pluginの比率が多いので、使うときには注意した方がいいです。
(今回ご紹介したもののなかではほとんどありませんが)

  • pluginディレクトリ配下にすべてのコードを配置していてる(plugin配下は起動時に読み込まれるため起動が遅くなる)
  • デフォルトキーマッピングを無効化出来ない
  • キーマッピングを変更できない

もちろん全部が全部ではないですし、日本産でも同じようなものもありますが、比較すると多いように感じます。

海外産Vim pluginはアイディアが面白いものも多いので、どんどん新しいpluginを試してみることをおすすめします。 使ってみて気になる所があればpull requestを送るか、最悪気に入らない所があればforkしてオレオレ魔改造版を作るのもありです。 (それでも足りなければオレオレpluginを1から…)

では、本編に移ります。

vim-startify

Vimの起動画面に、直近で開いたファイルや、ブックマークしたファイルなどをショートカットで開ける画面を表示するpluginです。

以下にスクリーンショットを載せます。

画像

本pluginをインストールしておくと、上記画像記載のように、Vimの起動画面に 最近使ったファイルなどのパスが表示されます。 該当ファイルの先頭の数字、アルファベットをタイプするか、該当ファイルに カーソルをあわせ<Enter>を押下すると、対応するファイルを開けます。

インストールするだけでも便利ですが、自分で表示するファイルをカスタマイズしたりもできます。

設定項目は色々あるので、詳細は:help startifyでhelpを見ていただきたいですが、便利な設定を3つほど載せておきます。 以下の様に用意されている変数で設定できます。

" startifyのヘッダー部分に表示する文字列を設定する(dateコマンドを実行して日付を設定している)
let g:startify_custom_header =
  \ map(split(system('date'), '\n'), '"   ". v:val') + ['','']
" デフォルトだと、最近使ったファイルの先頭は数字なので、使用するアルファベットを指定
let g:startify_custom_indices = ['f', 'g', 'h', 'r', 'i', 'o', 'b']
" よく使うファイルをブックマークとして登録しておく
let g:startify_bookmarks = [
  \ '~/.vimrc',
  \ '~/localrepos/blog/vac_20131215.md',
  \ ]

vim-multiple-cursors

Sublime Text の機能として有名な、multiple cursorsの機能をVimに移植したpluginです。

multiple cursorsの機能とは、操作対象の箇所を複数選択した状態で、視覚的に操作内容を 確認しながら一括操作できる機能です。

Vimは、操作対象の特定、操作、そして操作繰り返すということが容易なので、Vim的に常用して 便利かというと微妙なところですが、内容的に興味深いので載せました。

(久しぶりに使ってみたら変な挙動をしたので試される方はご注意ください)

(海外でも一時的に話題になっていたのでgithubでのstarが1900近くいっています。すごい)

ちなみに、Vimでのmultiple cursors実装は、これ以外も色々あるようです。

ただ、私は上記理由から使ってません。Vimmerなら検索、操作、.での繰り返し、 マクロ、:substituteコマンドなどを組合せて使ったほうが速い、ですよね?

複数箇所を視覚的に操作内容を確認しながら編集したいのであれば、 操作感、機能的には異なるものですが、manga_osyoさん作のover.vim を使った方が使い勝手が良いように思います。

over.vimは、昨年のVim Advent Calendar 2012でも ご本人が紹介されていたので、ここではブログ記事のご紹介までにします。

Vim の :substitute をプレビューするプラグインつくった

vim-expand-region

visual modeでの選択範囲を、さらに外側にあるtextobjectsに拡張して選択したり縮小して選択したりすることが出来るpluginです。

以下にスクリーンショットを載せます。

f:id:deris:20151120010343g:plain

上記スクリーンショットでは、初めはiw、続いてiWibil(textobj-lineインストール要)と 拡張して、その後、逆順で縮小しています。

拡張、縮小するときに考慮するtextobjectsは以下の様にvim-expand-regionのグローバル変数で変更することができます。

" デフォルトの設定
let g:expand_region_text_objects = {
  \ 'iw'  :0,
  \ 'iW'  :0,
  \ 'i"'  :0,
  \ 'i''' :0,
  \ 'i]'  :1,
  \ 'ib'  :1,
  \ 'iB'  :1,
  \ 'il'  :0,
  \ 'ip'  :0,
  \ 'ie'  :0,
  \ }

上記のようにtextobjectsをキーとした辞書をグローバル変数に設定します。

値は、01を指定します。textobjectsがネストする場合は1、しない場合は0を指定します。

ちなみに、il, ieは、標準Vimのtextobjectsではなく、Vim pluginで追加可能なtextobjectsです。iltextobj-lineietextobj-entireどちらも便利なtextobjectsなので、試してみることをおすすめします。

また、上記グローバル変数名の後ろに_{filetype}をつけることによって、filetypeごとに設定を変えることができます。

" Rubyのときだけ有効な設定は以下の変数で設定できる
let g:expand_region_text_objects_ruby = {
  \ 'iw'  :0,
  \ 'iW'  :0,
  \ 'i"'  :0,
  \ 'i''' :0,
  \ 'i]'  :1,
  \ 'ib'  :1,
  \ 'iB'  :1,
  \ 'il'  :0,
  \ 'ip'  :0,
  \ 'ie'  :0,
  \ }

脱線(submode.vimを使って入力しやすく)

私はexpand-regionでデフォルトのキーマッピングである+_は使用していません。 expand-regionを使う時は、大抵の場合、繰り返し拡張を行うため、マッピングするキーによっては 繰り返し入力するのが面倒になります。
私は拡張のキーマッピング,eに設定しているのですが、単純にキーマッピングすると、 連続して拡張する際は,e,e,eと入力する必要があり、若干入力しづらいです。
また、縮小用に別でキーマッピングする必要があり、これを考慮するとあまりマッピングするキーは 増やしたくないため、拡張は,ee、縮小は,esなどとする必要があり、,ee,ee,eeと更に入力しづらくなります。

こういう、なにかの操作をやっている間に繰り返し入力する必要があるような場合は、 submode.vimを使うと便利です。

submode.vimをインストールして、 以下の設定をすると、,eでexpand-regionのモードに入り、以降はeで拡張、 sで縮小できます。

" expand-regionモードの設定。,eでモードに入り、eで拡張、sで縮小できる
call submode#enter_with('expand-region', 'nv', 'r', '<Leader>e', '<Plug>(expand_region_expand)')
call submode#map('expand-region', 'nv', 'r', 'e', '<Plug>(expand_region_expand)')
call submode#map('expand-region', 'nv', 'r', 's', '<Plug>(expand_region_shrink)')

スクリーンショットでもsubmode.vimを使っています。

,eeeeなどとできて便利です。

splitjoin.vim

1行のコードを文脈的に同じ意味の複数行のコードに相互変換するpluginです。

以下にスクリーンショットを載せます。

f:id:deris:20151120010337g:plain

スクリーンショットでは、Rubyの一行コードを複数行コードに変換しています。

本pluginはfiletypeによっていくつかの変換ルールが定義されています。

12/15(日)現時点では以下の言語の変換ルールが定義されています。

自分が望む言語の変換ルールがなければ、pull requestを送ってみてはいかがでしょうか?

linediff.vim

visual modeで2組の行を選択し、選択した2つのdiffをvimdiffで表示できます。

以下にスクリーンショットを載せます。

f:id:deris:20151120010326g:plain

比較したい行を、visual modeで選択した上で、:'<,'>Linediffコマンドを実行し、 さらに比較対象の行をvisual modeで選択した上で同様に、:'<,'>Linediffコマンド を実行すると、両者のdiffを新しくタブページを開き表示します。

デフォルトでは、新しくタブページを開き垂直分割で開きますが、以下の グローバル変数を変更することにより、好みによってカスタマイズすることもできます。

" 1つ目に選択した行をタブページで開く
let g:linediff_first_buffer_command = 'tabnew'
" 2つ目に選択した行を垂直分割して新しいウィンドウで開く
let g:linediff_second_buffer_command = 'rightbelow vertical new'

textobj-word-column.vim

同列にある単語を矩形選択で選択したりoperatorの対象として指定したりすることができるpluginです。

以下にスクリーンショットを載せます。

f:id:deris:20151120010345g:plain

例では同列にある単語をvicで選択した後、cで編集してます。同様にしてdicで削除したり、cicで編集したりすることができます。

同列の単語を一括して編集したいときにわざわざ<C-v>で矩形選択して調整しなくても、ざっくり選択できるので便利です。

ちなみに、本pluginは、最初に述べたあまり行儀の良くないpluginに属するため(pluginディレクトリ配下にすべてのコードを配置)、 気になる方は、これを解消したLindanさんのfork版を使うことも検討してもよいかもしれません。

ただ、Lindanさんのfork版は以下2点の外部インターフェースが異なるため、使うのであれば注意が必要です。

  • デフォルトのkey mappingがoriginal版と異なる。(original版が、ic,acなのに対し、Lindanさんのfork版は、iv,av)
  • kanaさん作のVim pluginである、textobj-userが必須となる。(多くの便利なtextobjectsが本pluginを必須としているためインストールしておくことをおすすめします)

switch.vim

文字列のトグルができます。

以下にスクリーンショットを載せます。

f:id:deris:20151120010340g:plain

例えば、trueという文字列上で、:Switchコマンドを実行することによりfalseという文字列に変更できます。 逆も同様です。

毎回コマンドを実行するのはめんどうなので、実際に使う際は直接コマンドを実行するの ではなく、以下の様に何かしらのキーにマッピングして使います。 (上記スクリーンショットでもマッピングしたキーで操作しています。)

" <Space>mに、switch.vimをマッピング
" nnoremap <Space>m  <Plug>(switch-next)
" 12/16 修正
nnoremap <Space>m  :<C-u>Switch<CR>

なお、toggle系のpluginは色々ありますが、本pluginは、 正規表現での設定によりかなり柔軟な設定ができることが特徴です。 また、グローバル変数の辞書で設定するのでカスタマイズも比較的容易です。

vim-signify

VCSの差分をsignで表示するpluginです。

以下にスクリーンショットを載せます。

f:id:deris:20151120010333g:plain

:SignifyToggleコマンドを実行すると、VCSの差分がVimのsignで 表示されます。 また、上記スクリーンショットの例では、次の差分、前の差分 への移動をマッピングしたキーで行っています。

差分の移動は以下の様にキーにマッピングしておくと便利です。 また、合わせて:SignifyToggleマッピングしておくと便利でしょう。

" 次の差分箇所に移動
nmap <Leader>gj <Plug>(signify-next-hunk)zz
" 前の差分箇所に移動
nmap <Leader>gk <Plug>(signify-prev-hunk)zz
" 差分箇所をハイライト
nmap <Leader>gh <Plug>(signify-toggle-highlight)
" 差分表示をトグルする(:SignifyToggleコマンドと同じ)
nmap <Leader>gt <Plug>(signify-toggle)

おまけ

新しいVim pluginを発掘する方法

新しいVim pluginを発掘するには以下の様な方法があります。

皆さんも試してみてください。そして面白そうなpluginがあったら 是非Vim Advent Calendarに投稿してみてください。

ちなみに、上記の中では「vimrc読書会に参加する」 が特にお勧めです。

今回ご紹介したpluginの作者

今回ご紹介したpluginはよくよく見てみると、作者が同じ方のものが結構あります。

作者ごとにまとめてみました。

AndrewRadevさんのpluginが3つもありますねw 面白いpluginを書く方は、他にも面白いpluginを書いている可能性が高いので、 作者のリポジトリを眺めてみるのも良いかもしれません。

まとめ

以上が、2013年中に試しておきたい海外産Vim plugin 8選でした。

本記事で紹介する以外にも海外産Vim pluginはたくさんあるので、 興味があればいろいろ調べて見てはいかがでしょうか?

(そしてVim Advent Calendar 2013のネタとすると一石二鳥)

本題とはそれますが、Vimレベルが上がるのでvimrc読書会に参加することをおすすめします。毎週土曜日23時からやってます。

それではVim Advent Calendar 2013の15日目を終わります。

明日のVim Advent Calendar 2013はc0hamaさんです。

VimConf2013に参加しました

日付的には昨日になってしまいましたが、本日(11/16(土))にクックパッド株式会社で開催されたVimConf2013に参加してきたので参加レポートをば

そして、この記事はVim Advent Calendar 2012の352日目の記事を兼ねてます。 351日目はsynganさんによるvim-gitlab 作ったでした。

LTしました

以前Vim Advent Calendar 2012でも記事を書いたduzzle.vimというVimでできるパズルゲームについてLTしました。スライドは以下です。

一応国際カンファレンスということで、英語でスライドを作成しましたが、英語はGoogle翻訳先生に頼り切りでした…
もしおかしな英語を見つけたらご指摘いただけるとありがたいです。(あとで修正できるのかな…)

実は、プレゼン直前にゲーム画面のハイライト(色付け)のために作ったsyntaxファイルが無くなっている事に気づき 泣きながらLT直前までsyntaxファイルを作りなおしていたという背景があったりしました…

(git addしたつもりがしていなくてなんか適当に操作してたら消えてしまったらしい…)

今となってはいい思い出ですw

雑多な感想

詳細な感想は他の方にお任せして雑多な感想をば

  • 最初から最後まで感極まってた
  • Vimmerとのランチ楽しかった
  • Kaoriyaさんのプレゼンに圧倒された。
  • クォートのtextobj、Kaoriyaさんが作ったということを知って衝撃を受けた。スゴすぎる
  • 皆さんのプレゼン非常に濃ゆくてすごかった
  • LT前の私のテンパリ具合がやばかった
  • 歌があれであれだった
  • 懇親会、daisuzuさんとの転職話や、cohamaさんとまさかの同会社話や、色々なVimmerの方とお話出来て楽しすぎた
  • だいぶVimmerの知り合いできてきてうれしい

終わりに

まだ、興奮冷めやらぬ感じですが、ほんとに感極まりっぱなしで非常に濃い一日を過ごすことが出来ました。

主催のujihisaさん、VimConf2013運営にかかわられた方、クックパッドの方、美人受付のさっちゃんさん、発表者の方、参加者の方、皆さん本当にありがとうございました。

また次回のVimConf2014もしくはxxx.vimでお会いしましょう。

そして、明日のVACはまだ決まっていないですが、他の方のVimConf2013の参加レポを期待しましょう!

Happy Vim Life!

momonga.vim#2に参加しました

遅くなってしまいましたが、10/13(日)に武蔵境で開催されたmomonga.vim#2に参加したので、感想レポートをば

昼食

会場ともなった武蔵境プレイスで、参加者5名でお昼食をご一緒しました。 武蔵境プレイスが想像以上にお洒落空間でちょっと場違い感を感じつつも、カフェで優雅にランチ。 ランチの場ではVimmer特有のシャイフィールドを作りつつも小粋なVimトークで花をさかせつつ?美味しいランチを頂きました。

TokyoVimに参加して人生が変わりました! - daisuzu's notesを書かれたdaisuzuさんが隣にいらっしゃったので少しだけ 転職の話を少しお聞きするなどして有意義な時間を過ごすことができました。

もくもく会

以下簡単にもくもく会の成果をば

やったことは以下3点

  1. 鳩サブレ
  2. capslock.vimにpull request
  3. Sticky Shiftを改良(capslockも可能に)

鳩サブレ

おやつに鳩サブレ持って行きました。

人数分なくて食べれなかった方すいません。。。

capslock.vimにpull requestを送る

最近Sticky Shiftを使おうと色々調べてる過程で知ったcapslock.vim にpull requestを送りました。

capslock.vimVim Hacksでも紹介があったのでご存じの方もいるかと思います。

Vim-users.jp - Hack #47: 大文字を連続で入力する

capslock.vimVim上で仮想的にcapslock機能を提供するVim pluginです。

key mappingしてcapslockをenable,disable,toggleしたりできます。

ただ、現状のcapslock.vimでは、 切り替えられるのはa-zA-Zだけで、0-9や記号などをcapslockで切り替える ことができません。

このため、1-9や記号などもcapslockで切り替えられるように修正して pull requestを送りました。 (10/19 15:40時点 未取込)

修正はグローバル変数でcapslockで切り替えるキーをカスタマイズ出来るように したことです。 以下の様な設定をvimrcに書いておけば、数字や記号も capslockで切り替えることができます。

" capslock for US keyboard
let g:capslock_key_mapping = {
  \ '1': '!',
  \ '2': '@',
  \ '3': '#',
  \ '4': '$',
  \ '5': '%',
  \ '6': '^',
  \ '7': '&',
  \ '8': '*',
  \ '9': '(',
  \ '0': ')',
  \ '`': '~',
  \ '-': '_',
  \ '=': '+',
  \ '[': '{',
  \ ']': '}',
  \ '\': '|',
  \ ';': ':',
  \ '''': '"',
  \ ',': '<',
  \ '.': '>',
  \ '/': '?',
  \ }

上記グローバル変数の辞書で設定しておけば、capslock切替時に keyvalueに変換することができます。

Sticky Shiftを改良(capslockも可能に)

上記capslock.vimは実は本題ではなく 本題はこちらでした(pull req送ったものの、結局自分では使う予定ない。。。)。

Sticky Shiftでちょっと使いづらいところがあったので改良しました。 (Sticky Shiftの改良と言うよりは、併用して使うcapslock追加と言ったほうが正しいかな)

VimでSticky Shift使う方法はVim Hacksでも紹介されており、自分も最近この設定をしてSticky Shiftを使用しています。

Vim-users.jp - Hack #54: VimでSticky Shiftを実現する

基本的には上記設定で十分なのですが、たまにSticky Shiftではなくcapslock的な操作をしたいことがあり、 その際はSticky Shiftだと、毎回;x;x;x;xのような操作をしなければならず 普通にShiftを使うより打ちづらくなってしまいます。

このため、capslockしたい場合にはcapslockするように設定を追加しました。

設定の追加は上記でpull reqしたcapslock.vim ではなく、みんな大好きsubmode.vimで実現することにしました。

設定は以下です。 ;<Tab>でcapslockに切り替えられるようにしています。

" capslock for US keyboard
let s:capslock_key_set = {
  \ '1': '!',
  \ '2': '@',
  \ '3': '#',
  \ '4': '$',
  \ '5': '%',
  \ '6': '^',
  \ '7': '&',
  \ '8': '*',
  \ '9': '(',
  \ '0': ')',
  \ '-': '_',
  \ '=': '+',
  \ '[': '{',
  \ ']': '}',
  \ ';': ':',
  \ '''': '"',
  \ ',': '<',
  \ '.': '>',
  \ '/': '?',
  \ '`': '~',
  \ ' ': ';',
  \ }
call submode#enter_with('capslock', 'cis', '', ';<Tab>', '<Nop>')
call submode#leave_with('capslock', 'cis', '', '<Tab>')
for s:char in range(char2nr('a'), char2nr('z'))
  call submode#map('capslock', 'cis', '', nr2char(s:char), nr2char(s:char-32))
endfor
unlet s:char
for [s:lhs, s:rhs] in items(s:capslock_key_set)
  call submode#map('capslock', 'cis', '', s:lhs, s:rhs)
endfor
unlet s:lhs
unlet s:rhs

submode.vimでinsert modeのmappingを するとなぜかカーソル位置で)が表示されるのが玉に瑕ですが、 実害はないので気にしないことにしました。 (わかりやすいように表示してるのかな?)

雑多な感想

  • unmoremasterさんがいつもの?アノニマス仮面を会議室の外からかぶってきてとてもシュールだったw
  • メンバーが濃ゆかった(名だたるVimmerが勢ぞろい)
  • puyo.vimがすごいことになってた
  • スペシャルゲストがShougoさんだったなんて全然気づかなかったわー(棒)
  • Shougoさんがまさかあんな格好で写真を撮られるとは。。。
  • MBP 15inch Retina欲しい。。。
  • 二次会でdaisuzuさんの転職話もっとお聞きしたかった
  • 二次会でVim談義もっと(ry

終わりに

家族の集まりがあったため、二次会以降参加できなかったのが唯一の心残りでしたが Lingrでの三次会の会話にも若干混ざったりもして、一日楽しい時間を過ごすことが出来ました。

主催のsupermomongaさん、参加者の皆さん、ありがとうございました。

また、momonga.vimもしくはxxx.vim(直近ではVimConfかな?)でお会いしましょう。

Happy Vim Life!

Vimで編集を効率的に行うための繰り返し操作について

Vim

この記事はVim Advent Calendar 2012の232日目の記事です。
231日目はrbtnnさんによる`vimproc#system({expr})`の{expr}の展開のされ方でした。

本記事は、Vimで編集を効率的に行うための繰り返し操作について記載します。

カーソル位置の単語編集の繰り返し

カーソル位置の単語を編集して同じ単語の編集をファイル内で繰り返したい場合、 以下の順で実行します。

  1. *でカーソル位置の単語で前方検索する
  2. (必要に応じて)Nで最初の位置に戻る(私は**Nをマッピングしてます)
  3. ciwでカーソル位置の単語を削除し編集する
  4. n.で単語の編集を繰り返し
  5. 確認不要だったり量が多ければ%s//<C-r>./g

以下は上記操作のGIF画像です。 screenshot1

最初から:substituteコマンドを使う事も考えられますが、 検索で確認しながら、編集に移行するかどうかを判断できるので 上記のようにまずは.での繰り返しを考えます。

:substituteのオプションでcをつけることにより確認もできます :%s/foo/bar/gcのように実行します。

上記では*を使っていますが、g*で、カーソル行の単語を 他の単語の一部として検索して置換することもできます。

  1. g*でカーソル位置の単語で前方検索する
  2. (必要に応じて)Nで最初の位置に戻る
  3. vと移動(lなど)で単語を選択し、cで編集する
  4. n.で単語の編集を繰り返し
  5. 確認不要だったり量が多ければ%s//<C-r>./g

以下は上記操作のGIF画像です。 screenshot2

visual modeで選択したテキストで検索できる visualstar.vimというVim pluginも合わせて使うと更に便利です。

検索でマッチする(しない)行を削除

:globalコマンドと:deleteコマンドを組み合わせて実行します。

" fooにマッチする行をすべて削除する
:g/foo/d

逆に検索でマッチしない行を削除したい場合 :vglobalコマンドと:deleteコマンドを組み合わせて実行します。

" fooにマッチしない行をすべて削除する(:vglobalコマンド使用)
:v/foo/d

編集の繰り返しとは話が若干それますが、:globalコマンドと:yankコマンドを 組み合わせて検索にマッチする行をすべてレジスタにコピーすることができます。

" aレジスタに検索にマッチする行をすべてコピー

" aレジスタをクリア
:let @a = ''
" fooにマッチする行をすべてヤンクしてaレジスタに追加(大文字で追加になる)
:g/foo/y A

コマンド繰り返し

@:で最後に実行したコマンドを実行できます。
例えば:bnコマンドを実行したあと@:で繰り返せばバッファ移動を繰り返せます。

:global:substituteコマンドを繰り返すこともできます。

:substituteコマンドは、&g&:&&などで繰り返すこと もできます。それぞれの意味は:help &などで調べて見てください。

マクロで繰り返し

マクロは難しいと思われている方もいるかもしれませんが、慣れればとても便利なので使ってみましょう
マクロを使いはじめるには、まずは行単位の操作をマクロとして記録することをおすすめします。

例:検索にマッチする行の行頭と行末に特定の文字列を挿入する

検索にマッチする行の、行頭と行末に特定の文字列を挿入する操作をマクロとして記録したい場合、以下のようにタイプします。

/fooのように検索したうえで

qqI/*<Esc>A*/<Esc>nq

を実行します。

上記を分割すると
qq:マクロ記録開始
I/*<Esc>:行頭に/を挿入
A*/<Esc>:行末に
/を挿入
n:検索前方移動
q:マクロ記録終了
となります。

これでqレジスタにマクロが記録されたので@qで同じ操作を繰り返せます。
マクロはcountが使えるので9@qなどと指定することでマクロを複数回実行出来ます。

以下は上記操作を繰り返したGIF画像です。 screenshot3

最後にエラーが発生していますが、これは9@qでマクロをcount指定で 実行した際、nの検索で検索文字見つからなかったために表示されたものです。
countでの繰り返しの中でエラーが発生するとマクロ操作が途中で止まるため、 検索でマッチする数がわからなくても適当に999@qなど、countを適当に指定して繰り返し実行できます。

複数ファイル一括操作

複数ファイル一括操作には、argdobufdowindotabdoなどが使用出来ます。
それぞれの詳細は:help argdoなどで調べてください。

ここではargdoを例として説明します。

カレントディレクトリ内のすべてのファイルを一括編集するには argsargdoのコマンドを組み合わせて実行出来ます。

" カレントディレクトリ内の拡張子がvimのファイルをすべてargdoの対象にする
:args *.vim
" カレントディレクトリ内のファイルのすべてのfooをbarに一括置換
:argdo %s/foo/bar/g
" 上記編集結果をすべてのファイルで保存
:argdo update

:argdoする前に:set hiddenしておく必要があります。
カレントディレクトリは:pwdコマンドで確認できます。

カレントディレクトリ内のすべてのファイルにマクロ実行するには argsargdoのコマンドを組み合わせて実行出来ます。

" カレントディレクトリ内の拡張子がvimのファイルをすべてargdoの対象にする
:args *.vim
" カレントディレクトリ内のファイルにマクロ実行
:argdo normal! 999@q
" 上記編集結果をすべてのファイルで保存
:argdo update

ここでは:args *.vimなどとしましたが、vimfiler.vim というVim pluginでのファイル指定および、actionでexアクションからargsコマンドを使うことにより、 指定したファイルに対して一括操作ができます。

編集操作を繰り返す際の考え方

Vimでの編集操作の繰り返しは:help repeat.txtを見てもわかるように大きく3つあります。

  1. .での繰り返し
  2. :substituteglobalvglobalなどのコマンドでの一括編集
  3. マクロ(qx,@q)での繰り返し

私が編集操作を繰り返す際に考えるのは、上記の13の順に繰り返しで編集操作できないか考えます。
まずは.で繰り返せるものなら.で繰り返します。
.で対応できないような操作はコマンドかマクロで対応します。
コマンドとマクロのどちらを使うかは場合によります。単純なパターンを書けるのであれば :substituteなどのコマンドを使うことを先に考える場合もありますし、 ちょっとパターンを書くのが面倒そうであればマクロを先に考える場合もあります。

例えばマクロの例であげたの操作は、以下のように書いても実現出来ますが、パターンを考えなくていい分、マクロで考えた方が若干楽です。

:s/\s*\zs.*/\/*&*\//g

このバランスは使っていくうちにわかっていくと思います。

コマンド、マクロで実行した上で、更に他のファイルにも同じ操作を繰り返したい場合は @:でのコマンド繰り返しや、normal! 999@aでのマクロ操作繰り返しを使います。
更に複数ファイルある場合は、argdobufdowindotabdoなどを 使用して繰り返します。

おまけ

qfreplaceというVim pluginを使用することで、 grepした結果のquickfixウィンドウの該当する各行を別バッファで開き、 そのバッファ上で編集を行い保存することで、該当行を編集することができます。

以下はqfreplaceを使った操作のGIF画像です。

screenshot4

grepでNeoBundleを検索して、quickfixウィンドウを開き、 qfreplaceで開いた 別バッファ上で編集することで該当行を編集しています。
上記GIF画像は1ファイルだけで編集していますが、qfreplaceで 開かれる別バッファでは複数ファイルの該当行を一緒に編集することができるため かなり強力です。

まとめ

以上が、Vimで編集を効率的に行うための繰り返し操作についてでした。

編集の繰り返しを使いこなせれば、編集効率がかなり上がります。
繰り返し同じ事をしてるな、と思ったら本記事を参考にして色々と 試してみてください。
皆さんの編集効率が上がれば幸いです。

本題とはそれますが、Vimレベルが上がるのでvimrc読書会に参加することをおすすめします。毎週土曜日23時からやってます。

それではVim Advent Calendar 2012の232日目を終わります。

明日のVim Advent Calendar 2012はmanga_osyoさんです。