Vimにパッチが当てられるまでの間、Windowsでとりあえず外部grepを使えるようにする
mattn
jvgrepの問題、vimを直すしか方法ない
http://lingr.com/room/vim/archives/2013/12/05#message-17742024
vimがCreateProcessWを使えば解決
たしかパッチは出してあってtodoに入ってたと思う
とのことなので、それまでは我慢と工夫で乗り切るしかないのだ。
仕方ないので、Grepというコマンドを作った。ついでにターゲット無指定の時には現在バッファ周辺を検索対象にすることにして利便性を高めた。
function! s:grep_for_cmdprompt(cmd, argstr) "{{{ let args = split(a:argstr, '\%(\\\@<!\s\)\+') let i = 0 while match(args, '^-', i)!=-1 let i+=1 endwhile let dflbase = expand('%:p:h') let dflbase = dflbase==?expand('$HOME') ? expand('%') : dflbase.'/**/*' let opts = i==0 ? '' : join(args[:i-1]) let pat = has('win32') ? iconv(escape(args[i], '#%'), 'utf-8', 'cp932') : escape(args[i], '#%') let target = i+1>=len(args) ? dflbase : join(args[(i+1):]) let g:greped = a:cmd. ' '. opts. ' -8 '. pat. ' '. target silent exe g:greped endfunction "}}} command! -nargs=+ -complete=file Grep call s:grep_for_cmdprompt('grep', '<args>')
しかし外部grepだと、% # といった特殊文字が展開されてしまうのでエスケープしないといけないのが辛いところ。
vimgrepだとエスケープの必要がない。差別である。
どうにか利用時にエスケープしなくても済むようにしようとしたけれど無駄だった。
関連エントリ:最新版のjvgrepをコンパイルするにはgo言語とMercurialが必要だった - LeafCage備忘録
最新版のjvgrepをコンパイルするにはgo言語とMercurialが必要だった
# go get github.com/mattn/jvgrep
というコマンドを実行するにはThe Go Programming Languageが必要だった。
しかも$GOROOT
$GOPATH
という意味不明な環境変数を設定しなければいけなかった。
さらに、それに使われているmahonia - Mahonia—a character-set conversion library for Go - Google Project Hostingを得るためには水銀の元素記号hgでおなじみ、もう一つのバージョン管理システムであるJapaneseMercurial - Mercurialが必要だった。
インストーラでインストールするのが嫌だったのでMercurial Cmd Portable 1.5.1 Development test 1 | PortableApps.com - Portable software for USB, portable and cloud drivesを適当なディレクトリに展開した上で、Mercurialにパスを通すことで対応した。
悲しいお知らせ
ここまで苦労して導入しても、Vimの'encoding'オプションを'utf-8'にしている場合、Windowsではなすすべもなく使えないらしい。
set grepprg=jvgrepにして:grepしたいのですが、日本語が通りません。
Vim側がutf-8で吐いた文字をコマンドプロンプトがcp932として呼んでしまうからですが、解消する方法を知りませんか?
http://lingr.com/room/vim/archives/2013/12/05#message-17739621
絶望
つまり現状ではコマンドプロンプトを使うのをやめるか、qfixgrepを使うしか解決策がないわけですね。
http://lingr.com/room/vim/archives/2013/12/05#message-17740433
qfixgrepは余計なことを色々しているから好きにはなれないのですが。
光明
qfixgrepの中身を見てみたが、つまり最悪、外部コマンドに渡すときにiconv()でエンコードを変換してやれば何とか出来るっぽい。
http://lingr.com/room/vim/archives/2013/12/05#message-17740591
おし。
http://lingr.com/room/vim/archives/2013/12/05#message-17740802
exe 'grep '. iconv('ファイル', 'utf-8', 'cp932'). ' %'だと正常機能した。
つまり渡すときエンコードしてくれるラッパーコマンドを定義してそれを使えば当面は解決できる問題になった。
コマンドラインで :b を実行するときにバッファリストを表示する
Vim - hjklマスターに薦める意外と便利な機能 - Qiita [キータ]
の
バッファを選択する際に、同時にリストを表示する
nnoremap B :ls<CR>:b
という設定を見て閃いた。
cnoreabb <expr>b getcmdtype()==':' && getcmdline()=='b' ? 'ls<CR>:b' : 'b'
こうすればコマンドラインで:b
を打ってから<Space>
キーを打つと勝手に:ls
が表示されるようになる。
nebula.vimを使ってneobundle#tap()をより高速に書く
Shougo/neobundle.vim に ももんが流NeoBundle管理術 | かなりすごいブログ から機能が取り込まれneobundle#tap()
neobundle#untap()
が使えるようになりました。
これを利用するとだいたいこんな感じで非常にすっきりとプラグインの設定が書けます。
ここでは LeafCage/nebula.vim を使って、より楽に高速にneobundle#tap()
を記述する方法を紹介します。
vimrcのNeoBundle 'repository/pluginname'
のある行で:NebulaYankTap
を呼び出すと、
if neobundle#tap('pluginname') endif
がレジスタにセットされます。
:NebulaYankTap!
のように、!
付きで呼ぶと
if neobundle#tap('pluginname') "{{{ endif "}}}
のようにfoldingmarker付きでヤンクされます。
これを記述したい場所にカーソルを持ってきて貼り付ければよいのです。
中身のneobundle#config()
を書くときにはShougo/neosnippet.vimなどで
snippet neobundleconfig alias nbc call neobundle#config(${1})
みたいなsnippetを定義しておいて、オプションを:NebulaYankOptions
で生成すると捗ります。
コマンドラインからシームレスにover.vimの全体置き換えを使う
私は今まで:s
について以下の設定をしていた。
cnoreabb <expr>s getcmdtype()==':' && getcmdline()=~'^s' ? '%s/<C-r>=Eat_whitespace(''\s\\|;\\|:'')<CR>' : 's' function! Eat_whitespace(pat) "{{{ let c = nr2char(getchar(0)) if c=~a:pat return '' elseif c=~'\r' return '' end return c endfunction "}}}
こうしておくと、コマンドラインでs
と打ってから<Space>キーで %s/
という具合に展開されていたので、全体置き換えをするときに打ちにくい %
を打たなくて済むという利点があった。
そんな折、osyo-manga/vim-over がリリースされた。
結果をプレビューする機能はCoolだがぶっちゃけそんなに要らなかったが、置き換え実行後にカーソルが動くことがないというのに魅力を感じたので、上記の操作を over.vim で置き換えることにした。
以下のように設定することでコマンドラインで s
を打ってから<Space>を打つと、そのままover.vimで %s/
が入力された状態になる。
cnoreabb <silent><expr>s getcmdtype()==':' && getcmdline()=~'^s' ? 'OverCommandLine<CR><C-u>%s/<C-r>=get([], getchar(0), '')<CR>' : 's'
Vimのabbreviate(短縮入力)機能によって、行頭でのs
をOverCommandLine<CR><C-u>%s/
に置き換えているわけである。
その際、トリガーに使った<Space>は不要なのでgetchar(0)に食わせている。
<C-r>=get([], getchar(0), '')<CR>
の部分はトリガーに使った文字の処分である。
別にトリガーは短縮入力を展開できる文字なら何でも良いので<Space>でなくて<CR>でも良い。
'nobuflisted' なバッファの作り方
Vim Advent Calendar 2012 356日目の記事です。
バッファをバッファリストに登録したくないときがあります。
バッファリストに登録されていないバッファは:ls
では表示されず、:bnext
:bprevious
でのバッファ切換の対象になりません。
また、Vim終了時に次回起動時のための情報を書き込むviminfo
ファイルのバッファリスト保存・復元から除外されます。つまりVim終了時にはそのバッファは破棄され次回起動に持ち越しません。
このオプションは通常、その場限りの情報を表示するだけで、書き込む予定のない、使い捨てのバッファに設定します。
しかし、せっかく'buflisted'
オプションをオフに設定しても、バッファの内容を変更すると勝手に'buflisted'
がオンに設定し直されてしまいます。
正しくは「バッファの編集を始めると」オンになるのでした。:edit
や:split
:vsplit
:new
などで切り替えるとオンにされるみたいです。つまり:edit
などを使わず:buffer
でバッファを切り替えるのなら:setlocal nobuflisted
を設定するだけでよいです。
ここではいかにして、何らかの形で意図せず'buflisted'
オンになっても'buflisted'
をオフに保つようにするバッファを作るのかを解説します。また、特別なバッファに設定するべき他のオプションも併せて説明します。
変更の予定のないバッファの場合
バッファを変更する予定がなければ、ただ単に'nobuflisted'
オプションを設定すればいいです。
その際、ユーザにバッファの内容を変更を禁止させるように'nomodifiable'
オプション、読み込み専用だということをユーザに示すために'readonly'
オプションもセットしましょう。
edit examplebuf setlocal nobuflisted nomodifiable readonly
※これらはバッファにローカルなオプションなので:setlocal
ではなく通常の:set
で設定しても問題ありません。
:edit
に+cmd
オプションを与えればこのコマンドを1行で表せます。
edit +setlocal\ nobuflisted\ nomodifiable\ readonly examplebuf
変更の予定があるバッファの場合
編集が禁止されたバッファでスクリプトがバッファの内容を変更するのなら、そのときに一時的にこれらのオプションを変更し、内容変更後に元に戻せばいいでしょう。
setlocal buflisted modifiable noreadonly call setline(1, '==example==') setlocal nobuflisted nomodifiable readonly
ユーザが自由に編集できるバッファをバッファリストに登録させたくない場合は、そのバッファを抜けるときに'nobuflisted'
に設定しなおすバッファローカルなautocmdをそのバッファに設定しておきます。
また、たまたまそのバッファにいるときにVimを終了させようとしたときにもバッファリストから除外するようにVimLeavePre
イベントのautocmdも設定します。
edit examplebuf augroup example_local autocmd! autocmd BufLeave <buffer> setlocal nobuflisted autocmd VimLeavePre <buffer> setlocal nobuflisted augroup END
需要があるか分かりませんが、現在Vimではbuflisted
にしておきたいが、Vim終了時にはnobuflisted
にして次回起動時のバッファに残させないときの設定です。この場合そのバッファのバッファ番号を何らかの形で記憶しておき、autocmd VimLeavePre \*
でそれらのバッファにnobuflisted
オプションを設定します。
augroup example_local autocmd! autocmd VimLeavePre * call <SID>make_bufs_nobuflisted() augroup END let s:bufnrs = [] function! s:make_bufs_nobuflisted() for bufnr in s:bufnrs if buflisted(bufnr) call setbufvar(bufnr, "&bl", 0) endif endfor endfunction
edit examplebuf call add(s:bufnrs, bufnr('%'))
特別なバッファに設定するべき他のオプション
readonly, nomodifiable
説明済み
buftype
ファイルと関連がなく、書き込まれる予定のない仮想的なバッファにはset buftype=nofile
を設定します。
buftype=nofile
を設定すると:write
が禁止されます。しかし、バッファの編集変更自体は出来るので、それを禁止させたければ前述のnomodifiable
も設定しましょう。
bufhidden
バッファの使い捨てという正確を強めたいときに利用します。
バッファがウィンドウに表示されなくなったときの挙動を指定するオプションですが、そのバッファを閉じたらバッファの内容を破棄させたいのならbufhidden=unload
、削除や完全削除をしたいのならbufhidden=delete
(←これはまだ:b
でバッファ指定するなどしたらアクセスできる)やbufhidden=wipe
(←完全に削除される)を使います。
例えばkien/ctrlp.vimでbufhidden=unload
が利用されています。ctrlp.vimの作るバッファは刹那的な性格が強いですし、無駄なメモリも解放されるからでしょう。
活用例
例えばShougo/vimfiler.vimの作るバッファをバッファリストに残したくない時には.vimrc
に次の設定を書きます。
autocmd FileType vimfiler setlocal nobuflisted \ | autocmd BufLeave <buffer> setlocal nobuflisted \ | autocmd VimLeavePre <buffer> setlocal nobuflisted
これでバッファを閉じたときにはバッファリストのサイクルから外れますし、次回起動時にvimfilerのバッファが残っているということもありません。
Vimスクリプトのファイル先頭にscriptencodingを書く意味
LeafCage
ファイルの先頭でscriptencoding を書くのはどういった利点があるのでしょうか?今までscriptencodingを書いてこなかったのですが、書いておくとVimがencodingを調べることがなくなって読み込み速度がアップするのでしょうか?
thinca
マルチバイト文字がスクリプト内に含まれている場合は、scriptencoding がないと、'encoding' とファイルのエンコーディングが異なる場合に文字化けします
LeafCage
echoで日本語を表示させるときならscriptencodingは必須と言うことでしょうか?
コメントに日本語が含まれている場合には大丈夫ですか
thinca
http://lingr.com/room/vim/archives/2013/11/07#message-17304879
> echoで日本語を表示させるときならscriptencodingは必須と言うことでしょうか?
そうなります
コメントでも、改行文字が食われるような化け方をする可能性を考えると、書いておいた方がいいです
set encodingよりも後に書かなければいけないらしい。
thinca
scriptencoding は set encoding よりも後にやる必要があり、しかしマルチバイト文字が出てくる前に scriptencoding は実行しないと意味がない
http://lingr.com/room/vim/archives/2013/11/23#message-17465700