ご無沙汰しております、有末です。 Vim Advent Calendar 2017 の 12/24 の記事となります。
皆様、本日は休日かつクリスマス・イブという最高の日ですね。 イブといえば、デコレーションが施された街に愛するパートナーと出かけ、楽しい時間を過ごすというのが一般的な日本人の過ごし方かと思います。
しかしながら、これはあくまでも「日本」という国での話です。
クリスマス・イブの「イブ」というワードは、英語圏では "EVE" と書かれます。
これは "Enhance Vim's Experience" の略語であり、本来クリスマス・イブとは Vim の生誕を祝福し、次年度以降に更に効率的に仕事をこなすために vimrc
を見直す日でした。
ということで、今年のイブは僕が利用している vimrc
から便利そうなやつをピックアップします。
皆様に置かれましても、本来のクリスマス・イブの意味を尊重し「あ、これ良いな」と思う設定があったら積極的に盗んで作業効率アップを目指しましょう。
なお、明日は平日です。この意味を十分に理解した上でいつ読み進めるかを判断しましょう。
最初の一歩
まずは最低限必要だと思われる設定を記載します。 以下を参考にしてください。
if has('vim_starting') set encoding=utf-8 scriptencoding utf-8 endif " ----------------------------------- " ここに追記していく " ----------------------------------- " シンタックスハイライトを有効化 " ファイルタイプ別インデント・プラグインの有効化 syntax on filetype indent plugin on " 任意ディレクトリに存在する vimrc による悪意を持ったコマンド実行を防ぐ " ~/.vimrc や ~/.config/nvim/init.vim の一番最後には必ず書くのがお薦め set secure " このファイルを開いた際のルールを以下で定義する " 詳細は ':help modeline' を参照 " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker
上記を ~/.vimrc
に記載後 Vim を再起動してください。
リロード設定
今後 ~/.vimrc
はバリバリ修正を加えていきます。
その為以下のように簡単に編集・適用ができるようにマッピングしておきましょう。
" <F1> で ~/.vimrc を表示 (Neovim の場合は ~/.config/nvim/init.vim) " <F1> はデフォルトで `:help` にマッピングされているが `:help` と打てば良いため潰す if has('nvim') nnoremap <silent> <F1> :<C-u>e ~/.config/nvim/init.vim<CR> else nnoremap <silent> <F1> :<C-u>e ~/.vimrc<CR> endif " <F10> で編集中の Vim script をソース if !exists('*s:source_script') " ~/.vimrc をソースすると関数実行中に関数の上書きを行うことになりエラーとなるため " 'function!' による強制上書きではなく if によるガードを行っている function s:source_script(path) abort let path = expand(a:path) if !filereadable(path) return endif execute 'source' fnameescape(path) echomsg printf( \ '"%s" has sourced (%s)', \ simplify(fnamemodify(path, ':~:.')), \ strftime('%c'), \) endfunction endif nnoremap <silent> <F10> :<C-u>call <SID>source_script('%')<CR>
上記を ~/.vimrc
に記載後 Vim を再起動してください(マッピング系の部分に追記すると良いでしょう)。
以後は <F1>
を押すと ~/.vimrc
が表示され、修正したあとは <F10>
を押すだけでリロードが可能です。
True Color での表示
set termguicolors
を設定すれば True Color での表示が可能ですが、ターミナル自体が True Color に対応している必要があります。
また set termguicolors
は起動時に行う必要があるため vimrc の先頭 に記載する必要があります。
if has('vim_starting') " Vim のエンコーディングを utf-8 に set encoding=utf-8 scriptencoding utf-8 " 利用可能な場合は true color を有効化する if !has('gui_running') \ && exists('&termguicolors') \ && $COLORTERM ==# 'truecolor' " tmux 等でも強制的に termguicolors を有効化するための設定 (Neovim では不要) " https://medium.com/@dubistkomisch/how-to-actually-get-italics-and-true-colour-to-work-in-iterm-tmux-vim-9ebe55ebc2be if !has('nvim') let &t_8f = "\e[38;2;%lu;%lu;%lum" let &t_8b = "\e[48;2;%lu;%lu;%lum" endif set termguicolors " use truecolor in term endif endif
なお上記で利用している $COLORTERM
環境変数は一般的に TrueColor に対応したターミナルが自動的に設定する環境変数です(True Colour (16 million colours))。
そのため $COLORTERM
が存在していなくても TrueColor に対応しているターミナルがあるかもしれません。
Vim から見える PATH を正確に
Vim から見える $PATH
は Vim を起動した環境に依存します。
そのためターミナルから起動した Vim だと使えるけど GVim からは使えない等の現象が発生します。
これを治すために、利用する $PATH
は以下のように明示的に宣言してしまいましょう。
let s:is_windows = has('win32') || has('win64') function! s:configure_path(name, pathlist) abort let path_separator = s:is_windows ? ';' : ':' let pathlist = split(expand(a:name), path_separator) for path in map(filter(a:pathlist, '!empty(v:val)'), 'expand(v:val)') if isdirectory(path) && index(pathlist, path) == -1 call insert(pathlist, path, 0) endif endfor execute printf('let %s = join(pathlist, ''%s'')', a:name, path_separator) endfunction " 以下 macOS の自分が使っているやつ call s:configure_path('$PATH', [ \ '~/.cache/dein/repos/github.com/thinca/vim-themis/bin', \ '~/.cabal/bin', \ '~/.zplug/bin', \ '~/.anyenv/envs/pyenv/bin', \ '~/.anyenv/envs/plenv/bin', \ '~/.anyenv/envs/rbenv/bin', \ '~/.anyenv/envs/ndenv/bin', \ '~/.anyenv/envs/pyenv/shims', \ '~/.anyenv/envs/plenv/shims', \ '~/.anyenv/envs/rbenv/shims', \ '~/.anyenv/envs/ndenv/shims', \ '/usr/local/bin', \ '/usr/local/texlive/2017basic/bin/x86_64-darwin', \]) call s:configure_path('$MANPATH', [ \ '/usr/local/share/man/', \ '/usr/share/man/', \ '/Applications/Xcode.app/Contents/Developer/usr/share/man', \ '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/share/man', \])
上記のように関数を噛ませることで、すでに登録されているパスは重複登録しないようにできます。
利用する Python を固定する(Neovim 限定)
Python の補完に davidhalter/jedi-vim やzchee/deoplete-jedi を利用している場合は以下のように Neovim が参照する Python を明治指定することで、開発に用いている Python それぞれに neovim
パッケージや jedi
パッケージを入れなくても良くなり便利です。
function! s:pick_executable(pathspecs) abort for pathspec in filter(a:pathspecs, '!empty(v:val)') for path in reverse(glob(pathspec, 0, 1)) if executable(path) return path endif endfor endfor return '' endfunction if has('nvim') let g:python_host_prog = s:pick_executable([ \ '/usr/local/bin/python2', \ '/usr/bin/python2', \ '/bin/python2', \]) let g:python3_host_prog = s:pick_executable([ \ '/usr/local/bin/python3', \ '/usr/bin/python3', \ '/bin/python3', \]) endif
上記では関数をかませることで、幾つかの候補の中から最初に見つかった Python を利用するようにしています。
クリップボード連携をデフォルトに
Vim はデフォルトではシステムのクリップボードと連携しません。 システムのクリップボードと連携するには
"*y システムのクリップボードにコピー (Linux の場合は "+y) "*p システムのクリップボードから貼り付け(Linux の場合は "+p)
と打つ必要があり、若干面倒です。
以下の設定を追記することで y
や p
がデフォルトでシステムのクリップボードと連携します。
" システムのクリップボードを利用する " OS 種により利用するべき値が違うため分岐させている " - unnamed : 'selection' in X11; clipboard in Mac OS X and Windows " - unnamedplus : 'clipboard' in X11, Mac OS X, and Windows (but yank) if has('win32') || has('win64') || has('mac') set clipboard=unnamed else set clipboard=unnamed,unnamedplus endif
スペースを有効活用する
Vim のノーマルモードにおいてスペースキーは l
と同じ機能を持つだけなのでとても無駄です。
親指という超強力な指をもっと有効活用するために <Leader>
をスペースキーにマッピングしてしまいましょう。
またファイルタイププラグイン等で利用される <LocalLeader>
には余った \
を割り当てると良さそうです。
noremap <Leader> <Nop> noremap <LocalLeader> <Nop> let g:mapleader = "\<Space>" let g:maplocalleader = '\'
上記により、以下のようにプラグインマッピングを定義できます。
" gina.vim nnoremap <Leader>aa :<C-u>Gina status<CR> nnoremap <Leader>ac :<C-u>Gina commit<CR> " denite.nvim nnoremap <Leader>df :<C-u>Denite file<CR> nnoremap <Leader>db :<C-u>Denite buffer<CR> " jedi.vim function! s:configure_python() abort nnoremap <buffer> <LocalLeader>r :<C-u>call jedi#rename()<CR> endfunction autocmd MyAutoCmd FileType python call s:configure_python()
上記の <Leader>
は g:mapleader
で指定されているスペースに置き換わるので、利用時は <Space>aa
や <Space>df
のように利用できます。
また <LocalLeader>
は g:maplocalleader
で指定されている \
に置き換わるので、ファイルタイプが Python なバッファでは \r
のように利用できます。
Quickfix/LocationList を簡単に表示・非表示する
以下の設定により Quickfix や LocationList の表示を Q
と L
でトグル出来ます。
function! s:toggle_qf() abort let nwin = winnr('$') cclose if nwin == winnr('$') botright copen endif endfunction nnoremap <silent> <Plug>(my-toggle-quickfix) \ :<C-u>call <SID>toggle_qf()<CR> nmap Q <Plug>(my-toggle-quickfix) function! s:toggle_ll() abort try let nwin = winnr('$') lclose if nwin == winnr('$') botright lopen endif catch /^Vim\%((\a\+)\)\=:E776/ echohl WarningMsg redraw | echo 'No location list' echohl None endtry endfunction nnoremap <silent> <Plug>(my-toggle-locationlist) \ :<C-u>call <SID>toggle_ll()<CR> nmap L <Plug>(my-toggle-locationlist)
参考: http://d.hatena.ne.jp/kuhukuhun/20090119/1232343733
一時的に現在のバッファを最大化する
以下により <C-w>z
を押すことで現在のバッファを一時的に最大化します。
再度 <C-w>z
を押すともとに戻ります。
多数のバッファを分割で開いている際に、一時的に現在のバッファにフォーカスしたい場合に利用できます。
function! s:toggle_window_zoom() abort if exists('t:zoom_winrestcmd') execute t:zoom_winrestcmd unlet t:zoom_winrestcmd else let t:zoom_winrestcmd = winrestcmd() resize vertical resize endif endfunction nnoremap <silent> <Plug>(my-zoom-window) \ :<C-u>call <SID>toggle_window_zoom()<CR> nmap <C-w>z <Plug>(my-zoom-window) nmap <C-w><C-z> <Plug>(my-zoom-window)
なお vim-scripts/ZoomWin というのがあるようです。
ファイルタイプの再アサイン
空のファイルを新規に作成したときなど、ファイルタイプの自動推定に失敗することはよくあります。 以下を記載することで、ファイルタイプの自動推定に失敗した場合でも保存時に再度ファイル推定を行うようになります。
" 一括リセットが可能なように MyAutoCmd グループで定義する autocmd MyAutoCmd BufWritePost * \ if &filetype ==# '' && exists('b:ftdetect') | \ unlet! b:ftdetect | \ filetype detect | \ endif
なお autocmd は宣言により追加されるため vimrc をリロードした際に同じ autocmd が何個も登録されてしまいます。
これを防ぐために vimrc の最初の方で以下のようにして MyAutoCmd
に属する autocmd をすべてリセットしましょう。
" 利用しているオートコマンドはすべて MyAutoCmd に所属させているためここですべて削除する。 " これは vimrc をリロードした際にオートコマンドが重複して登録されるのを防ぐために必要。 augroup MyAutoCmd autocmd! * augroup END
おわりに
今回紹介していない色々な設定が lambdalisue/rook/blob/master/home/.config/nvim/init.vim に記載されているので、さらに盗みたい方は参照してください。