ぼちぼち散歩

Vimでoperator-userを使って他のプラグインをoperatorとして使えるようにしてみた

kanaさん作のoperator-userを使うと,簡単にoperatorを定義できる.operatorというのはここでは,Vimのコマンドのうちdwとかc$とかのdとかcとかの,動作を指定するコマンドのこと(こんな説明でいいのか,まぁ詳しくは:h operatorで(^-^;)).で,Vimにははじめから便利なoperatorが定義されていて,新たにoperatorを定義できると言われても,さてどうしたもんかと思っていた.

そんなときに,operator-userとは別に,commentop.vimというコメントアウト/アンコメントするためのoperatorを定義するプラグインを見つけて,あーなるほどこれは便利だと思った.ところが,コメント系のプラグインとしては,NERD Commenterが非常に高機能で便利に使っていたので,そこから機能が落ちるのはちょっとなぁとも思っていた.

というわけで,前置きが長くなったけど,それだったらNERD Commenterとoperator-userを組み合わせて新しいoperatorを作ったらいいんじゃね?ということでやったみた.以下を.vimrcなどに書いておけば,,cや,uなどといったoperatorが定義される.

function! s:SID_PREFIX()
    return matchstr(expand('<sfile>'), '<SNR>\d\+_')
endfunction

noremap [Operator] <Nop>
map , [Operator]

" デフォルトのマッピング定義を行わない
let g:NERDCreateDefaultMappings = 0
 
 nmap gA <Plug>NERDCommenterAppend
 nmap [Prefix]a <Plug>NERDCommenterAltDelims

" NERDCommenter + operator-user
function! s:setCommentOperator(key, name)
    call operator#user#define(
    \   'comment-' . a:name,
    \   s:SID_PREFIX() . 'doCommentCommand',
    \   'call ' . s:SID_PREFIX() . 'setCommentCommand("' . a:name . '")')
    execute 'map' a:key '<Plug>(operator-comment-' . a:name . ')'
endfunction

function! s:setCommentCommand(command)
    let s:comment_command = a:command
endfunction

function! s:doCommentCommand(motion_wiseness)
    let v = operator#user#visual_command_from_wise_name(a:motion_wiseness)
    execute 'normal! `[' . v . "`]\<Esc>"
    call NERDComment(1, s:comment_command)
endfunction

call s:setCommentOperator('[Operator]c',       'norm')
call s:setCommentOperator('[Operator]<Scace>', 'toggle')
call s:setCommentOperator('[Operator]m',       'minimal')
call s:setCommentOperator('[Operator]s',       'sexy')
call s:setCommentOperator('[Operator]i',       'invert')
call s:setCommentOperator('[Operator]y',       'yank')
call s:setCommentOperator('[Operator]l',       'alignLeft')
call s:setCommentOperator('[Operator]b',       'alignBoth')
call s:setCommentOperator('[Operator]n',       'nested')
call s:setCommentOperator('[Operator]u',       'uncomment')

一応ポイントとしては,NERDComment()という関数がNERD Commenterの本体で,第一引数を1にしておくと直前のVisual modeで選択された範囲に対して操作を行うというところ.なので,doCommentCommand()でoperatorの操作範囲を一旦Visual modeで選択してからEscするようにしている.NERD Commenterの各コマンドの意味は:h NERDComFunctionalitySummaryを参照ということで.

また,operatorは,例えばddで一行削除やyyで一行ヤンクというように,2回連続入力でその行全体に対して動作したり,Visual mode中では選択範囲に対して動作したりするのだが,operator-userで定義したoperatorもちゃんとそのように振る舞う.そのため,,c,cで一行コメントアウトやVisual mode中に,uで選択範囲をアンコメントといった動作も同時に定義される.なので,NERD Commenterのデフォルト定義は無効にしてある.

さらに,textobj-commenttextobj-indentといった,text objectとももちろん連携可能なので,使いこなせば光の速さでコメント操作ができるようになる!...はず!

あと,調子にのってAlignプラグインもoperator化してみたけど,さすがにこれはちょっと無理があると思った.自分ではたまに使おうと思うけど(^-^;)

2009/09/19 15:35 | Vim | トラックバック(0) | コメント(0)

ページの先頭へ

MacVim-Kaoriyaでデフォルトのvimrcとgvimrcを読まないようにする

Mac上のGVimとしては最強に快適なMacVim-Kaoriyaだけど,デフォルトでKaoriya版GVimに含まれるvimrcとgvimrcが読まれて,個人的にはいらない設定を勝手にされてしまうので,これを回避してみた.

vimrcとgvimrcを読んだらわかる通り,基本的には /Applications/MacVim.app/Contents/Resources/vim/ にちょろっとファイルおくだけだけど,MacVim-Kaoriyaアップデート時に簡単に再設定できるように簡単なワンライナ(?)にしてみた.ついでに,vimrc_local.vim にて set langmenu=ja_ja.utf-8.macvim することで,メニューがMacらしく日本語化される.自分はzshの履歴にこのコマンドを覚えさせといて利用している.

echo "let g:vimrc_local_finish = 1\nset langmenu=ja_ja.utf-8.macvim" > /Applications/MacVim.app/Contents/Resources/vim/vimrc_local.vim; \
echo "let g:gvimrc_local_finish = 1" > /Applications/MacVim.app/Contents/Resources/vim/gvimrc_local.vim

ちなみに,WindowsのKaoriya版GVimでも同様に,デフォルトのvimrcとgvimrcの読み込みを阻止している.あと,Windowsで:set encoding=utf-8する方法 - 永遠に未完成を参考にUTF-8化するのもおすすめ.自分の場合はPoeditで エンコードの変換とmoファイルへの変換を一気にやりました.

2009/07/01 20:53 | Vim | トラックバック(0) | コメント(0)

ページの先頭へ

ku source: mrufileとmrucommand続き,およびMac上のVimでOptionキーを扱う方法

昨日kuのsource作ったよ!とtwitterに書いたところ,Lingrのvim-users.jpにてkanaさんとthincaさんからいろいろとアドバイスを頂いたので,書き直してみた.

mrufileの方は,thincaさんのku source: file_mruを参考にしつつも,項目にディレクトリも入れておきたかったので,そんな感じで修正してみた.あと,autocmdはplugin以下に移した.ただ,履歴を削除できたりとかthincaさんの方が高機能なので,おすすめです.

mrufileとmrucommand共通の話としては,ku 0.2系からは本体側でキャッシュしてるので,source側では簡単に書けるようになっているそうだ.mrucommandの方なんかは,実質gather_itemの中で履歴集めるだけになった.

さらに,kuの設定についてもkanaさんにいろいろとアドバイスしてもらった.その結果はこんな感じ.ここで注意すべきは,kuは既に設定されているmapを上書きしないので,例えば,kuでコマンド実行する<Cr>とかを他のところで<Cr>をmapしているとうまく動かない.そこで,kuのデフォルトキーで強制的にmapしたのち,さらにそこに自分用のmapを設定するようにしている.

ちなみに,<Esc><Cr>とか書くとMeta-Returnというmapを定義したことになる.ただし,Macの場合は,Terminal.appだとターミナル -> 環境設定 -> 設定 -> キーボードの「メタキーとしてoptionキーを使用」,iTerm.appの場合は,Bookmarks -> Manage Profiles... -> Keyboard Profilesの「Option Key as」を「+Esc」にしなければならない.それでも,iTerm.appの場合は,<Esc>jとかはうまくいかない.それはことえりの英数入力とかだと,Option+[a-zA-Z]が記号入力に割り当てられていて,iTermまでOptionが届いてないのが原因の模様.入力モードをU.S.にすればこの問題は回避可能だが,その場合JISキーボードだとバックスラッシュを入力する手段がなくなるので,それはそれで使いにくくなってしまい残念な感じ.この辺の問題については今後の課題.

また,GVimとかMacVimの場合,<A-Cr>のようにA-をつけるとOptionキー(WindowsとかだとAltキー)指定になる.というわけで,現状は,Option-CrとかOption-Tabとかだけがほぼ全ての環境で使いものになる感じ.

2009/5/10 00:20 追記: thincaさんもmrucommand相当のを作ってくれたようだ.そちらも削除コマンドとかあったりして高機能なので,自分が作ったのは練習用&自分専用って感じやなー.でも,自分で実装すると具体的なアドバイスもらえたりとかなり楽しかったので,また別のsourceを作ってみようかな.何を補完できたら便利かなぁ.tagとかは微妙か.

2009/05/09 22:07 | Vim | トラックバック(0) | コメント(0)

ページの先頭へ

kuを使いはじめたのでku source: mrufileとmrucommandを作ってみた

最近,kanaさんによるVimプラグインであるkuを使ってみている.kuはsourceと呼ばれるプラグインの用なものを追加することで,検索対象を増やすことができる.というわけで,最近使ったファイルと最近使ったコマンド用のsourceを作ってみた.

mrufileはfuzzyfinderのMRUFileのあたりのソースとku source: historyのソースをだいぶ参考にし(というかパクリ)ながら,それっぽい感じにしたつもり.mrucommandはq:とq/で出てくるコマンド履歴と検索履歴をku用に整形した感じ.ただ,実行するところ(ku#mrucommand#execute()とku#mrucommand#input())の書き方がわからず結局feedkeys()になってしまった.

と思ったらmrufile相当のは既にありましたorz自分が書いたのは最近リリースされたku 0.2系に対応してるということで,ギリギリセーフといことにしておくか(^-^;) 2009/5/9 00:48追記: thincaさんが0.2系対応版のmrufileをgithubに上げてくれました!(リンク先の追記参照)

とりあえず動いていますが,バグとかあるかも知れません.あとはkanaさんが美しく直してくれるはず!

2009/05/08 21:07 | Vim | トラックバック(0) | コメント(0)

ページの先頭へ

Vimのマッピングについて考え中

Vim使いから見てkey-chord.elがいかに役に立たないか - while (”im mirrored”);を見て.

Vimで自分用に新しくマッピングを定義するとき,これまで以下の順番で考えて,結局今のところはだいたい<Space>をプレフィックスにする方法をメインで使って,使えるところは<expr>使って柔軟な動作にする感じになっている.

  1. 自分の使わない既存のマッピングを殺して,それをプレフィックスにして定義する.
    (例)f使わない人
    nnoremap f <nop>
    nnoremap fa :some_command<CR>
    nnoremap fb :call some_func()<CR>
    ...
  2. 既存のマッピング殺すのが気持ち悪いので<Leader>をプレフィックスとして使う.
    nnoremap <Leader>a :some_command<CR>
    nnoremap <Leader>b :call some_func()<CR>
    ...
  3. Leaderだとプラグインとかぶったり,デフォルトだと押しにくい.let leader=","とかも既存のマッピング殺しているので気持ち悪い.そこで,<Space>とか<CR>とかをプレフィックスにする.
    nnoremap <Space>a :some_command<CR>
    nnoremap <Space>b :call some_func()<CR>
    ...
  4. 場合によっては<expr>使うと幸せ.
    folding を h,l で閉じたり開いたりするマッピング - ns9logとか,
    inoremap <silent> <expr> <CR> (pumvisible() ? "\<C-e>" : "") . "\"
    inoremap <silent> <expr> <Tab> pumvisible() ? "\<C-y>" : "\<Tab>"
    みたいなやつ

ところが,<Space>を使うマッピングは思ったほど押しやすくない,つまり親指→その他の指,というシーケンスがそんなに押しやすくない.そこで,たまたまkanaさんのarpeggio.vimを使ってみて,これはいいなと思った.例えば,

Arpeggionnoremap ra :some_command<CR>

とした場合,r→aと押したときはデフォルトの文字置換できて,a→rと押したときはデフォルトの文字挿入ができて,rとaをほぼ同時に押したときはsome_commandが発動する,といったようにデフォルトの動作を殺さないまま,かつ押しやすいところにマッピングを追加できる.

ところが,冒頭で挙げたkanaさんの記事では,arpeggio.vimは役に立たなくないとい結論で,自分は稀な人なのか,と思った.考えてみると,

自明なことだが、同時押しを採用する主な理由は割り当てたい機能に対してそれ以外に使えるキーシーケンスがないからだ(「使える」はタイプのし易さ等を含む)。モードレスな編集体系ならばそう余裕はないが、Vimはそうではない。

に関しては,デフォルトのマッピング殺すの気持ち悪いというどうでもいい理由で,使えるキーシーケンスをむやみに絞っている自分が悪い.次に,

key-chord.elが提供する機能を言い換えると、タイムアウトありの曖昧なキーバインド定義になる(space-chord.elは特にこれを意識したものになっている。当人にそういうつもりはないだろうけれど)。これはVimではデフォルトでできるし、ある程度以上Vimを使っていればその恩恵に預かっている。だからVim使いから見ればkey-chord.elは「タイミングを微調整して同時押しをエミュレートした」という点以外に真新しいものはないし、それを使わなくても普通にキーバインドを定義するだけで十分だ。

に関しては,自分にとっては,どんな場面でも通用する一定のtimeoutlenがない,またはこのへんの動作がよくわかってない.最後に,

(これは主観だが)同時押しにかかるコストはそう小さくはない。Vim使いのキーバインドは「いかにモディファイヤーを押さずに事を済ませるか」あるいは「いかにモディファイヤーを押しっぱなしで事を済ませられるか」となる傾向にあるので、上記の理由も合わせて、タイミングのシビアな同時押しを利用するよりも普通のキーバインドを定義した方が楽だ。

に関しては,デフォルトのマッピングを殺さない前提だと,個人的には<Space>プレフィックスよりarpeggio.vimによる同時押しの方がましだと思っているのでちょっと違う.

要するに,「デフォルトのマッピングを殺したくない」にこだわってみた結果,なんだかおかしなことになっているのだと思う.kanaさんの.vimrcとか見るとtとかqは殺されているので,自分も思いきって適当なキーを殺すとすっきりいくかも知れない.その他の案としては,デフォルトのマッピング殺すにしても影響少なそうなShiftキー押しながらに全部定義してしまう,どうにかしてtimeoutlenを動的に定義する,がある.前者は,

nnoremap F <nop>
nnoremap FA :some_command<CR>
nnoremap FB :call some_func()<CR>

とか.後者は突き詰めると結局arpeggio.vimになってしまうような気もするな.もう少し考えてみよう.

2009/01/18 19:24 | Vim | トラックバック(0) | コメント(0)

ページの先頭へ

前のページへ << トップページへ >> 次のページへ