Vimが提供しているカーソルの移動機能を使えば、当然CSVファイルでもカーソルを移動させることができる。「chrisbra/csv.vim」は、これに加えてセルの間を移動するためのショートカットを提供している。主なショートカットは次の通りだ。

移動キー 内容
「Ctrl」+「→」 右の列へ移動
L 右の列へ移動
W 右の列へ移動
「Ctrl」+「←」 左の列へ移動
E 左の列へ移動
H 左の列へ移動
列を上へ移動
K 列を上へ移動
列を下へ移動
J 列を下へ移動

右のセルへの移動と、左のセルへの移動、この2つのショートカットは結構使うことになる。何種類か用意されているので、覚えやすいものを使ってもらえればと思う。

例えば、カーソルが次のように1列目にあったとする。

カーソルが1列目にある状態

この状態で「L」または「W」または「Ctrl」+「→」を押すと、次のようにカーソルが次のセルへ移動する。

カーソルを次のセルへ移動させたところ

このセルの移動はVimの規則に従って数字と組み合わせて連続実行させることができる。再びカーソルを行の先頭に戻してから(「0」でカーソルが行の先頭へ戻る)、次のように「4L」または「4W」、もしくは「4」+「Ctrl」+「→」のように入力する。こうすると、4回右のセルへ移動し、5列目へカーソルが移動する。

繰り返し処理を行って5列目へカーソルを移動させたところ

最低限として、「L」や「W」で右側のセルへ移動する方法だけ覚えておけばよい。Vimでは「0」でカーソルが行頭に移動するので、「0」を押してから「4」+「L」といった操作で特定の列まで移動させることで左側のセルへ移動する操作の代替とすることができるからだ。

現在の列番号、列ヘッダ、行ヘッダを表示

検索や列の移動を繰り返していると、「あれ、いま何列目にいるんだっけ」ということがよくある。スプレッドシートアプリケーションならば上部にセル番号が表示されているので何列目かわかりやすいが、chrisbra/csv.vimだとよくわからなくなってしまう。そんなときは、CSVWhatColumnコマンドだ。このコマンドでカーソルのある列が何列目かを表示させることができる。

CSVWhatColumnコマンドでカーソルが何列目にあるか表示させる

CSVWhatColumnコマンドは「CSVWhatColumn!」のように「!(エクスクラメーションマーク)」を付けると1行目の同じ列の値を表示してくれる。つまり、その列のヘッダを表示させることができるわけだ。

「CSVWhatColumn!」で1行目の同じ列の値を表示させることができる(列のヘッダを表示)

列数が多い場合には1列目が表示されない状態が続くことも多く、プライマリIDのような値が確認できなくなる。スプレッドシートアプリケーションなら、列を固定して常時表示させるようにするところだろう。chrisbra/csv.vimでは、CSVVHeaderコマンドで同じことができる。

CSVVHeaderで2列目を別ウィンドウで常に表示

CSVファイルのなかでカーソルを移動させているときは、「CSVWhatColumn」「CSVWhatColumn!」「CSVVHeader」で自分の場所を把握することができる。この操作はぜひ覚えてしまいたい。

ユーザー関数を定義してカスタマイズしよう

このようにセルを左右に移動する方法は提供されているのだが、指定した列に移動する方法は提供されていない。例えば6列目に移動する場合、chrisbra/csv.vimでは次のように操作することになる。

  1. ESC
  2. 0
  3. 「5」+「L」


できれば「6列目へ移動」といったコマンドを入力したい。「:Retu 6」みたいな入力で移動してくれるとわかりやすい。頭の中で列数から1を引いて「ESC」+「0」+「5」+「L」のように高速入力するのは、ささやかな手間だが度重なると面倒だ。

また、先述の通り、居場所を確認するには「CSVWhatColumn」「CSVWhatColumn!」「CSVVHeader」を使えばよいのだが、これらのコマンドは名前が長いし、覚えにくい。とは言えCSVファイルの編集を頻繁にするのであれば必須の機能なので、もっと使いやすくしたいところだ。

そこで、このプラグインを便利に利用するための機能を自分でつくってみよう。ここでは次のようなコマンドを作ることにする。

コマンド 内容
Retu カーソルのある列の列番号を表示
Retu 列番号 指定した列へカーソルを移動
Retumei カーソルのある列のヘッダ内容を表示
Retumei 列番号 指定した列のヘッダ内容を表示

今回は実装例を掲載しておく。次のようなコードを設定ファイルに追加しておけば、上記のコマンドが使用できるようになる。基本的に、先ほど説明した操作をユーザー定義関数のなかで実行しているだけだ。

" 列番号が指定された場合、その列へ移動
" 列番号が指定されなかった場合、連剤の列の列番号を表示
function MyCSVMoveToColumn(...)
  if a:0 == 0
    CSVNrColumns
  else
    let cmd = "normal 0"
    execute(cmd)

    let offset = a:1 - 1
    let cmd = "normal " . offset . "L"
    execute(cmd)
  end
endfunction
command -nargs=? Retu call MyCSVMoveToColumn(<f-args>)

" 現在の列または指定した列のヘッダを表示
function MyCSVShowHeaderNameOfColumn(...)
  if a:0 == 0
    CSVWhatColumn!
  else
    let cursor_pos = getpos(".")
    call MyCSVMoveToColumn(a:1)
    CSVWhatColumn!
    call setpos('.',cursor_pos)
  end
endfunction
command -nargs=? Retumei call MyCSVShowHeaderNameOfColumn(<f-args>)

上記の設定については、カスタマイズについて説明するときに詳しく取り上げるので、ここでは使用例を見ていきたい。まず次のスクリーンショットは「:Retu 4」を実行した結果だ。カーソルが4列目へ移動していることがわかる。

:Retu 4でカーソルを4列目へ移動

また、次のスクリーンショットは「:Retu 6」を実行した結果だ。6の数字に隠れてしまっていてとてもわかりにくいのだが、カーソルは6列目へ移動している。

:Retu 6でカーソルを6列目へ移動

次のスクリーンショットは「:Retumei」を実行したところだ。カーソルのある列の1行目の値、いわゆるヘッダの内容が出力されていることがわかる。

「:Retumei」を実行したところ

このように、よく使う機能に関しては自分が使いやすいように組み合わせるなどカスタマイズして一発で処理が完了するようにしておくとよい。こういったカスタマイズをするとしないのとでは、操作にかかる時間が大きく変わってくる。どういう処理を行いたいのか整理し、それをユーザー定義関数として定義してコマンドやショートカット入力で実行できるようにすることで、作業効率が大幅にアップする。ここまでできるようになれば、Vimによる作業効率は最高に向上するだろう。

最初は簡単なユーザー定義関数を書くのも苦労するかもしれないが、慣れてくるとサクサクと作れるようになってくる。そうなるとさらに自分だけの機能を実装するようになり、Vimが手放せなくなってくる。ある程度整理したらGitHub.comにアップロードするなどすれば、Deinなどのプラグイン管理機能でも管理できるようになり、新しい環境への導入も簡単になる。こうしてどんどん”沼”にはまっていき、Vimから抜け出せなくなっていくわけだ。とは言え、その努力に報いるだけの編集効率は得られるようになるので、悪くない時間の投資ではないかと思う。

使っている設定ファイルとセットアップ方法

プラグインを使うためにプラグインマネージャ「Dein」をセットアップする方法と、本連載で使っている設定ファイル(~/.vimrc)は以下の通りだ。

◆プラグインを使うために「Dein」をセットアップする方法

mkdir -p ~/.cache/dein
cd ~/.cache/dein/
curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
sh ./installer.sh .
rm ./installer.sh

◆本連載で使っている~/.vimrcファイル

"dein Scripts=============================
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=~/.cache/dein/./repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('~/.cache/dein/.')
  call dein#begin('~/.cache/dein/.')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/./repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here
  call dein#add('junegunn/seoul256.vim')
  call dein#add('vim-airline/vim-airline')
  call dein#add('vim-airline/vim-airline-themes')
  call dein#add('preservim/nerdtree')
  call dein#add('tpope/vim-commentary')
  call dein#add('tpope/vim-fugitive')
  call dein#add('fholgado/minibufexpl.vim')
  call dein#add('dense-analysis/ale')
  call dein#add('junegunn/fzf', {'build': './install --all'})
  call dein#add('junegunn/fzf.vim')
  call dein#add('sheerun/vim-polyglot')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif

" seoul256
let g:seoul256_background = 233
colo seoul256

" vim-airline
let g:airline_powerline_fonts = 1
let g:airline_theme = 'molokai'

" NERDTree
"  <C-o> open NERDTree
nnoremap <silent> <C-o> :NERDTreeToggle<CR>

" minibufexpl
nnoremap <silent> bn :<C-u>:bnext<CR>
nnoremap <silent> b1 :<C-u>:b1<CR>
nnoremap <silent> b2 :<C-u>:b2<CR>
nnoremap <silent> b3 :<C-u>:b3<CR>
nnoremap <silent> b4 :<C-u>:b4<CR>
nnoremap <silent> b5 :<C-u>:b5<CR>
nnoremap <silent> b6 :<C-u>:b6<CR>
nnoremap <silent> b7 :<C-u>:b7<CR>
nnoremap <silent> b8 :<C-u>:b8<CR>
nnoremap <silent> b9 :<C-u>:b9<CR>

" fzf
nnoremap <silent> fzf :Files<CR>
nnoremap <silent> ls :Buffers<CR>

"End dein Scripts=========================

set number
syntax on
set whichwrap=b,s,[,],<,>,~,h,l
set cursorline
set incsearch
set hlsearch
set ignorecase

付録「chrisbra/csv.vim」の操作/設定方法まとめ

コマンド 内容
CSVWhatColumn カーソルが何列目にあるか
CSVWhatColumn! 同列1行目の内容を表示
CSVNrColumns 最大列数を表示(先頭から10行で判断)
CSVSearchInColumn /パターン/ 現在の列をパターンで検索
CSVSearchInColumn 列番号 /パターン/ 指定した列をパターンで検索
CSVHiColumn 現在の列を強調表示
CSVHiColumn 列番号 指定した列を強調表示
CSVHiColumn! 列の強調表示を解除
CSVArrangeColumn テーブル形式での表示へ切り替え(実験的機能)
CSVTabularize テーブル形式でのプレビュー表示
CSVDeleteColumn 現在の列を削除
CSVDeleteColumn 列番号 指定した列を削除
CSVHeader 1行目を別ウィンドウで表示
CSVHeader 行数 先頭から指定行数分を別ウィンドウで表示
CSVHeader! 開いた行ヘッダウィンドウを閉じる
CSVVHeader 1列目を別ウィンドウで表示
CSVVHeader 列番号 行頭から指定列数分を別ウィンドウで表示
CSVVHeader 開いた列ヘッダウィンドウを閉じる
CSVSort 現在の列でファイルをソート
CSVSort 列番号 現在の列でファイルをソート
CSVSort! 現在の列でファイルを逆順にソート
CSVSort! 列番号 現在の列でファイルを逆順にソート
CSVColumn 現在の列をコピー
列番号CSVColumn 指定した列をコピー
CSVMoveColumnor 現在の列を最後の列の右側へ移動
CSVMoveColumn 列番号 列番号 最初に指定した列を、2つ目に指定した列の右側へ移動
CSVSumCol 現在の列の合計を出力
CSVSumCol 列番号 指定した列の合計を出力
CSVSumRow 行の合計を出力
CSVNewRecord 新しい行を作成
CSVNewDelimiter デリミタ 区切り文字を変更
CSVConvertData データをほかの形式に変換
CSVDuplicates 列番号 指定した列で重複している行を出力
CSVAnalyze 現在の列を分析する(値とその数、割合など)
CSVAnalyze 列番号 指定した列を分析する(値とその数、割合など)
CSVVertFold 1列目から現在の列を折りたたむ
CSVVertFold 列番号 1列目から指定した列までを折りたたむ
CSVVertFold! 列の折りたたみを解除する
CSVTranspose 列と行を入れ替える(転置)
CSVAddColumn 現在の列の右側に新しい列を追加
CSVAddColumn 列番号 指定した列の右側に新しい列を追加
CSVDupColumn 現在の列を右側に複製
CSVDupColumn 列番号 指定した列を右側に複製
CSVSubstitute 列番号/パターン/文字列/ 指定した列で置換
CSVColumnWidth 列ごとの最大文字数を出力
CSVCountCol 現在の列内の値の数を出力
CSVCountCol 列番号 指定した列内の値の数を出力
CSVMaxCol 現在の列内の最大値を出力
CSVMaxCol 列番号 指定した列内の最大値を出力
CSVMaxMin 現在の列内の最小値を出力
CSVMaxMin 列番号 指定した列内の最小値を出力
CSVAvgCol 現在の列内のデータの平均値を出力
CSVAvgCol 列番号 指定した列内のデータの平均値を出力
PopVarCol 現在の列の母集団分散を出力
PopVarCol 列番号 指定した列の母集団分散を出力
SmplVarCol 現在の列の標本分散を出力
SmplVarCol 列番号 指定した列の標本分散を出力
PopStdCol 現在の列の母標準偏差を出力
PopStdCol 列番号 指定した列の母標準偏差を出力
SmplStdCol 現在の列の標本標準偏差を出力
SmplStdCol 列番号 指定した列の標本標準偏差を出力
移動キー 内容
「Ctrl」+「→」 右の列へ移動
L 右の列へ移動
W 右の列へ移動
「Ctrl」+「←」 左の列へ移動
E 左の列へ移動
H 左の列へ移動
列を上へ移動
K 列を上へ移動
列を下へ移動
J 列を下へ移動
フィルタキー 内容
↩️ 現在の列と一致しないすべての行を動的に折りたたむ
Space 現在の列と一致するすべての行を動的に折りたたむ
BS 動的フィルタから最後のアイテムを削除
設定項目 内容
g:csv_delim デフォルトのデリミタ
g:csv_no_conceal 1に設定するとデリミタ部分を|で視覚的に表示(デフォルトは設定されていない)
g:csv_highlight_column ‘y’に設定するとカーソルがある列を自動でハイライト
b:csv_headerline ヘッダの行数を指定。0を指定するとヘッダとしてのハイライトが行われなくなる