【Vim】生産性向上Tip's

この記事は[Vim2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/vim2) 15日目の記事です。

# はじめに

当記事はVimの生産性向上を目的とした記事ですが、

- 「キーバインドが多くて何から覚えればいいかわからない..」
- 「キーバインドをもっと活用したい！」
- 「これからVScodeでもVimを使いたい！」

と思っている方に楽しんで頂けるような構成にしております。
※この手のVimのキーバインドを紹介する記事は何番煎じかわかりませんが、個人的なメモとして書き残していきたいと思います。少しでも他の人に参考になれば幸いです。


## VScodeにVimを導入

まずは、VScodeに[Vimのプラグイン](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim)をインストールして導入しましょう。

プラグインをインストールしたら次は以下3点のセットアップです。
一旦は丸パクリでOKです。だんだん使い慣れてきたら自分風にカスタマイズしていけばいいですし、「この設定は自分には合わないな」と分かってくるものです。

### .vimrc

**.vimrc**とは、Vimの設定やキーマッピングを記述したりする隠しファイルです。Vimを自分好みにカスタマイズすることができます。
以下を、コピーし**HOMEディレクトリ**にファイルを置いてください。

```
" -------------------------
" 基本設定
" -------------------------
" バックアップファイルを作らない
set nobackup
" スワップファイルを作らない
set noswapfile
" 編集中のファイルが変更されたら自動で読み直す
set autoread
" バッファが編集中でもその他のファイルを開けるように
set hidden
" 入力中のコマンドをステータスに表示する
set showcmd

" -------------------------
" 表示設定
" -------------------------
" コメントの色を水色
hi Comment ctermfg=3
" windowのタイトルを変更
set title
" 行番号
set number
" 相対行番号
set relativenumber
" 現在の行を強調表示
set cursorline
" 行末のスペースを可視化
set listchars=tab:^\ ,trail:~
" コマンドラインの補完
set wildmode=list:longest
" コマンドラインの履歴を100件保存
set history=100
" 不可視文字を可視化(タブが「▸-」と表示される)
set list listchars=tab:\▸\-
" Tab文字を半角スペースにする
set expandtab
" インデントはスマートインデント
set smartindent
" インデント幅
set shiftwidth=2
" タブキー押下時に挿入される文字幅
set softtabstop=2
" 対応する括弧を強調表示
set showmatch
" シンタックスハイライト
syntax on

" インサートモード時は縦棒カーソル
if has('vim_starting')
  " 挿入モード時に非点滅の縦棒タイプのカーソル
  let &t_SI .= "\e[6 q"
  " ノーマルモード時に非点滅のブロックタイプのカーソル
  let &t_EI .= "\e[2 q"
  " 置換モード時に非点滅の下線タイプのカーソル
  let &t_SR .= "\e[4 q"
endif

" -------------------------
" 検索
" -------------------------
" 検索するときに大文字小文字を区別しない
set ignorecase
" 小文字で検索すると大文字と小文字を無視して検索
set smartcase
" 検索がファイル末尾まで進んだら、ファイル先頭から再び検索
set wrapscan
" インクリメンタル検索 (検索ワードの最初の文字を入力した時点で検索が開始)
set incsearch
" 検索結果をハイライト表示
set hlsearch

" -------------------------
" key-mapping
" -------------------------
" ESC連打でハイライト解除
nmap <Esc><Esc> :nohlsearch<CR><Esc>
" カーソル下の単語を<space*2>ハイライトする
nnoremap <silent> <Space><Space> "zyiw:let @/ = '\<' . @z . '\>'<CR>:set hlsearch<CR>

" change normal mode
inoremap <silent> jj <Esc>

" ctrl + dで削除
inoremap <C-d> <Del>
noremap <C-d> <Del>
" 行頭、行末に移動して挿入モードに切り替え
inoremap <C-e> <Esc>$a
inoremap <C-a> <Esc>^i
noremap <C-e> <Esc>$a
noremap <C-a> <Esc>^i
" シンプルな行頭・行末・文字検索
noremap <Space>h  ^
noremap <Space>l  $
nnoremap <Space>/  *
" 画面半分先へ。画面半分戻るは[C-u]
noremap <C-m> <C-d>
" カーソル固定で下にスクロール。上にスクロールは[C-y]
noremap <C-i> <C-e>

" カーソル行の一つ上の行に空行を挿入
nnoremap <C-k> O<Esc>
" カーソル行の一つ下の行に空行を挿入
nnoremap <C-j> o<Esc>

" カーソル位置の単語をyankする
nnoremap vv vawy
" カーソル位置の単語をカットする
nnoremap cc vawc

" 対応する括弧に移動
nnoremap [ %
nnoremap ] %
```

### settings.json

```settings.json
{
  //----------------------------------------------------------
  // vscode vimの設定
  //----------------------------------------------------------
  "vim.vimrc.enable": true, // vimrcを適用
  "vim.vimrc.path": "/Users/ユーザー名/.vimrc", // .vimrcのパス
  "vim.hlsearch": true,
  "vim.easymotion": true,
  "vim.useCtrlKeys": true,
  "vim.ignorecase": true,
  "vim.incsearch": true,
  "editor.lineNumbers": "relative"
}

```

以下の**/Users/ユーザー名/.vimrc**のユーザー名の部分は各々で違ってくるので注意です。
簡単な調べ方は、ターミナルを起動して何もコマンドを打たずに`pwd`または、`users`と打ってみてください。するとユーザー名が分かります。

```settings.json
  "vim.vimrc.path": "/Users/ユーザー名/.vimrc", // .vimrcのパス
```

### keybindings.json

**keybindings.json**は直接Vimのセットアップには関係ありませんが、
以下の設定を記述しておくと何かと便利です。

- **ctrl + x**でエディタ画面とターミナルを移動
- **ctrl + jk**でターミナルを垂直に分割（Vimではjkで上下移動するため何となくjkの方が覚えやすいく、また競合するショートカットがない）
- **ctrl + kk**で次のペインに移動

```keybindings.json
[
  //----------------------------------------------------------
  // change settings line number (F3で行番号の表示を変更)
  //----------------------------------------------------------
  {
    "key": "f3",
    "command": "settings.cycle",
    "when": "editorTextFocus",
    "args": {
        "id": "relativeLineNumbers",
        "values": [
            {
                "editor.lineNumbers": "on"
            },
            {
                "editor.lineNumbers": "relative"
            }
        ]
    }
},

  //----------------------------------------------------------
  // ターミナル
  //----------------------------------------------------------
  {
    "key": "ctrl+x",
    "command": "workbench.action.terminal.focus",
    "when": "editorTextFocus"
  },
  {
    "key": "ctrl+x",
    "command": "workbench.action.focusFirstEditorGroup",
    "when": "terminalFocus"
  },
  {
    "key": "ctrl+j ctrl+k",
    "command": "workbench.action.terminal.split",
    "when": "terminalFocus && terminalProcessSupported"
  },
  {
    "key": "ctrl+k ctrl+k",
    "command": "workbench.action.terminal.focusNextPane",
    "when": "terminalFocus && terminalProcessSupported"
  },
]
```

これでようやく、Vim導入のセットアップが完了しました..！

## Vimキーバインド一覧

Vimのキーバインドはとにかく沢山存在します。
ここで紹介するものはほんの一部なので、気になったら実現したいキーバインドに応じて調べてみることをお勧めします。
はじめは、あまりのキーバインドの数の多さに圧倒されてしまい脳が拒絶してしまうのですが、最初はそうなって当たり前なので**徐々にできることを増やしていく**ようなスタンスでまったり楽しんでやっていきましょう。

※上述した**.vimrc**ではキーマッピングを多少弄っていますので、以下で記載するキーバインドで動かないものが存在します。**以下で記載するキーバインドはデフォルトのキーバインド**なので、何も弄られていないVimであれば動きます。
上述した**.vimrc**をコピーされた方は適宜.vimrcの**key-mapping**を参照してください。ファイルのコメントを参照して頂けますと理解できるかと思います。


### Normal mode

ここでは、以下3点に絞って紹介したいと思います。

- 移動
- 検索
- 保存

---

**移動**

| コマンド | 説明 |
|:-:|:-:|
| [ h ]・[ j ]・[ k ]・[ l ] | [ 左 ]・[ 下 ]・[ 上 ]・[ 右 ]に移動 |
| [ w ]・[ e ]・[ b ] | [ 次の単語の頭 ]・[ 次の単語の末尾 ]・[ 前の単語の頭 ] |
| [ f<記号> ]・[ t<記号> ] | [ 記号 ]・[ 記号の一つ手前 ]に移動 |
| [ 0 ]・[ ^ ]・[ $ ] | [ 行頭 ]・[ 空白を除く行頭 ]・[ 行末 ]にジャンプ |
| [ gg ]・[ G ] | [ ファイルの先頭 ]・[ ファイルの末尾 ]に移動 |
| [ ctrl + d ]・[ ctrl + u ] | [ 画面半分先へ ]・[ 画面半分戻る ] |
| [ ctrl + y ]・[ ctrl + e ] | [ カーソル固定で上 ]・[ カーソル固定で下 ]にスクロール |
| [ H ]・[ M ]・[ L ] | 画面の[ 一番上 ]・[ 中心 ]・[ 一番下 ]に移動 |
| [ zt ]・[ zz ]・[ zb ] | カーソル行を[ 画面上部 ]・[ 画面中央 ]・[ 画面下部 ]に移動 |
| [ :n ]・[ nG ]・[ ngg ] | 指定した行にジャンプ |
| gd | 定義元にジャンプ |
| [ ctrl ] + [ o ] | ジャンプ元に帰る |
| % | カーソル位置にある括弧に対応している括弧にジャンプ |

**検索**

| コマンド | 説明 |
|:-:|:-:|
| /任意記号 | /の後の任意記号を検索 |
| * | カーソル位置の文字を検索 |
| [ n ]・[ N ] | [ 次の検索候補に飛ぶ ]・[ 前の検索候補に飛ぶ ] |

**保存**

| コマンド | 説明 |
|:-:|:-:|
| [ :w ]・[ :q ]・[ :wq ] | [ 保存 ]・[ 閉じる ]・[ 保存して閉じる ] |
| [ :w! ]・[ :q! ]・[ :wq! ] | 上記の動作を強制実行 |
| :x | ファイルに変更があったときのみ、保存して閉じる |

### Insert mode

以下は、Insert modeに入るためのキーバインドです。
Insert modeでは、入力ができます。
Normal modeに戻るときは、`ESC`・`ctrl + C`で戻れます。
私の場合は、`jj`とタイプして戻りますが。（上述した.vimrcをコピーしている方であればjjで切り替えできるようになっています）

| コマンド | 説明 |
|:-:|:-:|
| i | カーソルの左から入力 |
| a | カーソルの右から入力 |
| I | 行頭から入力 |
| A | 行末から入力 |
| o | カーソルのある行の一つ下の行に空行を差し込んで入力開始 |
| O | カーソルのある行の一つ上の行に空行を差し込んで入力開始 |
| s | カーソル位置の記号を削除してinsertモードに入る |
| S | カーソル行を削除してinsertモードに入る |

### Visual mode

Visual modeでは**範囲選択**ができます。

| コマンド | 説明 |
|:-:|:-:|
| v | 範囲選択開始。移動と合わせることで範囲を拡大 |
| V | 行選択 |
| ggVG | ファイル全体を選択 |
| viw | 単語選択 |
| [ vi ] + [ 記号 ] | 記号の中身を選択 |
| [ vt ] + [ 任意の記号 ] | カーソル位置から任意の記号手前まで選択 |
| [ ctrl ] + [ v ] | 矩形選択 |

### 編集

| コマンド | 説明 |
|:-:|:-:|
| u | command + Zと同義 |
| U | 行全体の変更を戻す |
| [ ctrl + r ] | command + shift + Zと同義 |
| [ dd ]・[ Vd ] | 一行削除 |
| ddp | 行入れ替え |
| （範囲選択されている状態で） + y | その範囲をyank |
| [ y ]・[ yy ] | カーソル行をyank |
| yw | 単語をyank |
| （insert mode） + [ ctrl ] + [ y ] | 上の行を一押下ずつyank |
| p | カーソルの右側にpaste |
| P | カーソルの左側にpaste |
| [ r ] + [ 任意の1単語 ] | 一単語の置換 |
| R | 一意単語以上の置換 |
| ~ | カーソル位置の大文字と小文字を入れ替える |
| （選択されている状態で） + U | 選択した範囲の大文字と小文字を入れ替える |
| [ >> ]・[ ctrl ] + [ t ] | 右にインデント |
| [ << ]・[ ctrl ] + [ d ] | 左にインデント |

※vimではコピーのことをyankと呼びます。

## 必修Vimキーバインド

最後に、「これだけは覚えて帰って欲しい」Vimキーバインドを紹介します。
個人的にこれらのキーバインドを使用しなければ、**生きていけない**と思ってますw

| コマンド | 説明 |
|:-:|:-:|
| [ (c・d・v・y) + i ] + [ 記号 ] | 記号の中身を（c・d・v・y）する（記号は含まない） |
| [ (c・d・v・y) + a ] + [ 記号 ] | 記号の中身を（c・d・v・y）する（記号を含む） |
| [ (c・d・v・y) + f ] + [ 記号 ] | カーソル位置から記号までを（c・d・v・y） |
| [ (c・d・v・y) + t ] + [ 記号 ] | カーソル位置から記号手前までを（c・d・v・y） |
| [ c・d・v・y ] + it | HTMLタグの中身を（c・d・v・y） |
| [ (c・d・v・y) + at ] | HTMLタグを含めて（c・d・v・y） |
| [ (c・d・v・y) + iw ] | カーソル上の単語を（c・d・v・y） |

**surround.vim**

Vimを使う上では**避けては通れない**キーバインドです。
**surround**とは、「**囲い**」という意味で、その名の通り囲いに特化したキーバインドです。
また、VScodeのVimにはデフォルトでsurround.vimが入っているため、何も弄らなくてOKです。

| コマンド | 説明 |
|:-:|:-:|
| [ cs ] + [ 囲い ] + [ 囲い ] | 囲いを一瞬で変更 |
| [ cs ] + [ 囲い ] + [ 左囲い ] | 左囲いで指定した場合、内側に半角スペースが入る |
| [ cst ] + [ タグ記号 ] | 現在囲ってるタグ記号を変更 |
| [ ds ] + [ 囲い ] | 囲いを削除 |
| dst | 現在囲ってるタグ記号を削除 |
| [ ysiw ] + [ 囲い ] | カーソル上の文字列を指定した囲いで囲む |
| [ Visual ] + [ S ] + [ 囲い ] | Visualで選択している部分を指定した囲いで囲む |

## 参考記事

[さっさと帰りたい怠け者エンジニアは vim をマスターしましょう](http://wolfbash.hateblo.jp/entry/2017/08/25/121711)
[Vim幼稚園からVim小学校へ](https://qiita.com/hachi8833/items/7beeee825c11f7437f54)
[知識0から始めるVim講座](https://qiita.com/JpnLavender/items/fabcc79b4ab0d52e1f6d)

# 最後に

ここまで読んで頂きありがとうございます。
この記事を通して、少しでもVimに興味を持っていただければ嬉しいです！