Note
この記事はVim 駅伝の 4/19 の記事です。
はじめに
VSCode などのテキストエディタには、マルチカーソルという機能があります。 これは、エディタ上に複数のカーソルを出現させ、一度に複数の場所に同じ操作を行うことができる機能です。
VSCode上でのマルチカーソル
自分はVSCodeをメインとしていた時にはこの機能を多用していたのですが、Neovimに移行してから一切使っていません。
一応Vim/Neovimにもマルチカーソルを実現するプラグインがいくつか存在します。 ですが、一度は入れてみるものの結局使わないままアンインストールしてしまいました。
https://github.com/terryma/vim-multiple-cursors https://github.com/mg979/vim-visual-multi https://github.com/brenton-leighton/multiple-cursors.nvim
ではなぜ、マルチカーソルが必要なくなったのか。 それはVim/Neovimの操作体系/機能が十分に強力であるので、マルチカーソルを使わなくても同じことができるからです。
この記事では、自分がVSCodeのマルチカーソルで行っていた操作をVim/Neovimの操作体系/機能でどのように行っているかを紹介します。
行の先頭に文字を追加する
例えば以下のようなテキストがあるとします。
foo
bar
baz
例えばこのテキストの行頭に1.を追加したいとします。
1. foo
1. bar
1. baz
この時、VimではVisual Blockモードを使うことで簡単に行うことができます。
0または^で行頭に移動するCtrl-vでVisual Blockモードに入るjやkで追加したい行を選択するIで挿入モードに入る- 追加したい文字列を入力する
Escで挿入モードを抜ける
Visual Blockモードを使って行の先頭に文字を追加する
行の末尾に文字を追加する
行の末尾に文字を追加する場合もVisual Blockモードを使うことで簡単に行うことができます。
Ctrl-vでVisual Blockモードに入るjやkで追加したい行を選択する$で行末に移動するAで挿入モードに入る- 追加したい文字列を入力する
Visual Blockモードを使って行の末尾に文字を追加する
追記: Visual Blockモードを使って数字をインクリメントする
Note
この章は@taniさんにリマインドしていただき、追記しました。
Visual Blockモードを使うと、数字をインクリメントすることも簡単に行うことができます。 例えば
1. foo
1. bar
1. baz
この時、Visual Blockモードで数字を選択し、 <Ctrl-a>/<Ctrl-x>を押すことで、数字を一気にインクリメント/デクリメントすることができます。
2. foo
2. bar
2. baz
もちろん一気に増やしたい時は、20<Ctrl-a>のように数字を指定することもできます。
さらに、g<Ctrl-a>/g<Ctrl-x>を使うことで、連番でインクリメント/デクリメントすることもできます。
この場合、数字を選択してからg<Ctrl-a>を押すことで、
1. foo
2. bar
3. baz
のように数字をインクリメントすることができます。
dial.nvimについて
さらに、Neovimのプラグインであるdial.nvimを使うことで、色々な形式の数字をインクリメント/デクリメントすることができます。
2024-12-29 hello
2024-12-29 hello
2024-12-29 hello
2024-12-29 hello
2024-12-29 hello
この日付をVisual Blockモードで選択して、`g<Ctrl-a>`を押すと
2024-12-29 hello
2024-12-30 hello
2024-12-31 hello
2025-01-01 hello
2025-01-02 hello
こうなる
カーソル下の単語の編集
Vimでは*を用いるとカーソル下の単語を前方検索することができます。
また、gnを用いると前方検索&ビジュアル選択を行うことができます。
さらに、cgnを用いると前方検索&ビジュアル選択&変更を行うことができます。
ところで、vimにはドットリピートという機能があり、直前の変更を繰り返すことができます^[ここ(https://qiita.com/Kta-M/items/d8fbded37ad3140cfeb0)やここ参照]。 これを使うと、直前の変更を繰り返すことができるので、繰り返し置換が簡単に行えます。
これらを組み合わせると、以下の操作でカーソル下の単語を繰り返し置換することができます。
*でカーソル下の単語を検索''で元の位置に戻る^[''もしくは``で直前のジャンプ位置に戻る(https://vim-jp.org/vimdoc-ja/motion.html#‘’)]cgnで単語を編集nで次の検索結果へ移動.で単語の置換を繰り返す(いわゆるドットリピート)
カーソル下の単語を繰り返し置換
このような操作を毎回行ってもいいのですが、いい感じにkeymapを設定してしまうと便利です。
vim.keymap.set("n", "<leader>*", "*''cgn")
*の挙動についての補足
標準の*や#では、現在のカーソルの位置から前方検索を行って次の検索結果にジャンプします。
そのため本文中にある通り*で検索を行った後に''で元の位置に戻る必要があります。
もしカーソルを移動したくない場合はvim-asteriskのようなプラグインを使うと便利です。
LSPを用いて変数を一括変更する
Neovimの組み込みのLanguage Server Protocol(LSP)クライアントを用いることで、変数名の一括変更を行うことができます。
:lua vim.lsp.buf.rename()
LSPを用いて変数を一括変更する
また inc-rename.nvimを用いると、変更中にプレビューが表示されるようになります。 https://github.com/smjonas/inc-rename.nvim
Buffer全体で単語を一括変換する
Vimには便利な置換コマンドが用意されています。
例えば、:s/foo/bar/g でBuffer全体でfooをbarに置換することができます。
これを利用して、自分は選択した範囲から置換コマンドを一発で呼び出せるkeymapを設定しています。
vim.keymap.set("x", "<leader>r", 'y:%s/<C-r><C-r>"//g<Left><Left>')
vim.keymap.set("n", "<leader>r", 'yiw:%s/<C-r><C-r>"//g<Left><Left>')
このコマンドのやっていることは以下の通りです。
yで選択範囲をヤンク:%s//gでBuffer全体に対して置換コマンドを開始<C-r><C-r>"でヤンクした内容をペースト^[<C-r><C-r>(https://vim-jp.org/vimdoc-ja/insert.html#i_CTRL-R_CTRL-R)]<Left><Left>で最初の//の間にカーソルを移動
選択範囲から置換コマンドを一発で呼び出す
より複雑な操作
ではもっと複雑な操作を考えてみましょう。 例えば、以下のようなテキストがあるとします。
foo
bar
baz
hoge
fuga
このテキストを以下のように変更したいとします。
[foo](https://example.com/foo)
[bar](https://example.com/bar)
[baz](https://example.com/baz)
[hoge](https://example.com/hoge)
[fuga](https://example.com/fuga)
このような操作はVisual Blockで一発で行うことは難しいです。 移動が伴うために、挿入モードで一発で行うことができず、ドットリピートも難しいです。
このような場合に使えるのがマクロです。 マクロは、複数の操作を記録して再生することができる機能です。
この場合だと以下のようなマクロを記録して再生することで簡単に変換することができます。
- 最初の行に移動
qqでqレジスタへのマクロの記録を開始- 最初の行の編集を行う^この場合だと`0yiwI[<esc>A(https://example.com/
p) j` ] qでマクロの記録を終了4@qでマクロを4回繰り返す(Neovimなら4QでもOK)
マクロを使って複雑な操作を行う
先の場合では、繰り返し回数を指定することで置換を行いましたが、他にもマクロの適用方法はあります。
例えば、gコマンドを使うことで、特定のパターンにマッチする行に対してマクロを適用することができます。
:g/foo/normal @q
このコマンドは、fooという文字列を含む行全てに対してマクロqを適用します。
検索結果に対して個別にマクロを適用したい時もあるかもしれませんね。
その場合は、先に述べた*&gnを使って一個ずつ@qでマクロを適用していくことができます。
(もちろん適用したい行までjやkで移動してもOK)
また行単位に限らず、Visualモードに入って
:'<,'>normal @q
を実行することで任意の選択範囲に対してマクロを適用することができます。
AIを使う
「Vimの操作覚えるのとかめんどくせえよ、そんなことちまちまやってられっかよ」という方にはAIを使う方法がおすすめです。
https://github.com/github/copilot.vim https://github.com/zbirenbaum/copilot.lua
GitHub Copilotを使ってコードを生成する
まとめ
- VSCodeなどのマルチカーソル機能は便利だが、Vim/Neovimの操作体系/機能で代替できる
- Visual Blockモード/マクロ/LSP/置換コマンドなどを使うことでマルチカーソルで行っていた編集をカバーできる
- AIは正義
おまけ
Neovim向けにEmacsでお馴染みのdmacroが実装されつつあるらしい…? https://github.com/tani/dmacro.nvim