読者です 読者をやめる 読者になる 読者になる

Λlisue's blog

つれづれなるままに更新されないブログ

Vimを最強のPython開発環境にする2

f:id:lambdalisue:20130623070105p:plain

本気でPythonをやりたいならあわせて読みたいえ?君せっかく Python のバージョン管理に pyenv 使ってるのに Vim の補完はシステムライブラリ参照してるの?

  • 2013-06-23 21:30 おしりに追記しました
  • 2013-06-24 10:00 設定等微修正しました
  • 2013-06-24 15:20 quickrunの設定を修正しました
  • 2013-07-03 14:30 間違い等を修正しました

様々な開発環境を試してきましたが、結局Vimに落ち着いてしまっているAlisueです、どうも。 Vimを最強のPython IDEにするを書いてからかれこれ二年ほどが経ちます。 二年もあると新しいVimプラグインが増えるなどし、先の記事内容では最強ではなくなってしまいました。なのでこの辺でもう一度現在の最強をまとめてみたいと思います。

基本方針

  • プラグイン関係はすべてNeoBundleで管理
  • プラグインは可能な限り遅延ロードを使うことでVimを高速化
  • 開発環境として遜色がないように可能な限り自動化
  • メモなどを取るのに便利なMarkdown (Pandoc)を手軽に使えるように

前提条件

下記にあげるプログラムが使用可能な状態になっていることが条件です。 なお例の如くWindowsは対象としていないので、Windowsを使用している人はGoogle先生と一緒にがんばってください。

必須設定

本記事で使用しているマクロなどはすべて'MyAutoCmd'というグループに属しているのでそれの 初期化(リセット)処理を.vimrcの先頭に書いてください。

" release autogroup in MyAutoCmd
augroup MyAutoCmd
  autocmd!
augroup END

推奨設定

以下は自分が使用している.vimrcから持ってきた推奨設定です。説明を書いたので良さそうなものを選んで設定してください。

検索関係

set ignorecase          " 大文字小文字を区別しない
set smartcase           " 検索文字に大文字がある場合は大文字小文字を区別
set incsearch           " インクリメンタルサーチ
set hlsearch            " 検索マッチテキストをハイライト (2013-07-03 14:30 修正)

" バックスラッシュやクエスチョンを状況に合わせ自動的にエスケープ
cnoremap <expr> / getcmdtype() == '/' ? '\/' : '/'
cnoremap <expr> ? getcmdtype() == '?' ? '\?' : '?'

編集関係

set shiftround          " '<'や'>'でインデントする際に'shiftwidth'の倍数に丸める
set infercase           " 補完時に大文字小文字を区別しない
set virtualedit=all     " カーソルを文字が存在しない部分でも動けるようにする
set hidden              " バッファを閉じる代わりに隠す(Undo履歴を残すため)
set switchbuf=useopen   " 新しく開く代わりにすでに開いてあるバッファを開く
set showmatch           " 対応する括弧などをハイライト表示する
set matchtime=3         " 対応括弧のハイライト表示を3秒にする

" 対応括弧に'<'と'>'のペアを追加
set matchpairs& matchpairs+=<:>

" バックスペースでなんでも消せるようにする
set backspace=indent,eol,start

" クリップボードをデフォルトのレジスタとして指定。後にYankRingを使うので
" 'unnamedplus'が存在しているかどうかで設定を分ける必要がある
if has('unnamedplus')
    " set clipboard& clipboard+=unnamedplus " 2013-07-03 14:30 unnamed 追加
    set clipboard& clipboard+=unnamedplus,unnamed 
else
    " set clipboard& clipboard+=unnamed,autoselect 2013-06-24 10:00 autoselect 削除
    set clipboard& clipboard+=unnamed
endif

" Swapファイル?Backupファイル?前時代的すぎ
" なので全て無効化する
set nowritebackup
set nobackup
set noswapfile

表示関係

set list                " 不可視文字の可視化
set number              " 行番号の表示
set wrap                " 長いテキストの折り返し
set textwidth=0         " 自動的に改行が入るのを無効化
set colorcolumn=80      " その代わり80文字目にラインを入れる

" 前時代的スクリーンベルを無効化
set t_vb=
set novisualbell

" デフォルト不可視文字は美しくないのでUnicodeで綺麗に
set listchars=tab:»-,trail:-,extends:»,precedes:«,nbsp:%,eol:

マクロおよびキー設定

" 入力モード中に素早くjjと入力した場合はESCとみなす
inoremap jj <Esc>

" ESCを二回押すことでハイライトを消す
nmap <silent> <Esc><Esc> :nohlsearch<CR>

" カーソル下の単語を * で検索
vnoremap <silent> * "vy/\V<C-r>=substitute(escape(@v, '\/'), "\n", '\\n', 'g')<CR><CR>

" 検索後にジャンプした際に検索単語を画面中央に持ってくる
nnoremap n nzz
nnoremap N Nzz
nnoremap * *zz
nnoremap # #zz
nnoremap g* g*zz
nnoremap g# g#zz

" j, k による移動を折り返されたテキストでも自然に振る舞うように変更
nnoremap j gj
nnoremap k gk

" vを二回で行末まで選択
vnoremap v $h

" TABにて対応ペアにジャンプ
nnoremap <Tab> %
vnoremap <Tab> %

" Ctrl + hjkl でウィンドウ間を移動
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l

" Shift + 矢印でウィンドウサイズを変更
nnoremap <S-Left>  <C-w><<CR>
nnoremap <S-Right> <C-w>><CR>
nnoremap <S-Up>    <C-w>-<CR>
nnoremap <S-Down>  <C-w>+<CR>

" T + ? で各種設定をトグル
nnoremap [toggle] <Nop>
nmap T [toggle]
nnoremap <silent> [toggle]s :setl spell!<CR>:setl spell?<CR>
nnoremap <silent> [toggle]l :setl list!<CR>:setl list?<CR>
nnoremap <silent> [toggle]t :setl expandtab!<CR>:setl expandtab?<CR>
nnoremap <silent> [toggle]w :setl wrap!<CR>:setl wrap?<CR>

" make, grep などのコマンド後に自動的にQuickFixを開く
autocmd MyAutoCmd QuickfixCmdPost make,grep,grepadd,vimgrep copen

" QuickFixおよびHelpでは q でバッファを閉じる
autocmd MyAutoCmd FileType help,qf nnoremap <buffer> q <C-w>c

" w!! でスーパーユーザーとして保存(sudoが使える環境限定)
cmap w!! w !sudo tee > /dev/null %

" :e などでファイルを開く際にフォルダが存在しない場合は自動作成
function! s:mkdir(dir, force)
  if !isdirectory(a:dir) && (a:force ||
        \ input(printf('"%s" does not exist. Create? [y/N]', a:dir)) =~? '^y\%[es]$')
    call mkdir(iconv(a:dir, &encoding, &termencoding), 'p')
  endif
endfunction
autocmd MyAutoCmd BufWritePre * call s:mkdir(expand('<afile>:p:h'), v:cmdbang)

" vim 起動時のみカレントディレクトリを開いたファイルの親ディレクトリに指定
autocmd MyAutoCmd VimEnter * call s:ChangeCurrentDir('', '')
function! s:ChangeCurrentDir(directory, bang)
    if a:directory == ''
        lcd %:p:h
    else
        execute 'lcd' . a:directory
    endif

    if a:bang == ''
        pwd
    endif
endfunction

" ~/.vimrc.localが存在する場合のみ設定を読み込む
let s:local_vimrc = expand('~/.vimrc.local')
if filereadable(s:local_vimrc)
    execute 'source ' . s:local_vimrc
endif

NeoBundleによるプラグイン管理

昨今のVimプラグイン管理ツール乱立に終止符を打つであろうNeoBundleを使用します。 NeoBundleのプラグイン管理は基本的に

  1. NeoBundle 'YankRing'のように使用したいプラグイン.vimrcで指定
  2. :NeoBundleInstallで先に指定したプラグインをダウンロード指定(基本的に起動時に自動呼び出し)
  3. プラグインは特定のディレクトリ(通常は~/.vim/bundle)にダウンロードされる
  4. NeoBundleが指定されたプラグインのダウンロード先をruntimepathに自動的に加えてくれる

という流れです。したがって一時期流行ったPathogenとは異なりユーザーが行うべきことは使用したいプラグインをリストアップするだけです。 なお、この基本コンセプトは最近では最も有名なVundleというプラグインと同じなのですが、下記の点でNeoBundleはVundleより優れています。

  • SubversionなどのGit以外のバージョン管理システムへの対応
  • vimprocを用いた非同期アップデート
  • リビジョンロック・ブランチロック
  • 依存関係指定
  • 遅延ロード
  • 作成者が暗黒美夢王こと@Shougoさん(重要)

なかでも遅延ロードができる点が非常に大きくVimの高速化に貢献するため迷わずNeoBundleを選びましょう。

NeoBundleの簡単な使い方

最小の設定および高度な使用方法などはNeoBundleのREADMEなどを見るとして、ここでは実用的な設定を見ていきます。 下記に汎用的なNeoBundleの設定を書きました。なお" (ryの部分に欲しいプラグインを羅列します。

let s:noplugin = 0
let s:bundle_root = expand('~/.vim/bundle')
let s:neobundle_root = s:bundle_root . '/neobundle.vim'
if !isdirectory(s:neobundle_root) || v:version < 702
    " NeoBundleが存在しない、もしくはVimのバージョンが古い場合はプラグインを一切
    " 読み込まない
    let s:noplugin = 1
else
    " NeoBundleを'runtimepath'に追加し初期化を行う
    if has('vim_starting')
        execute "set runtimepath+=" . s:neobundle_root
    endif
    call neobundle#rc(s:bundle_root)

    " NeoBundle自身をNeoBundleで管理させる
    NeoBundleFetch 'Shougo/neobundle.vim'

    " 非同期通信を可能にする
    " 'build'が指定されているのでインストール時に自動的に
    " 指定されたコマンドが実行され vimproc がコンパイルされる
    NeoBundle "Shougo/vimproc", {
        \ "build": {
        \   "windows"   : "make -f make_mingw32.mak",
        \   "cygwin"    : "make -f make_cygwin.mak",
        \   "mac"       : "make -f make_mac.mak",
        \   "unix"      : "make -f make_unix.mak",
        \ }}

    " (ry

    " インストールされていないプラグインのチェックおよびダウンロード
    NeoBundleCheck
endif

" ファイルタイププラグインおよびインデントを有効化
" これはNeoBundleによる処理が終了したあとに呼ばなければならない
filetype plugin indent on

hooks.on_sourceによるロード時設定

特に下記で紹介する遅延ロードの際に力を発揮しますがNeoBundleではプラグインロード時に 特定の関数を実行、すなわち特定のプラグイン専用の設定コードを実行させることができます。

" 次に説明するがInsertモードに入るまではneocompleteはロードされない
NeoBundleLazy 'Shougo/neocomplete.vim', {
    \ "autoload": {"insert": 1}}
" neocompleteのhooksを取得
let s:hooks = neobundle#get_hooks("neocomplete.vim")
" neocomplete用の設定関数を定義。下記関数はneocompleteロード時に実行される
function! s:hooks.on_source(bundle)
    let g:acp_enableAtStartup = 0
    let g:neocomplete#enable_smart_case = 1
    " NeoCompleteを有効化
    NeoCompleteEnable
endfunction

NeoBundleLazyによる遅延ロード

NeoBundleでは下記のようにすることでプラグインを遅延ロードすることができます。

" Insertモードに入るまでロードしない

NeoBundleLazy 'Shougo/neosnippet.vim', {
    \ "autoload": {"insert": 1}}
" 'GundoToggle'が呼ばれるまでロードしない
NeoBundleLazy 'sjl/gundo.vim', {
    \ "autoload": {"commands": ["GundoToggle"]}}
" '<Plug>TaskList'というマッピングが呼ばれるまでロードしない
NeoBundleLazy 'vim-scripts/TaskList.vim', {
    \ "autoload": {"mappings": ['<Plug>TaskList']}}
" HTMLが開かれるまでロードしない
NeoBundleLazy 'mattn/zencoding-vim', {
    \ "autoload": {"filetypes": ['html']}}

先に紹介したhooks.on_sourceによるロード時設定を組み合わせることで完全な遅延ロードができます。

ファイル管理関係

vim-templateによるテンプレートファイルの使用

基本的にプログラミングを行う場合ファイル先頭部分はお決まりの表現、Pythonで言えば文字コードの指定、シェルスクリプトならシェバング(#!から始まるインタプリタ指定行)で始まることが多いです。 これらの決まり文句を毎度打つのも面倒なのでテンプレートを使用します。僕のおすすめはvim-template です。

vim-templateは数あるVim用テンプレートプラグインのなかでも極めてシンプルな部類に入ります。 結構適当な使い方で思い通りの挙動を示すので扱いやすいです。 詳しくは作者の紹介記事をどうぞ。 僕の.vimrcでは以下のように設定しています。

NeoBundle "thinca/vim-template"
" テンプレート中に含まれる特定文字列を置き換える
autocmd MyAutoCmd User plugin-template-loaded call s:template_keywords()
function! s:template_keywords()
    silent! %s/<+DATE+>/\=strftime('%Y-%m-%d')/g
    silent! %s/<+FILENAME+>/\=expand('%:r')/g
endfunction
" テンプレート中に含まれる'<+CURSOR+>'にカーソルを移動
autocmd MyAutoCmd User plugin-template-loaded
    \   if search('<+CURSOR+>')
    \ |   silent! execute 'normal! "_da>'
    \ | endif

テンプレートは下記のように記載し~/.vim/templateの中にtemplate.pyのように保存しておきます。

#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
#
# Author:   lambdalisue
# URL:      http://hashnote.net/
# License:  MIT License
# Created:  <+DATE+>
#
<+CURSOR+>

Unite.vimによる総合管理

f:id:lambdalisue:20130623070332p:plain

正直僕は全くといっていいほど使いこなせていないのですがUnite.vim というこれまたShougoさん作のコマンドラインランチャーちっくなナイスなプラグインがあります。

ノウハウなどここで紹介出来ればいいのでしょうが、ほとんど使えていないので紹介は他の方にお任せいたします。

いつか使えるようになったらここの記事をアップグレードしたい。ちなみに現在の僕の.vimrcは以下のようになっています。 なお単一ファイルを少し編集したい場合などはUnite.vimが不要なため遅延ロードを行なっています。

NeoBundleLazy "Shougo/unite.vim", {
      \ "autoload": {
      \   "commands": ["Unite", "UniteWithBufferDir"]
      \ }}
NeoBundleLazy 'h1mesuke/unite-outline', {
      \ "autoload": {
      \   "unite_sources": ["outline"],
      \ }}
nnoremap [unite] <Nop>
nmap U [unite]
nnoremap <silent> [unite]f :<C-u>UniteWithBufferDir -buffer-name=files file<CR>
nnoremap <silent> [unite]b :<C-u>Unite buffer<CR>
nnoremap <silent> [unite]r :<C-u>Unite register<CR>
nnoremap <silent> [unite]m :<C-u>Unite file_mru<CR>
nnoremap <silent> [unite]c :<C-u>Unite bookmark<CR>
nnoremap <silent> [unite]o :<C-u>Unite outline<CR>
nnoremap <silent> [unite]t :<C-u>Unite tab<CR>
nnoremap <silent> [unite]w :<C-u>Unite window<CR>
let s:hooks = neobundle#get_hooks("unite.vim")
function! s:hooks.on_source(bundle)
  " start unite in insert mode
  let g:unite_enable_start_insert = 1
  " use vimfiler to open directory
  call unite#custom_default_action("source/bookmark/directory", "vimfiler")
  call unite#custom_default_action("directory", "vimfiler")
  call unite#custom_default_action("directory_mru", "vimfiler")
  autocmd MyAutoCmd FileType unite call s:unite_settings()
  function! s:unite_settings()
    imap <buffer> <Esc><Esc> <Plug>(unite_exit)
    nmap <buffer> <Esc> <Plug>(unite_exit)
    nmap <buffer> <C-n> <Plug>(unite_select_next_line)
    nmap <buffer> <C-p> <Plug>(unite_select_previous_line)
  endfunction
endfunction

Vimfilerによる開発環境実装

f:id:lambdalisue:20130623070518p:plain

どんな開発環境にもたいてい左側にはファイルエクスプローラーが存在しています。 僕が前に書いたVimを最強のPython IDEにするではThe NERD Treeを利用していましたが、今はこれまたShougoさん作のVimfilerを使用しています。

Vimfilerに乗り換えた理由としては下記のようなものが挙げられます。

  • ファイルの作成・コピー・移動・削除などがわかりやすい
  • わかりやすいリネームコマンド
  • 2画面モードによる移動・コピー作業
  • 非常に高い拡張性
  • 新しいバージョンからThe NERD Treeちっくな起動が可能になった

なおVimfilerではThe NERD Treeとはキーマッピングが異なるので新たに覚え直す必要があります。 最低限覚える必用があるのは以下です。

キーマッピング コマンド
a アクションを選択
l フォルダを開く
h フォルダを閉じる
t フォルダを開く・閉じる
T フォルダを再帰的に開く・閉じる
Backspace 親フォルダに移動する
Enter フォルダに入る
e ファイルを開く
E 新しいウィンドウでファイルを開く
. 隠しファイル(ドットファイル)表示
I ディレクトリを入力し移動
yy フルパスをヤンク(コピー)する
ge システムのファイラーでフォルダを開く
gf ファイルを検索 (find)
gg ファイルをフィルタリング (grep)
x システムの関連付けでファイルを開く

また下記コマンドを覚えることでVimfiler上でファイルの作成・編集・削除ができます。 なおこれらの破壊的コマンドに関してはgsと入力しセーフモードを抜けないと実行できないようになっています

キーマッピング コマンド
Cc クリップボードにファイルをコピー
Cm クリップボードにファイルを移動
Cp クリップボードからファイルを貼り付け
N 新規ファイルを作成
c ファイルをコピー
m ファイルを移動
r ファイルをリネーム
d ファイルを削除

下記に僕の設定を記載します。なお僕はCtrl + lをウィンドウ移動に割り当てているためデフォルトのキーマッピングを上書きしています。 また単一ファイルを少し編集したい場合などはVimfilerが不要なため遅延ロードを行なっています。

NeoBundleLazy "Shougo/vimfiler", {
      \ "depends": ["Shougo/unite.vim"],
      \ "autoload": {
      \   "commands": ["VimFilerTab", "VimFiler", "VimFilerExplorer"],
      \   "mappings": ['<Plug>(vimfiler_switch)'],
      \   "explorer": 1,
      \ }}
nnoremap <Leader>e :VimFilerExplorer<CR>
" close vimfiler automatically when there are only vimfiler open
autocmd MyAutoCmd BufEnter * if (winnr('$') == 1 && &filetype ==# 'vimfiler') | q | endif
let s:hooks = neobundle#get_hooks("vimfiler")
function! s:hooks.on_source(bundle)
  let g:vimfiler_as_default_explorer = 1
  let g:vimfiler_enable_auto_cd = 1
  
  " .から始まるファイルおよび.pycで終わるファイルを不可視パターンに
  " 2013-08-14 追記
  let g:vimfiler_ignore_pattern = "\%(^\..*\|\.pyc$\)"

  " vimfiler specific key mappings
  autocmd MyAutoCmd FileType vimfiler call s:vimfiler_settings()
  function! s:vimfiler_settings()
    " ^^ to go up
    nmap <buffer> ^^ <Plug>(vimfiler_switch_to_parent_directory)
    " use R to refresh
    nmap <buffer> R <Plug>(vimfiler_redraw_screen)
    " overwrite C-l
    nmap <buffer> <C-l> <C-w>l
  endfunction
endfunction

Git関係の設定

f:id:lambdalisue:20130623070522p:plain

Git関係は下記プラグインにて設定しています。それぞれの使い方紹介は他の方にお任せいたします。

それぞれの設定は下記のとおりです。まだバリバリとは使ってない。

NeoBundleLazy "mattn/gist-vim", {
      \ "depends": ["mattn/webapi-vim"],
      \ "autoload": {
      \   "commands": ["Gist"],
      \ }}

" vim-fugitiveは'autocmd'多用してるっぽくて遅延ロード不可
NeoBundle "tpope/vim-fugitive"
NeoBundleLazy "gregsexton/gitv", {
      \ "depends": ["tpope/vim-fugitive"],
      \ "autoload": {
      \   "commands": ["Gitv"],
      \ }}

テキスト編集関係

三種の神器

テキスト編集補佐といえば以下3つ。開発環境を謳うためには必須です。

なおこれらに関しては下記のように指定しています。

NeoBundle 'tpope/vim-surround'
NeoBundle 'vim-scripts/Align'
NeoBundle 'vim-scripts/YankRing.vim'

では、それぞれの使い方を簡単に見ていきます。

vim-surround

vim-surroundはその名の通り囲んでいるものに対して操作をするプラグインです。下記のような機能があります。なおカーソルはWorldのoの位置にあると仮定します。

コマンド 実行前 実行後
ds" "Hello World" Hello world
ds( (Hello World) Hello World
ds) (Hello World) Hello World
dst <p>Hello World</p> Hello World
cs"' "Hello World" 'Hello World'
cs([ (Hello World) [ Hello World ]
cs(] (Hello World) [Hello World]
cs)[ (Hello World) [ Hello World ]
cs)] (Hello World) [Hello World]
cst<b> <p>Hello World</p> <b>Hello World</b>
ys$" Hello World Now Hello W"orld Now"
ysw' Hello World Now Hello W'orld' Now
ysiw) Hello World Now Hello (World) Now
yss" Hello World Now "Hello World Now"

Align

テキスト整形用プラグインです。基本的には:Align 区切り文字という形で指定します。 ただし空白文字(スペース・タブ)の場合は<Leader>tspおよび<Leader>tabを使用します。

非常に詳しく説明が書かれたページがあるので詳細はそちらを参照してください。

YankRing

'p'によりペーストを実行したあとCtrl-pで古い履歴、Ctrl-nで新しい履歴へと貼りつけたテキストの置き換えが起こります。

neocompleteによる気持ちがいい補完

f:id:lambdalisue:20130623070630p:plain

これまたShougoさん作のneocompleteを補完システムとして利用します。 neocompleteは世界的にも絶大な人気を誇ったneocomplcacheの後継機だそうです。 VimLua対応している必要がありますが、速度改善が図られたようなのでこれを使用します。

neocompleteに関しての説明をできるほど使いこなせていないので、これに関しても他の方にお任せいたします。 というかneocompleteは入れるだけで快適になります。僕は設定等はほとんどデフォルト状態です(下記参照)。 なおneocompleteは使用条件が割りと厳しい(+luaかつVim > 7.3.825)なので条件に当てはまらない場合は neocomplcacheを使うように設定しています(2013-07-08 追記: 再度確認したところ今現在の条件は7.3.885以上になっていました)。 またVimをless的な使い方(ビュワーとして使用)をすることもあるのでインサートモードになるまで読み込まないようにしています。

" if has('lua') && v:version > 703 && has('patch825') 2013-07-03 14:30 > から >= に修正
" if has('lua') && v:version >= 703 && has('patch825') 2013-07-08 10:00 必要バージョンが885にアップデートされていました
if has('lua') && v:version >= 703 && has('patch885')
    NeoBundleLazy "Shougo/neocomplete.vim", {
        \ "autoload": {
        \   "insert": 1,
        \ }}
    " 2013-07-03 14:30 NeoComplCacheに合わせた
    let g:neocomplete#enable_at_startup = 1
    let s:hooks = neobundle#get_hooks("neocomplete.vim")
    function! s:hooks.on_source(bundle)
        let g:acp_enableAtStartup = 0
        let g:neocomplet#enable_smart_case = 1
        " NeoCompleteを有効化
        " NeoCompleteEnable
    endfunction
else
    NeoBundleLazy "Shougo/neocomplcache.vim", {
        \ "autoload": {
        \   "insert": 1,
        \ }}
    " 2013-07-03 14:30 原因不明だがNeoComplCacheEnableコマンドが見つからないので変更
    let g:neocomplcache_enable_at_startup = 1
    let s:hooks = neobundle#get_hooks("neocomplcache.vim")
    function! s:hooks.on_source(bundle)
        let g:acp_enableAtStartup = 0
        let g:neocomplcache_enable_smart_case = 1
        " NeoComplCacheを有効化
        " NeoComplCacheEnable 
    endfunction
endif

neosnippetによるコード入力の簡略化

これはこの記事を書くに当たり設定ファイルを見直す段階で取り入れたので正直利便性はまだ未知数。 ただスニペット系は大量にコードを書く際には必須とも言える機能なので間違いなく便利だろう。Shougoさん作だし。

NeoBundleLazy "Shougo/neosnippet.vim", {
      \ "depends": ["honza/vim-snippets"],
      \ "autoload": {
      \   "insert": 1,
      \ }}
let s:hooks = neobundle#get_hooks("neosnippet.vim")
function! s:hooks.on_source(bundle)
  " Plugin key-mappings.
  imap <C-k>     <Plug>(neosnippet_expand_or_jump)
  smap <C-k>     <Plug>(neosnippet_expand_or_jump)
  xmap <C-k>     <Plug>(neosnippet_expand_target)
  " SuperTab like snippets behavior.
  imap <expr><TAB> neosnippet#expandable_or_jumpable() ?
  \ "\<Plug>(neosnippet_expand_or_jump)"
  \: pumvisible() ? "\<C-n>" : "\<TAB>"
  smap <expr><TAB> neosnippet#expandable_or_jumpable() ?
  \ "\<Plug>(neosnippet_expand_or_jump)"
  \: "\<TAB>"
  " For snippet_complete marker.
  if has('conceal')
    set conceallevel=2 concealcursor=i
  endif
  " Enable snipMate compatibility feature.
  let g:neosnippet#enable_snipmate_compatibility = 1
  " Tell Neosnippet about the other snippets
  let g:neosnippet#snippets_directory=s:bundle_root . '/vim-snippets/snippets'
endfunction

ちなみにsnipMate.vim形式のスニペット集を読み込んで使用しています。

vim-indent-guidesによるインデントの可視化

f:id:lambdalisue:20130623070648p:plain

vim-indent-guidesを用いることで上記写真のようにインデントレベルを可視化することができます。 下記のように設定してください。

NeoBundle "nathanaelkane/vim-indent-guides"
" let g:indent_guides_enable_on_vim_startup = 1 2013-06-24 10:00 削除
let s:hooks = neobundle#get_hooks("vim-indent-guides")
function! s:hooks.on_source(bundle)
  let g:indent_guides_guide_size = 1
  IndentGuidesEnable " 2013-06-24 10:00 追記
endfunction

Gundo.vimによる高機能アンドゥ実装

f:id:lambdalisue:20130623070701p:plain

普段はあまり恩恵を受けていませんが、実はVimの元に戻す・やり直す機能は他のエディタとは比べ物にならないくらい高機能です。 どう高機能か?に関してはgundo.vimが超便利なのとvimのアンドゥツリーについてに図解でわかりやすく乗っているのでそちらを参照してください。 というかリンク先にGundo.vimがいかに素晴らしいかも書いてあるので見てください。説明は他の人に任せて、下記に僕の設定を載せます。

NeoBundleLazy "sjl/gundo.vim", {
      \ "autoload": {
      \   "commands": ['GundoToggle'],
      \}}
nnoremap <Leader>g :GundoToggle<CR>

これさえあれば(バッファを開いている間は)簡易的なバージョン管理になるのでバージョン管理する程でもない修正などに重宝します。

TaskList.vimによるTODO管理

f:id:lambdalisue:20130623070713p:plain

TaskList.vimEclipseなどに付いているTODOをVimでも有効化するためのプラグインです。

下記に僕の設定を記載します。

NeoBundleLazy "vim-scripts/TaskList.vim", {
      \ "autoload": {
      \   "mappings": ['<Plug>TaskList'],
      \}}
nmap <Leader>T <plug>TaskList

プログラミング関係

quickrunによる即時実行

f:id:lambdalisue:20130623070727p:plain

<Leader>rを入力するだけで適切なプログラムを選択し、実行してくれるのがvim-quickrunです。 スクリプトなどをサッと書いて確認するときに非常に重宝します。 またデフォルトでは同期的に実行するためVimが固まりますがvimprocを利用することで非同期通信を安全に実行可能なため僕はその設定で使用しています。

NeoBundleLazy "thinca/vim-quickrun", {
      \ "autoload": {
      \   "mappings": [['nxo', '<Plug>(quickrun)']]
      \ }}
nmap <Leader>r <Plug>(quickrun)
let s:hooks = neobundle#get_hooks("vim-quickrun")
function! s:hooks.on_source(bundle)
  let g:quickrun_config = {
      \ "*": {"runner": "remote/vimproc"},
      \ }
endfunction

非同期実行に関しては作者紹介ブログ記事を参照してください。

Tagbarによるクラスアウトライン

f:id:lambdalisue:20130623070741p:plain

TagbarはExuberant ctagsさえあれば全部勝手にやってくれる素敵プラグインです。 Exuberant ctagsはUnix系OSならパッケージマネージャなどで割りと簡単に入れられるのでお手軽です。

NeoBundleLazy 'majutsushi/tagbar', {
      \ "autload": {
      \   "commands": ["TagbarToggle"],
      \ },
      \ "build": {
      \   "mac": "brew install ctags",
      \ }}
nmap <Leader>t :TagbarToggle<CR>

syntasticによる構文エラー表示

f:id:lambdalisue:20130623070751p:plain

これに関してはまだちゃんと使っていないのでわかりませんが、見た感じ良さそうです。

NeoBundle "scrooloose/syntastic", {
      \ "build": {
      \   "mac": ["pip install flake8", "npm -g install coffeelint"],
      \   "unix": ["pip install flake8", "npm -g install coffeelint"],
      \ }}

Python関係

virtualenvとdjango問題の解決

VimPythonを書く場合virtualenvとDjangoが問題になることが多いです。 まずはそれらを修正するプラグインを入れます。

" Djangoを正しくVimで読み込めるようにする
NeoBundleLazy "lambdalisue/vim-django-support", {
      \ "autoload": {
      \   "filetypes": ["python", "python3", "djangohtml"]
      \ }}
" Vimで正しくvirtualenvを処理できるようにする
NeoBundleLazy "jmcantrell/vim-virtualenv", {
      \ "autoload": {
      \   "filetypes": ["python", "python3", "djangohtml"]
      \ }}

この二つのプラグインを入れることで大抵の既存プラグイン(pythoncomplete等)は動くようになります。

jedi-vimによる最強のPython補完・リファクタリング・リファレンス環境を構築

f:id:lambdalisue:20130623070805p:plain

もう完璧です。jedi-vim最強です。 使ってみればわかりますが、これ以上の機能は望めないでしょう。完璧に高速に動作します。

さらに、なんと、このjedi-vimは補完だけではないのです。こいつが持っている機能を羅列すると

  • .による最高級の補完機能(もしくはCtrl-Space
  • <Leader>gで呼び出し元に飛ぶ
  • <Leader>dで定義まで飛ぶ
  • <Leader>rで名前変更リファクタリング
  • <Leader>nで関係する変数(リファクタリング対象)を羅列
  • Kでカーソル下のPydocを開く

これだけ聞くと「なんだ他のプラグインでも聞いたことある機能だな」と思うと思いますが、完成度が違います。 いままでいくつかのプラグインを試してきましたが、たいていは予想外の動作をするため使い物になりませんでした。 しかしこのjedi-vimさんは賢い。十分使用可能なレベルでシンプルに機能してくれます。

下記が僕の設定です。<Leader>rはquickrunと被るため大文字に変更して有ります。 また補完が最初から選択されていると使いにくいため、補完自動選択機能をオフにしてあります。 さらに関数定義がプレビューされる素晴らしい機能があるのですがウィンドウサイズがガタガタ変わるのでこれもオフにしてあります。

" 2013-07-03 14:30 書き方を思いっきり間違えていたので修正
"NeoBundleLazy "davidhalter/jedi-vim", {
"      \ "autoload": {
"      \   "filetypes": ["python", "python3", "djangohtml"],
"      \   "build": {
"      \     "mac": "pip install jedi",
"      \     "unix": "pip install jedi",
"      \   }
"      \ }}
NeoBundleLazy "davidhalter/jedi-vim", {
      \ "autoload": {
      \   "filetypes": ["python", "python3", "djangohtml"],
      \ },
      \ "build": {
      \   "mac": "pip install jedi",
      \   "unix": "pip install jedi",
      \ }}
let s:hooks = neobundle#get_hooks("jedi-vim")
function! s:hooks.on_source(bundle)
  " jediにvimの設定を任せると'completeopt+=preview'するので
  " 自動設定機能をOFFにし手動で設定を行う
  let g:jedi#auto_vim_configuration = 0
  " 補完の最初の項目が選択された状態だと使いにくいためオフにする
  let g:jedi#popup_select_first = 0
  " quickrunと被るため大文字に変更
  let g:jedi#rename_command = '<Leader>R'
  " gundoと被るため大文字に変更 (2013-06-24 10:00 追記)
  let g:jedi#goto_command = '<Leader>G'
endfunction

ドキュメント関係(Pandoc)

ドキュメント変換ソフトPandocが使える状態になっていることが条件です。 ここではCabalでPandocをインストールし~/.cabal/binの中にpandocという実行ファイルがあると仮定します。

vim-pandoc

それなりに高機能なvim-pandocですが、後記するプラグインのようにビュワーが無いため 基本的にはシンタックス・インデント用にインストールします。下記が僕の設定です。

NeoBundleLazy "vim-pandoc/vim-pandoc", {
      \ "autoload": {
      \   "filetypes": ["text", "pandoc", "markdown", "rst", "textile"],
      \ }}

僕自身このプラグインの機能はほとんど使用していないので興味がある方は本家READMEを読んでください。

shareboard & shareboard.vim

f:id:lambdalisue:20130623070820p:plain

shareboard.vim はどうしてもVimで機能する良いビュワーがなかったので随分前に自分で作ったプラグインです。 shareboard というHTTPベースのクリップボードタイププログラムをベースにしプレビューを表示します。

とりあえず便利なんですが、少しインストールなどの難易度が高いためチュートリアル形式で説明します。

  1. PySideおよびQtのインストール

    Mac OS X % brew install pyside

    Debian % sudo aptitude install python-pyside

  2. Shareboardのインストール

    % pip install shareboard
    
  3. 起動確認

    % shareboard start
    

    を実行後違うシェル(ターミナル)にて

    % shareboard set "Hello"  
    % shareboard get  
    Hello
    

    となるか確認。確認後Ctrl-Cで先のshareboard startを止める

  4. GUI起動確認

    % shareboard start -v
    

    にてウィンドウが立ち上がるか確認。確認後ウィンドウを閉じる

これらがすべてうまく行けば残りは下記設定を行うことで使用可能になります。

NeoBundleLazy "lambdalisue/shareboard.vim", {
      \ "autoload": {
      \   "commands": ["ShareboardPreview", "ShareboardCompile"],
      \ },
      \ "build": {
      \   "mac": "pip install shareboard",
      \   "unix": "pip install shareboard",
      \ }}
function! s:shareboard_settings()
  nnoremap <buffer>[shareboard] <Nop>
  nmap <buffer><Leader> [shareboard]
  nnoremap <buffer><silent> [shareboard]v :ShareboardPreview<CR>
  nnoremap <buffer><silent> [shareboard]c :ShareboardCompile<CR>
endfunction
autocmd MyAutoCmd FileType rst,text,pandoc,markdown,textile call s:shareboard_settings()
let s:hooks = neobundle#get_hooks("shareboard.vim")
function! s:hooks.on_source(bundle)
  " VimからPandocが見えないことが多々あるので念の為~/.cabal/binをPATHに追加
  let $PATH=expand("~/.cabal/bin:") . $PATH
endfunction

なおカスタムCSSを使いたい場合やテキストの置き換え処理などを噛ませたい場合は shareboard.vim#advanced-usage を参照してください。

最後に

正直書くの疲れた!(笑。本当はpowerlineのインストール法なども書こうと思っていたのですが面倒くさすぎるのでそれは他の人に任せます。Google先生に聞けば誰か詳しく解説しているでしょう、たぶん。

追記

結構反響が出たみたいでちょっと嬉しいです。うそ、かなり嬉しいです(真顔。

反響の中でいくつか気になった点に関して書きます。

Python関係なくない?

はい、そのとおりです(笑。 最初は「VIMを最強の開発環境にする」としていたのですが、前書いた記事に合わせるためにPythonをつけただけです(僕個人基本的にはPythonを使うことが多いというのもあります)。 基本的にはVIMの便利設定集みたいなノリで書きました。なのでここに書かれている内容でPythonに全く関係ない設定なども多々あります。

なんでわざわざVIM使ってるの?PyCharmでいいじゃん

Vimperatorとか使ってるほどVIMキーバインド依存してるだけです(笑。

ま、一つ納得できそうな理由をあげるとするならばあらゆるテキスト形式ファイルをVimという共通インターフェイスで編集できたほうが楽だよね?ってことくらいですね。

C/C++はCode Block, C#はMono Developer、PythonはPydev…のように分けると結構大変なんですよね。Vimならば共通設定で通常のテキスト編集設定をして、ファイルタイプ設定で言語依存設定をすれば一つのソフトだけで完結するから個人的には楽です。ま、好みの問題ですね。JavaとかはEclipse一択だと思いますし。

ropevimの話は?

昔使ってましたVimを最強のPython IDEにする - ropevimによるリファクタリング。 ただ個人的にはjedi-vimさえ入ってれば万事OKだと思ったので本記事では言及していません。

vim-markgreenの話は?

これも昔使ってましたVimを最強のPython IDEにする - vim-makegreenによるTDD開発。 ただ最近のユニットテストソフト(Pythonに限らず)は色がついてグラフィカルなものが多いのでターミナルで起動して「おれすげー」感を演出したいので最近は一切使ってません。Vimshellとか使えばいいんでしょうがzsh依存症も酷いので、ここだけは非効率的ですがzshから起動しています(Guakeとか使ってるのでそこまで面倒な作業ではないですしね)。

ま、反響結構あったけど僕がすごいんじゃなくてShougoさんとmattnさんマジパネェって記事なんですよね、そういう素晴らしいツールプラグインを開発できる人材になりたい…