vimで逆方向の行削除コマンドを作る

vimでは ddコマンドで現在オンカーソルな行を削除できます。
[count]dd とキータイプすれば現在行含み count下の行まで一気に削除できて便利です。僕は仕事柄膨大な行数のデータファイルを扱うことがままあり、その際に [count]dd はよく使用しているのですが、[count]ddライクに上方向にも行削除もできたらなぁ、とよく考えていました。そこで今回、vimスクリプトの勉強も兼ねて実装にチャレンジしてみました。

実装

ddの動作イメージから、以下のように動くことを目標とします。

  • 「キー」をタイプするとオンカーソル行削除
  • [count]「キー」でオンカーソル行含め上方向count行分を削除
  • [count] 指定での操作で1行目まで削除したら、それ以上は削除しない。

以下のように vimスクリプトを組みました。

1
2
3
4
5
6
7
8
9
10
11
function! ReverseDelete(count)
let ddc = v:count1
let lnum = line('.')
if ddc > lnum
let ddc = lnum
endif
if ddc > 1
execute "normal!" (ddc - 1) . "k"
endif
execute "normal!" ddc . "dd"
endfunction

この関数を <Space>ddキーにキーマップします。

1
nnoremap <Space>dd :<C-u>call ReverseDelete(v:count1)<CR>

動作

実際に動かしてみます。4<Space>ddと入力します。

動きました!1行目や最終行にオンカーソルな状態でも期待通り動作します!
ここで満足しかけたのですが、上記の実装では vimの便利機能であるドット”.”キーによる操作の繰り返しができませんでした。これは不便です。なんとかドットリピート対応したい。

ドットで繰り返せるようにする

Vim script テクニックバイブルとかウェブの情報とか色々調べたところ、delisさんの以下の記事に行き当たりました。

空行を挿入する+α - derisの日記

後半にドットリピートについて言及されていました。どうやら repeat.vim を使えばできそうです。repeat.vim をインストールし、キーマップを以下のように変更してみました。

1
nnoremap <Space>dd :<C-u>let b:ddcount = v:count1 \| call ReverseDelete(v:count1) \| silent! call repeat#set("<Space>dd", b:ddcount)<CR>

動かしてみます! 2<Space>dd とタイプしドットリピートします!

出来ました!ちゃんと[count]分だけ上方向に行削除できて、ドットで繰り返すことができます!
やった!

今回は初めてvimスクリプトを書いて色々勉強になりました。あと、GIFアニメ付きの記事を投稿するに当たり deris さんのブログにお世話になりっぱなしでした。Gifzo便利。