💭

慣れてきた頃に知りたいVimの便利機能

2023/12/06に公開

自己紹介

Sun AsteriskでBEエンジニアをしているテツです。
Ruby on Railsを利用したバックエンドの実装や、Flutterを使ってモバイルアプリの開発、たまにPMと言う名の業務整理をやったりしています。

自分はエンジニア歴(約4年)≒Vim歴なのですが、周りでVimのユーザーが中々居なかった所に、最近同じPJで1人Neovimに入門したメンバーがいて、やっぱりVimって良いよね!、と布教欲が湧いたのでこの記事を書いています。

想定する読者

この記事の想定する対象読者はvimtutorを終えたVim又はNeovim入門者です。この記事では、vimでもNeovimでも共通で利用できる機能を紹介します。
自分がvimを始めた頃に知りたかった機能を纏めた物になってます。
基本的なモードの概念やカーソル移動などには触れないため、まだvimtutorを終えていない方は、vimtutor コマンド、Neovimの場合はNeovimを起動した中でTutor コマンドでチュートリアルを行なってください。

背景

同じPJに参加するメンバーが最近Neovimを使い始めたので、こんな機能もあるよ!みたいな話をしていたら...

プラグインの紹介をし始めると長くなってしまうので、この記事では基本的にはプラグインに依存しないデフォルトの機能を紹介していきます。

前提の説明

想定読者にも記載しましたが、vimtutorに記載されている内容は知っている前提で記載をしますが、1点事前に説明しておく点があります。

それがキー入力の記載方法について、具体的には<C-w>という表記についてです。
これはVimのキーマップを変更する時の記載方法で、<C-w>はCTRLキーとwキーを同時押しという意味です。<C-w><C-w>であればCTRLキーを押したままwキーを2回押す、という意味になり、<C-w>wならCTRLキーを押したままwキーを押した後にCTRLキーを話してwキーを1回押すという意味になります。

こちらの表記は他のVimについての記事やプラグインのREADMEなどでも良く見る表記なので、本記事でも利用していきます。

ヘルプの日本語化

まず最初に紹介するのはヘルプの日本語化です。
「プラグインに依存しないデフォルトの機能」と書いた直後にこの紹介を記載するのもアレですが、こちらはプラグインの追加が必要になります。これがあるか無いかでVimへの理解の深め方が全然違うものになるため、こちらは唯一の例外として紹介させて下さい。

helpの機能はvimtutorの中でも紹介されていますが、:help<F1>キーでヘルプを開く事ができます。しかし、vimturor自体もそうですが、表示されるヘルプは全て英語です。
いくらVim、Neovimに興味があるとはいっても、知識が少ない状態で英語のヘルプを読み解くのは相当に骨が折れます。
それを解決してくれるのがこちらのプラグインです。
https://github.com/vim-jp/vimdoc-ja
このリポジトリはvim-jpという日本のvimユーザーのコミュニティの中で、有志がhelpの翻訳を行なったものになります
以下のWEBサイトでも読むことができるので、プラグインを入れるのが面倒な人は、この後のプラグインのインストールの解説は飛ばしてもらって大丈夫です。
https://vim-jp.org/vimdoc-ja/

※ こちらはあくまでVimのヘルプを翻訳したものになるため、Neovimでは一部記載が異なる場合があります。Neovimユーザーは日本語で概要を理解した上で、英語のヘルプを見て違いが無いか確認するのをオススメします

プラグインのインストール

プラグインのインストールには以下の2通りがあります。

  1. runtimepathが通ったディレクトリにダウンロードしたリポジトリを配置する方法
  2. プラグインマネージャを利用してインストールする方法

今回はこの内、プラグインマネージャを利用した方法を説明します。
プラグインマネージャにはいくつも種類があり、物によって機能や設定ファイルの書き方など様々ですが、今回は軽量で高機能なvim-plugというプラグインマネージャを使った方法を説明します。既に他のプラグインマネージャを利用している方はお使いのプラグインマネージャを利用してインストールを行なって下さい

まずはREADMEのInstrationの章に記載されている方法で、vim-plugをインストールして下さい。
https://github.com/junegunn/vim-plug#installation

続いて、vim-plugを有効化してインストールするプラグインを記載するために、vimの設定ファイルを記載します。
設定ファイルの保存先とファイル名はVimとNeovimで異なります
Vim: ~/.vimrc
Neovim: ~/.config/nvim/init.vim

設定ファイルに以下の様に記載して下さい

call plug#begin()
" こからplug#end()までの間にプラグインのリポジトリ(URLでも可)を記載する
Plug 'vim-jp/vimdoc-ja'
set helplang=ja,en

call plug#end()

記載したら、Vimを立ち上げ直し、:PlugInstallとコマンドを入力して下さい。
コマンドを入力すると画面左側にインストールステータスが表示され、Done!と表示されたら完了です。

日本語化プラグインの使い方

使い方は通常のヘルプと同様です。
また、helpを開く時に末尾に@enを追加すると元の英語のドキュメントを読むことができます。
特にNeovimを利用する場合は内容が違う場合もあるため、原文も確認する様にしましょう。

Neovimの場合、上記の設定ファイルの記載にある以下の記載をしないとデフォルトの記載は英語のままなので設定を忘れない様にしましょう

set helplang=ja,en

Vimで複数のファイルを開く

Vimでは、起動時にファイルを指定するだけではなく、起動した後に新しくファイルを開くこともできます。

コマンド 概要
:e ファイルパス 指定したファイルを開く。:editの略。例: :e ~/.vimrc

開いたファイルはバッファと呼ばれ、一度開いたファイルを再度開く時はバッファのリストから選択して開く事ができます。

コマンド 概要
:ls バッファの一覧を表示する
:bn 次のバッファを表示する。:bnextの略
:bp 次のバッファを表示する。:bpreviousの略
:b# 直前まで開いていたバッファを表示する。
:b[N] 該当の番号のバッファを表示する。番号はファイルを開いた順に振られます。例: :b2

詳細は :help buffer-listを参照して下さい

画面の分割

Vimでは画面を分割して別々のファイルを開く機能があります。そのため、一度に複数のファイルを閲覧/編集する場合にVimを開き直したり、ターミナルのタブを行き来する必要はありません。
方法は、コマンドを利用する方法とノーマルモードのキーバインドを利用する方法の2通りあります

キー 概要
:sp 画面を上下に分割する。:splitの略
:vs 画面を左右に分割する。:vsplitの略
<C-w>s 画面を上下に分割する。ctrlを押しながらwと入力し、その後にsを入力する、の意味
<C-w>v 画面を上下に分割する。ctrlを押しながらwと入力し、その後にvを入力する、の意味

コマンドの場合、引数にファイルパスを渡し、そのファイルを開く事ができます

window間でのカーソルの移動

画面の分割ができたらどのファイルを編集するのかの選択です。
もちろんマウスでクリックしたら選択できるのですが、Vimmerたるものマウスは使わずに操作したいので、ノーマルモードで以下のキーバインドを利用します

キー 概要
<C-w>h カーソルを1つ左のwindowに移動
<C-w>j カーソルを1つ下のwindowに移動
<C-w>k カーソルを1つ上のwindowに移動
<C-w>l カーソルを1つ右のwindowに移動
<C-w>w カーソルを1つ前のwindowに移動

基本的にはCtrl + wを押した後にhjklという普段からカーソル移動で利用するキーを使うので覚え易いと思います。
また「コメントに1つ左」などと記載していますが、このキーを入力する前に数字を入力すると、その数の分移動する、という使い方もできます
2<C-w>h " カーソルを2つ左のwindowに移動

分割された画面の操作

こちらは分割した画面自体を操作するコマンドやキーバインドの紹介です

キー 概要
:q 現在のwindowを閉じる
:e 現在のwindowで別のファイルを開く(設定ファイルに「set hidden」を記載するのを推奨)
<C-w>H 現在のwindowを画面の一番左に移動する
<C-w>J 現在のwindowを画面の一番下に移動する
<C-w>K 現在のwindowを画面の一番上に移動する
<C-w>L 現在のwindowを画面の一番右に移動する
<C-w>> 現在のwindowの横幅を広げる(1回では変化が小さいので数値指定推奨)
<C-w>< 現在のwindowの横幅を狭める(1回では変化が小さいので数値指定推奨)
<C-w>+ 現在のwindowの縦幅を広げる(1回では変化が小さいので数値指定推奨)
<C-w>- 現在のwindowの縦幅を狭める(1回では変化が小さいので数値指定推奨)
<C-w>= 現在表示している全てのwindowのサイズを均等にする

ウィンドウのサイズの変更については、デフォルトの機能だけだと不便なこともあるため、以下のプラグインの導入もオススメです
https://github.com/simeji/winresizer

画面の分割やバッファなどの詳細については:help windowsに纏まっているので

タブの作成、操作

Vimでは画面の分割だけではなく、タブを利用することもできます。
コマンドやキー操作は以下です

キー 概要
:tabnew タブの新規作成(ファイルパスを指定可
<C-w>gf 現在カーソルがあるファイルを新しいタブで開く
:tabclose 現在のタブを閉じる
gt 次のタブに移動
gT 前のタブに移動

VSCodeなどと違い、タブが変わると画面の分割状況も変わります。
タブ1で4つに画面を分割していたとしても、タブ2では画面は1つだけ、という状況になります。

タブの面白い機能として、現在のタブ内だけカレントディレクトリを変更できる、という物があります。
:tcd 移動先ディレクトリというコマンドでディレクトリを移動すると、現在のタブのカレントディレクトリを変更できます。
コマンドを入力する時の相対パスの指定が便利なくらいではありますが、モノレポのプロジェクトで作業する時などに便利なことがあります。

タブの詳細やその他の使い方についてはl:help tabpageを参照して下さい

コピー&ペースト(レジスタについて)

通常コピー&ペーストを行う場合、yでヤンクしてpでペーストを行ないますが、Vimにはヤンクしたテキストの履歴が残っています。
この履歴の事をレジスタと言い、:registersというコマンドを利用すると履歴として何が保存されているか見る事ができます。
履歴は0~9まであり、ペーストする際にl" + レジスタ名 + pと入力する事で、指定の履歴を貼り付ける事ができます。
ちなみに、この番号のレジスタにはdcxなどで削除された文字列は記録されないため、ヤンクした後に文字を消してしまってpで貼り付けされた文字が思ったのと違う、という場合は"0pで最後にヤンクした文字列を指定して貼り付けすることができます。

レジスタにはヤンクの履歴である番号付きレジスタだけではなく、いくつかの種類があります。以下は良く使うレジスタです

  • 無名レジスタ
    • レジスタを指定しないでペーストを行なう際に使われるデフォルトのレジスタ。ヤンクだけではなく、文字の削除でも更新される
  • 番号付きレジスタ
    • ヤンクした時と複数行に跨がる削除を行なった場合に利用されるレジスタ。利用される度に番号がインクリメントされ、0が最新で9が最も古い履歴となる。
  • 名前付きレジスタa-z, A-Z
    • ユーザーが指定した時のみ利用されるレジスタ。小文字と大文字では別の扱いとなる。
    • "ay"apと入力して利用する
    • 番号付きレジスタと違い、勝手に消えたり番号がズレることもないので、何度も利用する内容を保存するのに便利
  • selectionレジスタ+, **
    • OSのクリップボードと連携するレジスタ。+と*は基本的に同じ動作なので通常はどちらを利用しても良い。
    • "*yでコピーを行なえば、Vim以外のアプリ、例えばブラウザなどにヤンクした内容を貼り付けることができる
    • "*pでペーストを行なえば、ブラウザなどでコピーした内容をVimに貼り付けることができる
    • 環境によってはクリップボードとの連携が上手くいかない場合があるが、その場合以下を確認すると良い
      • Vimの場合はターミナル上で vim --version | grep clipboard を実行し、+clipboardと表示される様にVimのインストール方法を調査する必要がある。
      • Neovimの場合はクリップボード連携を行うためのコマンドを指定することができる。詳細は:help clipboard-toolで確認して下さい。
    • ※「Vim クリップボード」などで検索するとset clipboard=unnamedを設定しろという記事が良く出てくるが、そうすると無名レジスタと同じ様にxdなどで文字を削除する度にクリップボードが更新されるため、WindowsのWin+vやMacのclipyアプリなどでクリップボードの履歴を遡って最適な物を貼り付けをする様な場合、無駄な履歴が増えて非常に邪魔になることが多々あるあめ、clipboardオプションの指定はせずに、必要な時だけレジスタを指定する方法がオススメです

文字の検索置換

Vimでは検索した文字列の置換は:substituteコマンドを利用します。

例: Vimという文字列をNoevimに置換する
%s/Vim/Neovim/g

このコマンドは利用する際に指定できるオプションが多く、最初は慣れが必要かもしれません。
上記の例を分解すると、以下の8つに分けることができます
% + s + / + Vim + / + Neovim + / + g

  • 最初の%は範囲指定の文字で、今のファイル全体を検索して置換する、という指定になります
    • 他に良く使う範囲指定としては、Visualモードで範囲指定した後に:でEX(コマンドライン)モードに移ると'<,'>という文字が入力されますが、そのままsubstituteコマンドを入力すると選択した行だけが対象となります。
    • 範囲指定の部分は省略することもでき、その場合はカーソルがある行のみが対象になります
    • 他の範囲指定方法などの詳細は:help [range]を確認して下さい
  • ssubstituteの省略系です。%substitute/Vim/Neovim/gと入力しても同様ですが、タイピング数が増えるのでsとする事が多いです。
  • /は区切り文字です。/で囲われた1つ目の文字列(Vim)を2つ目の文字列(Neovim)に変換しています
    • この区切り文字は/以外の文字を使う事もでき、置換したい文字の中に/が入っている時に代わりにs'dir/filename'dir2/filename'gの様に指定することができます
  • Vimの部分は検索文字列です。検索コマンドと同じく、Vimの正規表現モドキが使えます。
    • Vimで使える正規表現については、「Vim 正規表現」等で調べると解説記事などがあるので調べてみてください。
    • この部分は省略することもでき、省略した場合は前に/で検索した文字列を検索して置換する。
      • 例: %s//Neovim/g という様に記述する
  • Neovimの部分は置換するの文字列です。
    • テキスト以外にも正規表現で利用される様な文字列を利用することができる。詳細は:help sub-replace-specialを確認して下さい
  • 最後のgは検索時の挙動を指定するフラグになります。
    • gの場合は、1つの行に検索対象の文字が複数あった場合、その全てを置換する、というフラグになります。
      • このフラグを付けないと、1つの行にVimという文字列が2回以上出てきた場合、行の最初にある1つだけ置換され、残りは置換されずそのままになります
      • そのため、慣れない内はとりあえず最後にgを指定することをオススメします
    • 他に良く使うフラグとしてciがあります
      • cは検索対象の文字列を1つずつ確認して、置換するかスキップするかを選べます
      • iは大文字小文字を無視して検索します。上記の場合Vimだけでなく、vimVIMといった文字列も置換されるようになります

通常の置換以外に良く使うケースとして、行頭行末に文字を追加する、というのがあります。
検索文字列に $ を使うと行末、 ^を使うと行頭がマッチするので、

  1. Visualモードで変換したい行を選択
  2. :'<,'>s/$/; とコマンドを入力
    とすると、行末に;を追加する、といった事ができます。

substituteコマンドを利用するに当たって、以下のオプションを設定しておくと便利です

set incsearch " コマンド入力中もマッチする部分がハイライトされる"
set inccommand=split " Neovimのみ。画面下にマッチする行と置換結果のプレビューが表示される

詳細は :help :substituteを参照してください。

マクロ

VimにはExcel等と同じ様なマクロ機能があります。
基本的には上記のsubstituteコマンドで何とかなることが多いですが、使いこなせると便利になることも結構あります。

使い方はノーマルモードで以下のキーを押します

キー 概要
q + 任意の英数字(レジスタ) マクロ記録開始
q マクロ記録終了
@ + 登録時に指定したレジスタ マクロ呼び出し
@@ マクロ呼び出し(連続呼び出し)

記録している間は、ステータスライン(画面の最下部)に「recording」や「記録中」などと表示されます。

記録したマクロは以下のキーを押して実行します
@ + 記録したレジスタ
また、同じマクロを連続で利用する場合は、「@@」 と入力しても呼び出す事ができます。

マクロの記録には、ヤンクと同様にレジスタを利用するため、マクロの記録中に同じレジスタを利用すると上手く動かないため、要注意です。
例: qaで記録開始し、"ay"でaレジスタを上書きする、など

以下の例では、markdownで記載したテーブルの最初の列を最後の列に入れ変えている例です

  1. qq で記録開始
  2. 0 で行頭に移動
  3. lvf| で1列目の内容を選択
  4. d で1列目の内容を削除
  5. $で行末に移動
  6. pでペースト
  7. q で記録終了
  8. jjでテーブルのBodyの行に移動
  9. @qでマクロを再生
  10. j + @@ でそれ以降の各行に適用

詳細な使い方は:help qでヘルプを読み、「Vim マクロ」などでGoogle検索してみて下さい

マーク

Vimでは、好きなファイルの好きな行にマークを設定して、他の場所から一瞬でその行に戻る、という便利機能があります
Vimtutorで記載があった<C-o><C-i>で移動するのと同様です。

使い方は以下です。

キー 概要
m + 半角英字(マーク) 現在の行にマークを設定する
' + マーク マークを設定した行に移動する
' + . 最後に編集した行に移動する
:marks 現在設定しているマークの一覧を確認する

マークを設定する際は

  • 小文字 → 現在のファイルのみで有効
  • 大文字 → ファイルを跨いで同一
    という違いがあるため、基本的には大文字でマークを設定しておくのがオススメです

マークについては正直な所自分も使いこなせていないのですが、現在編集しているメソッドにとりあえず大文字でマークを付けておき、実装に必要な別のメソッドの定義を確認した後にマークを使って戻る、などの使い方をすると便利なのではないか、と思います。

詳細は :help mark-motions を参照して下さい

quickfix

Vimでは、grepなどの検索結果を便利に表示して、該当の行に簡単に移動できるquickfixという機能があります。
この機能は元々、C言語のコードをコンパイルした時に出たコンパイルエラーのメッセージとファイルの位置を表示し、すぐ(quick)に修正(fix)するための機能ですが、今では検索結果やLanguageServerのtextDocument/referencesの結果(指定の変数やメソッドがどこで使われているか)をquickfixで表示する、という使い方が多いと思います。

使い方は以下です。

キー 概要
:vim 検索する文字 検索するパス :vimgrepコマンドの略。grepしてその結果をquickfixに保存する(:help :vimgrep)
:copen quickfixのウィンドウを開く
<CR> quickfixウィンドウ内でエンターキーを押すと、該当の行に移動します

以下の例ではカレントディレクトリ以下のファイルからNeovimという文字列を検索し、quickfixで確認をしています

また、quickfixは履歴が保存されているので、別の検索をした後に前の検索結果を再度確認することもできます

コマンド 概要
:chistory quickfixの履歴を確認する(:help :chistory)
:colder [count] count分古いエラーリストに移動する。省略した場合1つ古いエラーリストに移動
:cnewer [count] count分新しいエラーリストに移動する。省略した場合1つ新しいエラーリストに移動
:[count]chistory countの番号のエラーリストに移動する。例: :2chistoryで2番のエラーリストに移動

terminal

Vimの中でターミナルが開けます。
:terminal
ターミナル画面にもInsertモードとNormalモードがあり、ターミナルの出力をヤンクしてペーストするなどの操作が便利になります。
ターミナルコマンドはVimとNeovimで挙動の違いがあり、

  • Vimの場合

    • コマンドを実行すると上下に画面分割され(:splitと同じ)、デフォルトでInsertモードになります
  • Neovimの場合

    • コマンドを実行すると、現在のwindowでターミナルの画面が開き、デフォルトでNormalモードになります

ターミナルの操作は以下です

モード キー 概要
EX(コマンドライン) :ter :terminal の略。新しくターミナルを開く
terminalのNormalモード i Insertモードに入る。現在のカーソルの位置に関わらず、シェルの入力位置に移動する
terminalのInsertモード <C-\><C-n> Normalモードに戻る。カーソルの位置はInsertモードに入る前の位置に移動する
terminalのNormalモード p ペーストする。現在のカーソルの位置に関わらず、シェルの入力位置に文字がペーストされる

デフォルトではノーマルモードへの遷移に ctrl + \ + ctrl + n という不便なキー入力が必要になるので、以下の様に設定して好きなキーに変更しておくことをオススメします

" `ctrl + w` + `ctrl + w`でNormalモードに戻る様に設定
tnoremap <C-w><C-w> <C-\><C-n>

詳細は:help terminalを参照して下さい。

その他の良く使うマッピングなど

この章では個人的に良く使う便利なキーを紹介します

モード キー ヘルプの検索キーワード 説明
Normal . single-repeat 最後の変更を繰り返す。同じ文字の挿入や、同じ長さの文字の削除などが現在のカーソルを起点に行なわれる
Normal * * カーソル下の単語を検索する。単語単位での検索なのでComponnentという単語を検索した時にBaseComponentという単語にはマッチしない
Normal ~ ~ カーソル下のアルファベットの大文字小文字を反転させる(例: a → A, A → a)
Visual ~ v_~ 選択したのアルファベットの大文字小文字を反転させる(例: aBc → AbC)
Visual U v_U 選択したアルファベットを大文字にする(例: aBc → ABC)
Visual u v_u 選択したアルファベットを小文字にする(例: aBc → abc)
Insert <C-r>" i_CTRL-R 無名レジスタの内容を入力する。ノーマルモードでのpと同等("の変わりに別のレジスタも指定可能
EX(コマンドライン) <C-r>" c_CTRL-R 無名レジスタの内容を入力する。ノーマルモードでのpと同等("の変わりに別のレジスタも指定可能
EX(コマンドライン) <C-r><C-w> c_CTRL-R_CTRL-W EXモードに入る直前のカーソル下の単語を入力する
Normal V V 行単位のビジュアルモードを開始する。選択範囲が行全体になるので、選択範囲を削除する時に行の途中までしか削除できなかった、といったミスが無くなる
Normal <C-V> CTRL-V 矩形ビジュアルモードを開始する。上下の同じ列に文字を挿入したい場合などに便利

終わりに

ということでVimのデフォルト機能の紹介でした。
プラグインを入れてどんどんリッチにするのも楽しいですし、自分も最初そうでしたが、そもそもVim自体が結構便利なことを知らず、window分割すら知らずに数ヶ月使っていてもったいなかったな、と思った記憶があるので、今回その頃の自分に教えたいVimのデフォルト機能に焦点を絞って記載してみました。
これらの機能を更に便利にしたプラグインなども沢山あるので、そのままでは使いずらい、などあればプラグインを探して自分のVimをカスタマイズして行ってみてください。
この記事がVimの初心者にとって学びがあるものになっていると幸いです。

明日はYoshii Mochiharaさんによる記事です。お楽しみに!

Sun* Developers

Discussion