見出し画像

健康で文化的な最低限の生活のためのvimrcの話

そういえばプロフィールに「vimを愛する」書いとるのにちゃんとvimの話をしていないなと思ったのでそろそろ……というか、実際はvimのお勉強を始めた時にQiitaにそこそこの量のエントリを書いていたので「今更書くかね?」という気もするんですけど、当時の記事からかなり時間もたったのでそろそろ書いておこう、と。

実際のところなんですけど、ここ数週間会社にとんでもないデスマーチが襲来していて、その中で久しぶりに訪れた土日休をどうやって文化的に過ごすか考えた結果、1つエントリを書いておこうという次第です。

なお先日のエントリの通りで実際の僕の生業は技術系とは一切関係がないことは付け加えておきます。

~/.vim/vimrc

https://github.com/astrorobot110/vimrc/blob/8e7ddffe06f42115cba45bd251da4d54e96dc9a0/vimrc

何やってますのこれ?

先に方針ですが、リマップの小技みたいなのはそもそもvimrc外に書いている上で、結局手癖の話になるので「あまり役に立たない情報」として割愛します。僕自身のvimとの付き合い方も界隈で言う「スパルタン」に属するのもあります。vimrc内で触れている部分に関しては解説しますが、基本的には蛇足と言う事で……。

<script>

if v:version >= 900
  let $VIMFILES = expand('<script>:p:h')
else
  let $VIMFILES = expand('<sfile>:p:h')
endif

"<script>"は「現在実行しているvimscriptのファイル名」に置き換えられます。この場合はvimrcのファイル名が入っているので、修飾子を使ってディレクトリをフルパスで取得し、環境変数$VIMFILESに格納しています。多分かなり最初の頃に(但し当時はフルパスを生書きで)した設定で、当時はこれを変数にすべきか環境変数にすべきかの区別がついていないまま環境変数を使ってしまっているのですが、まぁ環境変数の方がよさそうです。

実際にどう使っているかと言うとスニペットとして……

cabbrev vv= $VIMFILES
cabbrev vV= $VIMFILES/vimrc
cabbrev vs= $VIMFILES/plugin
cabbrev vS= $VIMFILES/pack/myplug/opt
cabbrev va= $VIMFILES/autoload
cabbrev vA= $VIMFILES/plugin/command.vim
cabbrev vp= $VIMFILES/vim-plug
cabbrev vP= $VIMFILES/vim-plug/vim-plug.conf.vim

……みたいなことをしています。vimの設定群にいつでもアクセスするための方法をスニペットで行うのは「キーマップを増やさない」ための方法で、この後も数回出てきます。

"v:version"で分岐しているのは後方互換性の為ですが、そろそろ要らないかも……。

デバイス識別

if has('win32')
  let g:device = tolower($COMPUTERNAME)
  set fileformat=dos
  set fileformats=dos,unix,mac
  set termguicolors
elseif has('unix')
  let g:device = tolower(system('echo $(hostname)')) ->trim()
  try
    language ja_JP.utf8
  catch /E197/
  endtry
  set fileformat=unix
  set fileformats=unix,dos,mac
endif

現在僕がメインで使う端末がwindowsとlinuxの両方になるので、同じvimrcを使えるように色々と根回しはしているのですが、どうしてもデバイスそのものを指定しないとならない時があります……正確にはありました。というわけで"g:device"に使っている端末名を放り込んであります。過去形で書いてある通り最近はこれによる識別がほぼほぼ必要なくなっているのですが。

完全におミソで使っているDroidVimが":language ja_JP.utf8"を食べてくれなかったのでtry文でエラーを無視しています。昔はガッツリ使い込んでいたんですけど、サンドボックスの問題などもあって残念ながら今は……。

vim-plug

単純に、パッケージ管理はvim-plugです。設定群は別ファイルにしていますが、公式tipsの「vim-plugがなければcurlしてくれる設定」は書いてあります。

Automatic installation
Place the following code in your .vimrc before plug#begin() call

tips · junegunn/vim-plug Wiki

vimrc読み直し時は設定再読み込みをスキップできるように"v:vim_did_enter"で分岐しています。

":colorscheme"を遅延させる理由

" タイミング調整の為にオートコマンドに(わざわざautocmd.vimに書かんよ)
autocmd VimEnter * ++once ++nested colorscheme janah

autocmdでvimrcの読み込み処理が終わった後にカラースキームを読み込んでほしい、というちょっと癖のある設定をしています。ちゃんとした理由があるのでちょっとオートコマンドの設定を併記しておきます。

" Some trick in colorscheme 'janah'.
augroup cs-janah
  autocmd!
  autocmd ColorScheme janah call s:janah()

  function s:janah() abort
    " Terminal用
    highlight Normal ctermbg=235

    " ステータスライン調整
    highlight StatusLine term=bold,reverse cterm=bold,reverse gui=bold,reverse ctermfg=216 ctermbg=16 guifg=#ffaf87 guibg=#3a3a3a

    " 分割線
    highlight VertSplit    term=reverse ctermfg=237 ctermbg=bg  guifg=#3a3a3a guibg=bg
    highlight CursorLineNr term=bold    ctermfg=110 ctermbg=240 guifg=#87afdf guibg=#585858

    " カーソルの色変更
    if has('multi_byte_ime')
      highlight CursorIM guifg=bg guibg=#87dfaf
    endif
  endfunction
augroup END

……という設定をオートコマンドでしています。これはカラースキームのカスタム部分を別に書いておき、オートコマンドの"ColorScheme"で発火させたかったんですが、"~/.vim/plugin"に入っているカラースキームのカスタム設定の読み込みとどうしてもタイミングが合わず、オートコマンドが発火しなかったのでこのような方法になっています。良くない方法かもしれないです。

ドキュメントディレクトリのめんどくさい話

" 汎用アドレス
let $DOCS = expand('~/Documents')

if isdirectory($DOCS..'/Documents')
	let $DOCS .= '/Documents'
endif

let g:private = { 'doc': $DOCS }

set backup
set backupdir=$DOCS/backup

環境変数を使うのはまぁともかくとして(これもvimを使い始めたころからの設定で、こっちは継ぎ足してきたvimrcの互換性の問題があります)、$DOCS追加でパスを書き込んでいます。最近のwindowsってドキュメントフォルダに何でもかんでも突っ込まれてしまうので、対策として"~/Documents/"内にもう一層、プレーンテキストや、いわゆるoffice系のファイルを整理するドキュメントディレクトリを掘る、という余り幸せには見えない理由があります。というわけでDocumentsディレクトリが二重であればそちらをドキュメント群のディレクトリとしますね、という設定です。

ちなみに環境変数にしてあるのでvimのコマンドラインでパス展開がしやすくなっていますが、さらに"g:private"変数に辞書型で格納しています。理由なのですが、スニペットをまとめてある別のvimscriptで……

for [ key, value ] in items(g:private)
  if isdirectory(expand(value)) || filereadable(expand(value))
    call execute(printf('cabbrev %s= %s', key, value))
  endif
endfor

……なんてことをしています。ここが実行されるまでに"g:private"に値を突っ込んでおけば、自動でスニペットが登録されますよ、と言う事です。

ちょっとだけリマップの話

前述の通りよほど利便性がよくなる見通しがない限りはキーマップの設定を行っていないのですが、その中でも数ヶ所はしているので触れておきます。

let g:mapleader = "\<space>"

……これは定番っぽいのでまぁ、として。リマップの設定ファイルがそもそもvimrcと分けられているので定番っぽい奴と、僕固有の問題によるけどちょっとクレバーにやれたものだけご紹介します。

inoremap <Left> <nop>
inoremap <Down> <nop>
inoremap <Up> <nop>
inoremap <Right> <nop>

当然です。疑問を持たないように。ノーマルモードでは使用を許している理由はDroidVimでは流石に使える方が良かったので妥協しました。

" ハイライト消し
noremap <ESC><ESC> :<C-u>noh<CR>

ハイライトを消したい時に押しやすいキーマップを探した結果ここに行きつきました。なんかもったいない気もするんですけど。

ターミナルモードだけは別なアサインをしています。

" ターミナルモードあるっぽい?
tnoremap <Esc><Esc> <C-w>N

ハンディにターミナルモードを抜ける手段として使っています。流石にctrlとshiftでバタバタする"<C-w>N"は押しづらくて。

" 設定群への移動専用
nnoremap <Leader>v :<C-u>e v

先に設定群のファイルを開くためのスニペットが……例えば~/.vimだと"vv="だったのを思い出していただけると何をしているか分かるかと思います。

" bang実行
nnoremap <expr> <Leader>: substitute( @:, '^\(\S\+\)', ':\1!', 'e')

「あーbang要るのか」って時にとりあえずバタッと押すとbang実行してくれるキュートな設定です。

" calcIt (コマンドモードなら<C-r>=あるので)
inoremap <expr> <C-z>= nr2char(10)..eval(getline('.'))

リマップ設定時、「<Leader>を使うにはちょっと(リマップ資源として)もったいないなぁ」というときに大文字Zを使っているのですが、その設定で使っている"nnoremap Z= :<C-u>put =eval(getline('.'))<CR>$"と直交させる形で「インサートモード中にカレント行を計算させるワンライナー」を使っています。

ここから先は個人的な使用頻度上している設定なのですが、再度確認する事項として……僕、技術系エンジニアではないのでvimで作るファイルはmarkdownやcsv等、平文としてみなせるものが圧倒的に多いです。そうなってくるとIME回りや文章の推敲をやりやすいように設定したいのです。ということで……

noremap <Leader>i :<C-u>set iminsert=2<CR>i
noremap <Leader>I :<C-u>set iminsert=2<CR>I
noremap <Leader>a :<C-u>set iminsert=2<CR>a
noremap <Leader>A :<C-u>set iminsert=2<CR>A
noremap <Leader>o :<C-u>set iminsert=2<CR>o
noremap <Leader>O :<C-u>set iminsert=2<CR>O
noremap <Leader>R :<C-u>set iminsert=2<CR>R
noremap <Leader>c :<C-u>set iminsert=2<CR>c
noremap <Leader>C :<C-u>set iminsert=2<CR>C
noremap <Leader>s :<C-u>set iminsert=2<CR>s
noremap <Leader>S :<C-u>set iminsert=2<CR>S

" ビジュアルモード対策が必要

vnoremap <Leader>i :<C-u>set iminsert=2<CR>gvi
vnoremap <Leader>I :<C-u>set iminsert=2<CR>gvI
vnoremap <Leader>a :<C-u>set iminsert=2<CR>gva
vnoremap <Leader>A :<C-u>set iminsert=2<CR>gvA
vnoremap <Leader>o :<C-u>set iminsert=2<CR>gvo
vnoremap <Leader>O :<C-u>set iminsert=2<CR>gvO
vnoremap <Leader>R :<C-u>set iminsert=2<CR>gvR
vnoremap <Leader>c :<C-u>set iminsert=2<CR>gvc
vnoremap <Leader>C :<C-u>set iminsert=2<CR>gvC
vnoremap <Leader>s :<C-u>set iminsert=2<CR>gvs
vnoremap <Leader>S :<C-u>set iminsert=2<CR>gvS

……こんな設定が増えることになります。ちなみに最近のIMEのトグルは"ctrl+space"にあたりがちですが、そもさctrl+space自体がキーマップ資源としてかなり貴重なので、検討の結果"ctrl+^"というかなりストロングスタイルな位置に収まりました。直交していないのがちょっと残念なところです……え、半角/全角キー?……ないですよ?なんでvim使いなのにusキー使ってないんです?

冗談はさておき、もう一つ日本語の校正用と、一応スクリプトは書くのでそれ用の設定をしています。

nnoremap <Leader><Space> i <Esc>

nnoremap <Leader>, i,<Esc>
nnoremap <Leader>. i.<Esc>
nnoremap <Leader>? i?<Esc>
nnoremap <Leader>! i!<Esc>

ノーマルモードから句点とスペースを入れるためのキーマップです。これに関してはもう一つ触れておきたいキーマップがあって、自作の関数で「カーソル上の文字が記号ならば全角/半角をトグル変換するスクリプト」があって、それも"<Leader>`"みたいなキーで行っています。これは「コンマを全角読点、ピリオドを全角句点にする」のような目的です。(逆も出来ます。)

とりあえず人にも薦めてみたい設定はそんなところです……ということで。久しぶりに文化的な活動が出来て僕は満足です、ご清聴ありがとうございました。Happy vimming.

この記事が気に入ったらサポートをしてみませんか?