🏋️‍♂️

Vimで本格的にWeb開発したい人の為のステップアップガイド

2022/10/30に公開

想定読者

この記事は「Vimって便利だけど、覚えたてだと局所的にしか使えなかったりして、実際に本格的にWeb開発するのは難しいし、モチベーションも続かないなあ…」という人のために書きました。

工夫した点

  • TODOサンプルアプリを用意して「Vimの設定適用 → リアルなコードを使って実際にVimを動かす」という感じで少しずつ便利になる体験をしながら実際のWeb開発でも使えるVimを使った操作や設定などを覚えていけるステップアップ構成
  • 特定のプラグインを使うケースは類似プラグインを紹介し、他のプラグインも選択できるように。(これこそVimの楽しいところ。好きなものを好きなように自分で組み合わせて使う。)

注意点

  • Vimの説明になります(Neovimではありませんのでご注意ください)。
  • Vimはバージョン8.2を使っています。
  • Docker上のUbuntuでVimを動かす想定になっています。インストール方法などはプラグインやツールの公式READMEを参照いただきご自身のOSに適宜読みかえてください。

その他

  • Vimのクリップボード対応はこの記事中では説明していません。Vimのクリップボード対応は必須で対応しておきたいところですが、OSや環境によって設定方法が変わってくるため「Vim クリップボード対応」などで調べて適宜設定をおねがいします。

筆者について

  • 大体Vim歴は約2年くらい、ぎゅっと縮めたら数か月くらい
  • 試して動いた!やった!という感じで、今も雰囲気でVimを使っている部分はたくさんあります;;
  • 筆者のVimrcです。

今回使用するもの

TODOサンプルアプリ

用意したリポジトリ
https://github.com/snyt45/sample-rails-graphql-typescript-react-apollo

実際のソースコードがあったほうがリアルな使い方が伝わるかなと思いそのためだけに用意しました。実際に動かすことができますが、記事中ではセットアップの必要はありません。ソースコードだけgit cloneだけしていただければOKです。

Vim検証用のDockerfile

私がこの記事を書きながら検証に使ったDockerfileです。
この環境を立ち上げて、記事に記載しているコマンドや設定をしていけば動くと思います。
実際に触ってみたい方などは使ってみてください。

FROM ubuntu:22.04

ENV LANG ja_JP.UTF-8
ARG USERNAME=user
ARG GROUPNAME=user
ARG PASSWORD=password
ARG UID=1000
ARG GID=1000

# apt高速化
RUN sed -i '[email protected]@ftp.jaist.ac.jp/pub/Linux@g' /etc/apt/sources.list
RUN apt update && apt upgrade -y && apt install -y curl sudo git locales vim && \
    locale-gen ja_JP.UTF-8

RUN groupadd -g $GID $GROUPNAME && \
    useradd -m -s /bin/bash -u $UID -g $GID $USERNAME && \
    echo "$USERNAME:$PASSWORD" | chpasswd && \
    echo "$USERNAME ALL=(ALL) ALL" >> /etc/sudoers
USER $USERNAME
WORKDIR /home/$USERNAME/

使い方

# Vim検証用のイメージ作成
docker image build -t vim-test .
# Vim検証用のイメージからコンテナ作成
docker container run -it vim-test
# 作業終わるときはexitでコンテナから抜けます。
# コンテナを削除すると、自分で追加した設定等が消えてしまうので基本削除しないようにします。不要になった時や一からやり直したいときはコンテナを削除しても大丈夫です。

最終的なvimrc

最終的なvimrcです。
依存ツールなどがあるため、このままでは動かないと思いますが、全体像を把握するために貼っておきます。

  • 必要なツール
    • fzf、bat、ripgrep
  • LSPで必要なツール
    • Node.js、Yarn、Ruby
set number            " 画面左端に行番号を表示
set signcolumn=yes    " 画面左端にサイン列を常に表示
set laststatus=2      " 画面最下部に常にステータスラインを表示
set cmdheight=2       " 画面最下部(ステータス行より下)のメッセージ表示欄を2行にする
set showtabline=2     " タブ毎に常にタブラインを表示

set virtualedit=block " 矩形選択時に仮想編集を有効化
set wildmenu          " コマンドラインでTAB補完時に候補メニューを表示
set wildignorecase    " コマンドラインでTAB補完時に大文字・小文字を区別しない

set tabstop=2         " タブを2文字分にする
set expandtab         " タブの代わりに半角スペースを使用
set shiftwidth=2      " インデントを半角スペース2文字にする
set smartindent       " 新しい行追加時に自動でインデントを追加

set hlsearch          " 文字列検索のハイライト
set ignorecase        " 文字列検索で大文字・小文字を区別しない
set smartcase         " 文字列検索で大文字を含んでいたらignorecaseを上書きし、大文字・小文字を区別する
set incsearch         " インクリメンタルサーチ

set noswapfile        " スワップファイル(.swp)を生成しない
set nobackup          " バックアップファイル(~)を生成しない
set noundofile        " undoファイル(.un~)を生成しない
set encoding=utf-8    " Vim内部で使われる文字エンコーディングにutf-8にする

set mouse=a           " マウス操作を有効にする

augroup signcolumn_bg_none
  autocmd!
  " colorscheme読み込み後、サイン列の背景色をNONEにする ※Windows Terminal側の色を使いたいため
  autocmd VimEnter,ColorScheme * highlight SignColumn guibg=NONE ctermbg=NONE
augroup END

nmap <silent> <Esc><Esc> :<C-u>nohlsearch<CR><Esc> " 文字列検索のハイライトオフ

call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
  Plug 'airblade/vim-gitgutter'
  Plug 'tpope/vim-fugitive'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'junegunn/fzf.vim'
  Plug 'tpope/vim-rails'
  Plug 'prabirshrestha/vim-lsp'
  Plug 'mattn/vim-lsp-settings'
  Plug 'prabirshrestha/asyncomplete.vim'
  Plug 'prabirshrestha/asyncomplete-lsp.vim'
  Plug 'liuchengxu/vim-which-key'
call plug#end()

if !has('gui_running')
  set t_Co=256
endif

let g:fern#default_hidden=1 " 隠しファイルを表示する
let g:fern#renderer = 'nerdfont'
let g:fern#renderer#nerdfont#indent_markers = 1

set updatetime=100 " 更新時間を100msに設定

let g:gitgutter_sign_added = '+'
let g:gitgutter_sign_modified = '>'
let g:gitgutter_sign_removed = '-'
let g:gitgutter_sign_removed_first_line = '^'
let g:gitgutter_sign_modified_removed = '<'

augroup vimrc_vim_gitgutter
  autocmd!
  " colorscheme読み込み後、サイン列の記号の背景色を設定
  autocmd VimEnter,ColorScheme * highlight GitGutterAdd guibg=NONE ctermbg=NONE guifg=#000900 ctermfg=2
  autocmd VimEnter,ColorScheme * highlight GitGutterChange guibg=NONE ctermbg=NONE guifg=#bbbb00 ctermfg=3
  autocmd VimEnter,ColorScheme * highlight GitGutterDelete guibg=NONE ctermbg=NONE guifg=#ff2222 ctermfg=1
augroup END

let g:lsp_diagnostics_enabled = 1                        " Diagnosticsを有効にする
let g:lsp_diagnostics_echo_cursor = 1                    " カーソル下のエラー、警告、情報、ヒントを画面下部のコマンド ラインに表示
let g:lsp_diagnostics_echo_delay = 50                    " Diagnosticsの表示の遅延を50msに設定
let g:lsp_diagnostics_float_cursor = 1                   " カーソル下のエラー、警告、情報、ヒントをフロート表示
let g:lsp_diagnostics_signs_enabled = 1                  " 画面左端のサイン列にエラー、警告、情報、ヒントのアイコンを 表示
let g:lsp_diagnostics_signs_delay = 50                   " Diagnosticsのサイン列の表示の遅延を50msに設定
let g:lsp_diagnostics_signs_insert_mode_enabled = 0      " 挿入モード時、Diagnosticsのサイン列を表示しない
let g:lsp_diagnostics_highlights_delay = 50              " Diagnosticsの指摘箇所自体の文字ハイライト表示の遅延を50msに設定
let g:lsp_diagnostics_highlights_insert_mode_enabled = 0 " 挿入モード時、Diagnosticsの指摘箇所自体の文字ハイライトを表示しない
let g:lsp_document_code_action_signs_enabled = 0         " 画面左端のサイン列にコードアクションのアイコン非表示

let g:asyncomplete_popup_delay = 100 " 補完メニューを開く際の遅延を100msに設定

imap <expr> <Tab>   pumvisible() ? "\<C-n>" : "\<Tab>"
imap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
imap <expr> <cr>    pumvisible() ? asyncomplete#close_popup() : "\<cr>"

let g:lsp_settings_filetype_ruby = ['solargraph']

set timeoutlen=500 " 100msだと他のキーマッピングが上手く動かないため500msに設定

let g:which_key_ignore_outside_mappings = 1 " 辞書にないマッピングは非表示にする
let g:which_key_sep = '→'
let g:which_key_use_floating_win = 0

let g:which_key_map_tabs = { 'name' : '+tabs' }
call which_key#register('t', 'g:which_key_map_tabs')
nmap t :<c-u>WhichKey 't'<CR>
vmap t :<c-u>WhichKeyVisual 't'<CR>

let g:which_key_map_tabs.e = [':tabedit'   , 'new']
let g:which_key_map_tabs.t = [':tab split' , 'split']
let g:which_key_map_tabs.h = [':tabprev'   , 'focus left']
let g:which_key_map_tabs.l = [':tabnext'   , 'focus right']
let g:which_key_map_tabs.H = [':tabmove -1', 'move left']
let g:which_key_map_tabs.L = [':tabmove +1', 'move right']

Vimで本格的にWeb開発したい人の為のステップアップガイド

【ステップ0】素のVimに慣れる、思い出す

この記事を読まれる方はVimをちょっとかじったけど辞めてしまったみたいな人も想定しています。順を追って少しずつレベルアップしていきましょう。まずは、チュートリアルをやりましょう。

このステップでやること

  • COMMAND LABで、ブラウザからVim操作を練習する
  • Vimに付属しているチュートリアル「vimtutor」で練習する
    • vimtutor jaで日本語化されたチュートリアルを開始しましょう。

このステップで覚えておきたい操作

ここで紹介するものはVimの機能の中でもほんの一部ですが、最低限覚えておきたい開発を便利にするキー操作です。

Vimの起動と終了と保存
操作/コマンド 説明
vi Vimを起動
:q ファイルを閉じる
:q! ファイルを保存せずに強制的に閉じる
:w ファイルを保存
カーソル移動
操作/コマンド 説明
h 左方向に1文字移動
j 下方向に1文字移動
k 上方向に1文字移動
l 右方向に1文字移動
ノーマルモード/ビジュアルモード/挿入モード

「ノーマルモード」が基本のモードです。
「モード切替で困ったら、とりあえずESC」と覚えましょう。

「ノーマルモード」から「挿入モード」で編集して、「ノーマルモード」に戻る。
「ノーマルモード」から「ビジュアルモード」で操作して、「ノーマルモード」に戻る。

操作/コマンド 説明
ESC ノーマルモードに切り替え
v ビジュアルモードに切り替え
i 挿入モードに切り替え
a 挿入モードに切り替え(カーソル後ろ)
o 下に行を挿入して挿入モードに切り替え
O 上に行を挿入して挿入モードに切り替え
I 行の最初に移動して挿入モードに切り替え
A 行の最後に移動して挿入モードに切り替え
テキストのコピー/ペースト/削除/選択
操作/コマンド 説明
y ヤンク(コピー)
yy 1行ヤンク(コピー)
p ペースト
x 1文字削除
dd 1行削除
v 1文字選択
V 1行選択
画面内移動
操作/コマンド 説明
gg ファイルの先頭に移動
G ファイルの最後に移動する
C-u 画面の高さの半分だけ上に移動
C-d 画面の高さの半分だけ下に移動
C-b 画面の高さの分を上に移動
C-f 画面の高さの分を下に移動
単語移動/行移動
操作/コマンド 説明
w 次の単語の先頭へ
b 前の単語の先頭へ
^ 行頭に移動(最初の文字)
0 行頭に移動(一番先頭)
$ 行末に移動
文字列検索
操作/コマンド 説明
/検索文字列 文字列検索を開始
n で 前方検索を繰り返す
N で 後方検索を繰り返す

【ステップ1】Vimの基本設定をしよう

Vimではさまざまな設定をvimrcという設定ファイルに書き込みます。
素のVimではほとんど設定されておらず使いづらいので設定を追加しましょう。

このステップでやること

  • vimrcに基本設定を追加する
  • 文字列検索のハイライトオフにキーを割り当てる

vimrcに基本設定を追加する

ここでは、私が実際に設定で使っているものでこれがあると便利だなというものを追加していきます。

~/.vimrc
+set number            " 画面左端に行番号を表示
+set signcolumn=yes    " 画面左端にサイン列を常に表示
+set laststatus=2      " 画面最下部に常にステータスラインを表示
+set cmdheight=2       " 画面最下部(ステータス行より下)のメッセージ表示欄を2行にする
+set showtabline=2     " タブ毎に常にタブラインを表示

+set virtualedit=block " 矩形選択時に仮想編集を有効化
+set wildmenu          " コマンドラインでTAB補完時に候補メニューを表示
+set wildignorecase    " コマンドラインでTAB補完時に大文字・小文字を区別しない

+set tabstop=2         " タブを2文字分にする
+set expandtab         " タブの代わりに半角スペースを使用
+set shiftwidth=2      " インデントを半角スペース2文字にする
+set smartindent       " 新しい行追加時に自動でインデントを追加

+set hlsearch          " 文字列検索のハイライト
+set ignorecase        " 文字列検索で大文字・小文字を区別しない
+set smartcase         " 文字列検索で大文字を含んでいたらignorecaseを上書きし、大文字・小文字を区別する
+set incsearch         " インクリメンタルサーチ

+set noswapfile        " スワップファイル(.swp)を生成しない
+set nobackup          " バックアップファイル(~)を生成しない
+set noundofile        " undoファイル(.un~)を生成しない
+set encoding=utf-8    " Vim内部で使われる文字エンコーディングにutf-8にする

+set mouse=a           " マウス操作を有効にする
~/.vimrc
augroup signcolumn_bg_none
  autocmd!
  " colorscheme読み込み後、サイン列の背景色をNONEにする ※Windows Terminal側の色を使いたいため
  autocmd VimEnter,ColorScheme * highlight SignColumn guibg=NONE ctermbg=NONE
augroup END

文字列検索のハイライトオフにキーを割り当てる

先ほど、set hlsearchを有効にしたので、検索でマッチした文字列がハイライトされるようになります。ですが何もしないとハイライトされたままになります…そのため、ESCを2回連打したらハイライトを消せるように設定を行います。

~/.vimrc
nmap <silent> <Esc><Esc> :<C-u>nohlsearch<CR><Esc> " 文字列検索のハイライトオフ

これでESCを2回連打したら、文字列検索のハイライトを消せるようになりました。

【ステップ2】Vimの道もhelpから

Vimのhelpをちゃんと読むようになってVim力がじわじわとついたので、最初のうちにVimのhelpの日本語化をやっておきましょう。
また、日本語化するためにはVimのプラグインが必要になるので、ここでプラグインマネージャーも使えるようにします。

このステップでやること

  • プラグインマネージャーの導入
  • Vimのhelpの日本語化

プラグインマネージャーの導入

Vim本体にパッケージ管理機能がありますが、今回はそちらは使用せずにサードパーティー製ですが導入が簡単でシンプルで使いやすいvim-plugを使用します。

公式ドキュメントをもとにインストールしていきます

# ~/.vim/autoload/plug.vim  をインストールする
$ curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

vimrcを新たに作成して、vim-plugセクションをvimrcに追加します。

~/.vimrc
+call plug#begin('~/.vim/plugged')
+call plug#end()

Vimのhelpの日本語化

プラグインマネージャーが導入できたので、次はhelpを日本語化してくれるプラグインを導入します。

下記をvimrcに追加しましょう。

~/.vimrc
call plug#begin('~/.vim/plugged')
+  Plug 'vim-jp/vimdoc-ja'
call plug#end()

次に、Vimを開きなおして:PlugInstallコマンドを実行するとプラグインが~/.vim/pluggedにインストールされます。

:h 検索文字列でhelpが日本語化されていれば成功です!

【ステップ3】ステータスライン/タブラインの表示をリッチにしよう

Vimでは何も設定しないと、ステータスライン/タブラインの表示がとても分かりにくいです…
今回は導入がとても簡単でいい感じにリッチな表示にしてくれる「lightline.vim」を使います。

このステップでやること

lightline.vimの導入・設定

lightline.vimを導入する前に現在の表示を確認しておきます。
やはりデフォルトの状態だとステータスライン/タブラインの情報も少なく、色分けもされていないのでわかりにくいです…

さっそく公式ドキュメントをもとにインストールしていきます。

下記をvimrcに追加しましょう。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
+  Plug 'itchyny/lightline.vim'
call plug#end()

次に、Vimを開きなおして:PlugInstallコマンドを実行してプラグインをインストールします。

ステータスラインに表示される情報が増えました!

ですが、色付けされていないので、次の設定を追加します。

~/.vimrc
+if !has('gui_running')
+  set t_Co=256
+endif

ステータスラインが色付けされて正しく動作しました!

これでlightline.vimの導入・設定は完了です。

ステータスライン/タブラインともに表示がリッチになりました!

【ステップ4】ファイルエクスプローラーを使ったファイル操作

IDEであれば、左ペインにファイルエクスプローラーが表示されているのが当たり前ですね。
Vimでも同じような操作ができるように今回は「fern.vim」を導入します。

「fern.vim」は

  • 「ウィンドウスタイル」と「サイドバースタイル」が用意されている
  • ファイル操作のためのデフォルトキーマッピングが用意されている
  • さらにfern.vimを便利にするためのfern.vim用プラグインも豊富

という特徴があります。

このステップでやること

fern.vimの導入

さっそく公式ドキュメントをもとにインストールしていきます。

下記をvimrcに追加しましょう。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
+  Plug 'lambdalisue/fern.vim'
call plug#end()

+let g:fern#default_hidden=1 " 隠しファイルを表示する

次に、Vimを開きなおして:PlugInstallコマンドを実行してプラグインをインストールします。

「ウィンドウスタイル」で動かしてみます。

" 現在の作業ディレクトリでFernを開き、現在のバッファ(ファイル)にフォーカスする
:Fern . -reveal=%

「サイドバースタイル」で動かしてみます。
「サイドバースタイル」で開くには、-drawerオプションを使います。

" 現在の作業ディレクトリでFernを開き、現在のバッファ(ファイル)にフォーカスする
:Fern . -drawer -reveal=%

Fernをさらに便利にするFernプラグインの導入

Fernはこのままでも十分便利です。
ただ、ファイルごとにアイコンを表示したり、ファイルごとにgitステータスの状況を表示したかったりしませんか?
それぞれFern専用プラグインが用意されているのでそちらを導入していきましょう。

ファイルごとにアイコンを表示する

ファイルごとにアイコンを表示するFernプラグインは、fern-renderer-nerdfont.vimがあります。

fern-renderer-nerdfont.vimを動かすためには

が必須になります。

私が使っているOSはWindowsで、ターミナルにはWindows Terminalを使用しています。
参考までにフォントのインストールからフォントの設定までご紹介します。

今回Nerd Fontsは「SourceCodePro」をインストールします。

$ git clone --depth 1 https://github.com/ryanoasis/nerd-fonts.git
$ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
$ cd .\nerd-fonts\
$ ./install.ps1 SourceCodePro

これでNerd Fontsのインストールが完了しました。

次に、Windows Terminalのフォントに「SourceCodePro Nerd Font」を使うように設定します。

次に「nerdfont.vim」と「fern-renderer-nerdfont.vim」をインストールします。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
+  Plug 'lambdalisue/nerdfont.vim'
+  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
call plug#end()

let g:fern#default_hidden=1 " 隠しファイルを表示する
+let g:fern#renderer = 'nerdfont'
+let g:fern#renderer#nerdfont#indent_markers = 1

忘れずに:PlugInstallコマンドを実行しましょう。

正しく設定されているか:echo nerdfont#find()コマンドで確認します。
アイコンが正しく表示されていればOKです(赤枠で囲っているのがアイコンです)。

:Fern . -reveal=%コマンドを実行するとファイル横にいい感じのアイコンが表示されるようになりました!

ファイルごとにgitステータスの状況を表示する

ファイルごとにgitステータスの状況を表示するFernプラグインは、fern-git-status.vimがあります。

このプラグインはインストールするだけでOKです。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
+  Plug 'lambdalisue/fern-git-status.vim'
call plug#end()

試しに今回のTODOサンプルアプリをgit cloneしてきて、README.mdに変更を加えてみると、次のようにREADME.mdの右横にgitステータスの状況が表示されるようになりました!

Fernのファイル操作を理解する

Fernでは、ファイル操作のためのデフォルトキーマッピングとアクションが用意されています。
移動はhjklで移動ができ、Fernを開いた状態で?を押すと、キーマッピング一覧を確認できます。
また、Fernを開いた状態でaを押すと、アクションの入力が求められます。例えば、ファイルを削除したい場合は「remove」と入力してEnterでファイルを削除できます。
アクションとキーマッピングどちらでもお好きなほうを使いましょう。

ここではよく使うキーマッピングを紹介します。

操作/コマンド 説明
? help表示
N ファイル新規作成
K ディレクトリ作成
R リネーム(ファイル or ディレクトリ)
m 移動(ファイル or ディレクトリ)
C コピー(ファイル or ディレクトリ)
M カット(ファイル or ディレクトリ)
P ペースト(ファイル or ディレクトリ)
- 選択(ファイル or ディレクトリ)
a → remove 削除(ファイル or ディレクトリ)

【ステップ5】Vimで簡単なGit操作をしよう

ここではVimで簡単なGit操作をするためのプラグイン等や操作の流れを説明しようと思います。

このステップでやること

  • ファイルの左端にGitの差分情報を表示するプラグイン(vim-gitgutter)の導入
  • Git操作をするためのプラグイン(vim-fugitive)の導入
  • 簡単なGitな操作をしてみよう

ファイルの左端にGitの差分情報を表示するプラグインの導入

Gitの差分情報を表示するために、今回は「vim-gitgutter」を導入します。

下記をvimrcに追加しましょう。
:PlugInstallコマンドを実行してプラグインをインストールします。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
+  Plug 'airblade/vim-gitgutter'
call plug#end()

次に設定を追加します。

set updatetime=100では、ファイルを変更してサイン列に記号が反映されるまでの時間を100msにしています。

~/.vimrc
+set updatetime=100 " 更新時間を100msに設定

+let g:gitgutter_sign_added = '+'
+let g:gitgutter_sign_modified = '>'
+let g:gitgutter_sign_removed = '-'
+let g:gitgutter_sign_removed_first_line = '^'
+let g:gitgutter_sign_modified_removed = '<'
~/.vimrc
augroup vimrc_vim_gitgutter
  autocmd!
  " colorscheme読み込み後、サイン列の記号の背景色を設定
  autocmd VimEnter,ColorScheme * highlight GitGutterAdd guibg=NONE ctermbg=NONE guifg=#000900 ctermfg=2
  autocmd VimEnter,ColorScheme * highlight GitGutterChange guibg=NONE ctermbg=NONE guifg=#bbbb00 ctermfg=3
  autocmd VimEnter,ColorScheme * highlight GitGutterDelete guibg=NONE ctermbg=NONE guifg=#ff2222 ctermfg=1
augroup END

設定適用後に、Git管理下のファイルを編集して左端に記号が表示されるようになっていれば導入完了です。

Git操作をするためのプラグインの導入

VimでGit操作をするために今回は「vim-fugitive」を導入していきます。

下記をvimrcに追加しましょう。
:PlugInstallコマンドを実行してプラグインをインストールします。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
  Plug 'airblade/vim-gitgutter'
+  Plug 'tpope/vim-fugitive'
call plug#end()

導入はこれだけです!w

簡単なGitな操作をしてみよう

Git操作をVimだけで完結しようとすると、かなりの練度が求められる気がしているため、ここでは簡単な操作の説明だけにとどめています。

また、Git操作に関してはCLIで完結したい場合はVim以外にもlazygitやtigという選択肢があり、GUIであれば、VSCode、GitKraken、Sourcetreeなどの選択肢もありますので、自分に使い慣れたものや自分に合ったツールを使うのがいい気がしています。

今回は適当に作ったリポジトリでGit操作を試します。

コミットしてプッシュするまでの流れ
  1. ファイルを編集する
  2. ファイルの差分を:Gitで確認する
  3. sでステージング(add)にあげる
  4. ccでコミットする
  5. :Git pushでコミットをプッシュする

:Git blameでファイルのコミットを確認する

これもよく使うので紹介しておきます。
とても簡単で、ファイルを開いて:Git blameするだけです。

ファイルの特定行の変更を追いたい時などに使います。

GIFでは先ほどのコミットの内容を:Git blameで確認しています。

【ステップ6】ファジーファインダーであらゆるものを検索して開く

ファジーファインダーを導入すると、Vim上であらゆるものを検索して開くことができるようになるので一気に開発効率があがります。

ファジーファインダーには色んな種類がありますが今回は私が使っている「fzf.vim」を導入します。

このステップでやること

  • fzf.vimの導入
  • fzf.vimの操作を理解する

fzf.vimの導入

fzf.vimを動かすためには

が必須になります。

また、合わせて下記もインストールします。

  • シンタックスハイライトをいい感じに表示
  • :Rgコマンドを使うため

fzfの公式ドキュメントを参考にインストールします。

$ sudo apt install fzf
$ which fzf #=> /usr/bin/fzf

次にbatの公式ドキュメントを参考にインストールします。

$ sudo apt install bat
$ sudo ln -s /usr/bin/batcat /usr/local/bin/bat # batで使えるように
$ which bat #=> /usr/local/bin/bat

最後にripgrepの公式ドキュメントを参考にインストールします。

$ sudo apt install ripgrep
$ which rg #=> /usr/bin/rg

次に下記をvimrcに追加しましょう。
:PlugInstallコマンドを実行してプラグインをインストールします。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
  Plug 'airblade/vim-gitgutter'
  Plug 'tpope/vim-fugitive'
+  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
+  Plug 'junegunn/fzf.vim'
call plug#end()

これで準備ができました!

fzf.vimの操作を理解する

TODOサンプルアプリを使って、いくつか実際の操作を紹介しようと思います。

:GFilesコマンドでGit管理のファイル一覧をあいまい検索してファイルを開く
  1. :GFilesコマンドを実行する
  2. Git管理のファイル一覧からあいまい検索する
  3. 開きたいファイルが見つかったらEnterで開く

:Rgコマンドで全文検索する
  1. :Rgコマンドを実行する
  2. 全文検索する
  3. 開きたいファイルが見つかったらEnterで開く

:BCommitsコマンドでカレントバッファのコミット一覧を調べる
  1. :BCommitsコマンドを実行する
  2. カレントバッファのコミット一覧が表示される
  3. 開きたいコミットをEnterで開く

よく使うコマンド

よく使うコマンドをピックアップしてみました。
全てのコマンドを知りたい方はドキュメントを確認してみてください。

操作/コマンド 説明
:Files ファイル一覧
:GFiles Git管理のファイル一覧
:GFiles? Gitステータス
:Rg 全文検索(rg)
:Buffers バッファ一覧
:BCommits カレントバッファのコミット一覧
:Commits コミット一覧
:BLines カレントバッファの行
:Maps マッピング一覧
:Commands: コマンド一覧
:History 開いたファイルの履歴
:History/ 検索履歴
:History: コマンド履歴

【ステップ7】言語別の開発を便利にするプラグインを入れよう

ここでは、Railsの開発を便利にする「vim-rails」を紹介します。

このステップでやること

vim-railsの導入

下記をvimrcに追加しましょう。
:PlugInstallコマンドを実行してプラグインをインストールします。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
  Plug 'airblade/vim-gitgutter'
  Plug 'tpope/vim-fugitive'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'junegunn/fzf.vim'
+  Plug 'tpope/vim-rails'
call plug#end()
  1. api/app/graphql/resolvers/todos/todo_resolver.rbを開く
  2. Todoという文字の上にカーソルを移動させる
  3. gfでカーソル下の文字列から対応するファイルを開く
  4. :Aで今開いているファイルに対応するSpecファイルを開く

今回は下記の二つのコマンドを紹介しました。

操作/コマンド 説明
:A 対応するSpecファイルを開く
gf カーソル下の文字列から対応するファイルを開く

【ステップ8】LSPクライアントを使ってVimをモダンなIDEに進化させよう

LSPとは、Language Server Protocolの略です。

オートコンプリート、goto定義、hover時のドキュメント、ソースコードに警告・エラーの表示などプログラミングを便利にする言語特有の機能を提供するためのプロトコルです。

モダンなIDE同様の機能をVimでも使えるように今回はLSPクライアント(今回導入するのは、「vim-lsp」)を導入していきます。

参考:vim-lsp の導入コストを下げるプラグイン vim-lsp-settings を書いた。 - Qiita

このステップでやること

  • vim-lspの導入
  • vim-lspの機能を使ってみる

vim-lspの導入

今回vim-lspを導入していきますが、vim-lsp単体だと導入のハードルが高いため、簡単に導入できるようにvim-lsp-settingsというプラグインがあります。

vim-lsp-settingsのドキュメントを参考にしてインストールしていきます。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
  Plug 'airblade/vim-gitgutter'
  Plug 'tpope/vim-fugitive'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'junegunn/fzf.vim'
  Plug 'tpope/vim-rails'
+  Plug 'prabirshrestha/vim-lsp'
+  Plug 'mattn/vim-lsp-settings'
call plug#end()

次に自動補完を使用するためのプラグインもインストールしておきます。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
  Plug 'airblade/vim-gitgutter'
  Plug 'tpope/vim-fugitive'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'junegunn/fzf.vim'
  Plug 'tpope/vim-rails'
  Plug 'prabirshrestha/vim-lsp'
  Plug 'mattn/vim-lsp-settings'
+  Plug 'prabirshrestha/asyncomplete.vim'
+  Plug 'prabirshrestha/asyncomplete-lsp.vim'
call plug#end()

導入自体はこれで完了ですが少しだけ設定を追加しておきます。

vim-lspの設定を追加します。

~/.vimrc
+let g:lsp_diagnostics_enabled = 1                        " Diagnosticsを有効にする
+let g:lsp_diagnostics_echo_cursor = 1                    " カーソル下のエラー、警告、情報、ヒントを画面下部のコマンドラインに表示
+let g:lsp_diagnostics_echo_delay = 50                    " Diagnosticsの表示の遅延を50msに設定
+let g:lsp_diagnostics_float_cursor = 1                   " カーソル下のエラー、警告、情報、ヒントをフロート表示
+let g:lsp_diagnostics_signs_enabled = 1                  " 画面左端のサイン列にエラー、警告、情報、ヒントのアイコンを表示
+let g:lsp_diagnostics_signs_delay = 50                   " Diagnosticsのサイン列の表示の遅延を50msに設定
+let g:lsp_diagnostics_signs_insert_mode_enabled = 0      " 挿入モード時、Diagnosticsのサイン列を表示しない
+let g:lsp_diagnostics_highlights_delay = 50              " Diagnosticsの指摘箇所自体の文字ハイライト表示の遅延を50msに設定
+let g:lsp_diagnostics_highlights_insert_mode_enabled = 0 " 挿入モード時、Diagnosticsの指摘箇所自体の文字ハイライトを表示しない
+let g:lsp_document_code_action_signs_enabled = 0         " 画面左端のサイン列にコードアクションのアイコン非表示

asyncomplete.vimの設定を追加します。

~/.vimrc
+let g:asyncomplete_popup_delay = 100 " 補完メニューを開く際の遅延を100msに設定

+imap <expr> <Tab>   pumvisible() ? "\<C-n>" : "\<Tab>"
+imap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
+imap <expr> <cr>    pumvisible() ? asyncomplete#close_popup() : "\<cr>"

vim-lspの機能を使ってみる

vim-lspは奥が深いので簡単な内容だけを取り扱ってます。

Language Serverをインストールする

IDE同様の機能を得るためには言語ごとにLanguage Serverをインストールする必要があります。

インストール方法は2種類あります。

  • :LspInstallServerを使う(参考)
  • :LspManageServersを使う(参考)

今回は、TODOサンプルアプリを使って、インストールしたいLanguage Serverを画面から選択してインストールできる:LspManageServersを使ってみます。

TypeScriptのLanguage Server「typescript-language-server」をインストールする

「typescript-language-server」を使うには、ホスト側にNode.jsとyarn(TODOサンプルアプリではyarnを使っているため)をインストールしている必要がありました。
※インストールしていないと、Language Serverのインストール候補にでてきません。

$ curl https://get.volta.sh | bash
$ source ~/.bashrc
$ volta install node@14 # TODOサンプルアプリのバージョンに合わせてます
$ volta install yarn
$ cd sample-rails-graphql-typescript-react-apollo/frontend/
$ yarn install # これしないとLanguage Serverが動かない
  1. :LspManageServersを実行する
  2. 「typescript-language-server」上にカーソルを移動し、iでインストールする
  3. vimを開き直して、tsxファイルを開いて、:LspStatusで「typescript-language-server」がrunningになっていることを確認する

動くようになったので試しにコード補完、定義元に移動を試してみます。

RubyのLanguage Server「solargraph」をインストールする

「solargraph」を使うには、ホスト側にRubyをインストールしている必要がありました。
※インストールしていないと、Language Serverのインストール候補にでてきません。

$ sudo apt install rbenv
$ mkdir -p "$(rbenv root)"/plugins
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby
$ rbenv install 3.1.2  # TODOサンプルアプリのバージョンに合わせてます
$ rbenv global 3.1.2
$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
$ source ~/.bashrc

なぜかtypeprofが有効になってしまうので先に下記も設定しておきます。

~/.vimrc
let g:lsp_settings_filetype_ruby = ['solargraph']
  1. :LspManageServersを実行する
  2. 「solargraph」上にカーソルを移動し、iでインストールする
  3. vimを開き直して、rbファイルを開いて、:LspStatusで「solargraph」がrunningになっていることを確認する

動くようになったので試しにコード補完、定義元に移動を試してみます。

よく使うコマンド

よく使うコマンドをピックアップしてみました。
全てのコマンドを知りたい方はドキュメントを確認してみてください。

操作/コマンド 説明
:LspCodeAction ファイルに適用できるコマンドのリストを取得(quickfix)
:LspDocumentDiagnostics ドキュメント診断を行う
:LspDocumentFormat ドキュメント全体をフォーマット
:LspHover 情報をホバー表示
:LspRename シンボルの名前を変更
:LspDefinition 定義に移動
:LspReferences 参照を検索
:LspStatus 言語サーバーのステータス表示

【おまけ】コマンドやショートカットキーを覚えるのが辛いときは、vim-which-keyを使おう

ここまでたくさんのコマンド、たくさんのショートカットキーが出てきましたが途中で「こんなの覚えられない…」と思った人いませんか?

そんな方のために「vim-which-key」を紹介しておきます。

かくいう私もたくさんのコマンド、たくさんのショートカットキーを覚えるのが辛くVimをあきらめていた時期もありましたが、このプラグインを使ってからはだいぶ覚える周りが楽になりました。

このプラグインを導入すると、利用可能なキーバインディングをポップアップで表示してくれます。また、キーバインディングは自分の好きなようにカスタマイズできます。

参考に筆者の設定も貼っておきます。
(自分の覚えやすいキーショートカットにできて、管理もできるのでとても助かってます)

この記事では入り口だけ紹介します。

プラグインをインストールします。

~/.vimrc
call plug#begin('~/.vim/plugged')
  Plug 'vim-jp/vimdoc-ja'
  Plug 'itchyny/lightline.vim'
  Plug 'lambdalisue/fern.vim'
  Plug 'lambdalisue/nerdfont.vim'
  Plug 'lambdalisue/fern-renderer-nerdfont.vim'
  Plug 'lambdalisue/fern-git-status.vim'
  Plug 'airblade/vim-gitgutter'
  Plug 'tpope/vim-fugitive'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'junegunn/fzf.vim'
  Plug 'tpope/vim-rails'
  Plug 'prabirshrestha/vim-lsp'
  Plug 'mattn/vim-lsp-settings'
  Plug 'prabirshrestha/asyncomplete.vim'
  Plug 'prabirshrestha/asyncomplete-lsp.vim'
+  Plug 'liuchengxu/vim-which-key'
call plug#end()

設定を追加します。
下記はtキー(トリガー)にタブ系のキーを割り当てており、tキーを押すと次に続いて打つキーの一覧がポップアップが表示さるので、そのキーを押すと対応した操作が実行できます。

~/.vimrc
set timeoutlen=500 " 100msだと他のキーマッピングが上手く動かないため500msに設定

let g:which_key_ignore_outside_mappings = 1 " 辞書にないマッピングは非表示にする
let g:which_key_sep = '→'
let g:which_key_use_floating_win = 0

let g:which_key_map_tabs = { 'name' : '+tabs' }
call which_key#register('t', 'g:which_key_map_tabs')
nmap t :<c-u>WhichKey 't'<CR>
vmap t :<c-u>WhichKeyVisual 't'<CR>

let g:which_key_map_tabs.e = [':tabedit'   , 'new']
let g:which_key_map_tabs.t = [':tab split' , 'split']
let g:which_key_map_tabs.h = [':tabprev'   , 'focus left']
let g:which_key_map_tabs.l = [':tabnext'   , 'focus right']
let g:which_key_map_tabs.H = [':tabmove -1', 'move left']
let g:which_key_map_tabs.L = [':tabmove +1', 'move right']

対応表にすると次のような感じになります。

操作/コマンド 説明
te 新規タブを開く
tt タブ分割
th 前のタブに移動
tl 次のタブに移動
tH 現在タブ自体を左に移動
tL 現在タブ自体を右に移動

実際に使ってみたGIFです。

さいごに

この記事は8つのステップに分けて、私が実際にWeb開発で使っているもので、できるだけWeb開発にあると便利なものをステップアップで紹介してきました。

ここまできたら実践で使えるレベルのVimに育っているはずです。

ただ、この記事で説明していないこともたくさんあります。
おそらくある程度使える環境は整ったものの実際に使おうとするとたくさんの壁があるはずです。
Vim操作、各プラグインの操作や設定の理解、自分の使いやすいようにカスタマイズしていくなどは実際に使いながら練度をあげていくしかありません。

記事内では説明口調でさも詳しそうな雰囲気がありますが、筆者も雰囲気でVimを使っているところはたくさんありますし、何度も挫折をしたことがありますw

挫折した理由はいろいろありますが、おもな理由はWeb開発でVimが使いたいのに、Vimだけで完結しようとかなりハードルが高いんです。

  • 記事を見てその人のVimrcを丸コピで使う
    • → 記事に説明が書いている内容だと動くけど、ちょっとカスタマイズしようとすると急にハードルが高くなる
    • → Vim以外の話も出てきて覚えることがめちゃくちゃ多いので、ちょっと時間空くと忘れてる

このような感じで一気にやろうとしてきて失敗してきました。

こういった挫折を何度か繰り返したあと、「ちゃんとVimを理解しよう」と思い、helpを日本語化したり、Vimを好きになる本を読んだり、プラグイン管理について理解したり、と順序を追って少しずつ理解していくと、自分の分かる範囲が少しずつ広がっていって、新しく覚えることに集中できるようになって、今はほぼメインにVimを使ってWeb開発が完結できるようになってきました。

そんな昔の自分に向けて、こういうステップで覚えていくといいよという記事を書きました。

楽しいVim活ライフを送りましょう!

追記(2022/11/8)

さっそく身近な人からフィードバックをいただけたので追記しようと思います!
(フィードバックありがとうございます!)

Q. どういう時にVimのhelpを見ればいい?

例えば、次のようなときに見るとよいと思います。

  • Vimの設定について知りたい → (例):h number
  • プラグインのこと(変数の意味、設定の意味 etc..)について知りたい → (例):h g:which_key_ignore_outside_mappings

Vimのhelpを日本語化するプラグインを記事中では入れているので日本語で読むことができます。
ですが、プラグインの説明に関しては日本語化されていません。
私の場合、日本語化されていないものは、skanehira/denops-translate.vimを使ってVim内で翻訳したり読むことが多いです。

Q. プラグインの詳しい説明を見たいときはどこを見るといい?

プラグインのリポジトリを見ると、READMEとは別に「doc」フォルダがあり、その中のテキストファイルに詳しい説明が書いてあるので、READMEでわからないときは「doc」フォルダを見てみるといいかもです。

Q. プラグインや設定でどの設定が影響しているか切り分けたいときはどうするとよい?

私の場合は、vim -u NONEでvimrcなど設定を何も読み込まない状態でVimを起動して動作を確認したり、vim-plugを使っている場合はPlug xxxをコメントアウトしたりして問題の切り分けをしていくことが多いです。

Q. Fernをウィンドウスタイルで開いたあとどうやって戻れますか?

そのときはいい回答が思いつかなかったのですが、下記で戻れました。

  • Fernを開く前に何かのファイルを開いていた場合は、C-^で直前のバッファに戻れます
  • Fernを開く前に無名のバッファを開いていた場合は、上記のC-^では戻れないため、:enewすると無名のバッファを新規で開けます

Discussion