cafegale(LeafCage備忘録)

LeafCage備忘録(はてなダイアリー)と統一しました。

ウィンドウを分割させて新しいバッファを表示させる系のコマンドを含む関数内での:echoは一瞬だけしか表示されない

WarningMsgを表示させてから新窓で開こうとしたら、新窓が開かれた後の画面更新でechoが消されてしまった。関数内で、順番を、[新窓を開く→:echo]の順にしても無駄。

関数が終了して初めて画面更新が行われるので、それで:echoが消されてしまう。
しょうがないので、:echoの代わりに:call input()でメッセージを表示させて、必ず一瞬立ち止まらせるようにした。邪道。
良い回避法があれば知りたい。

ctrlp.vimの拡張作成は想像以上に自由がなかった

実際拡張を作ろうとすると、想像以上に自由がないことが分かる。

  • 複数選択が出来ない(標準プラグインでは出来るのに)
  • 入力パターンマッチの種類が少ない(前方一致が欲しい)
  • ページ送り・戻し機能がないから画面にない候補を選択することが出来ない(何となく一覧するという使い方が不可能)
  • 正規表現モードの切換を拡張作成者側が設定できない(ここは正規表現で入力させたいと思っても、切換はユーザに委ねられている)
  • 初期入力を拡張作成者が設定できない(feedkeys()を使えば出来ないことはないけど標準ではサポートされていない)
  • 候補窓の大きさや表示方法を拡張作成者が設定できない(ユーザの初期グローバル設定に依存する)

候補の表示方法を拡張作成者が選択できないこととか、窓から溢れて見えなくなっている候補にアクセスできないことは、拡張の可能性をとても狭めている。

副作用の少ないYankRing.vimみたいなのができました

Vimmerにハロウィンがアドベントしましたね。
Vim Advent Calendar 2012 335日目の記事です。


Vimレジスタの履歴を取って再利用するプラグインにYankRing.vimというものがあります。間違えてp(テキストを貼り付け)してしまっても<C-p>で即座に履歴を遡(さかのぼ)ってテキストを置き換えられます。とてもお手軽で、優れたインターフェイスです。
しかしながら副作用が多く、他のプラグインや設定と干渉してしまうという問題がありました。(重要なキーマッピングを軒並み置き換えてしまうのは勘弁してほしいです。)
それを見かねたShougoさんはunite-source-history/yankというものを作ってくださいました。レジスタの履歴がunite.vimのインターフェイスで閲覧でき、操作できます。便利でしたが、YankRing.vimと比べると、お手軽さで劣りました。

それでしばらくはレジスタ履歴を使わず、必要になったらその都度ヤンクし直すという原始的なことをしていましたが、ふとYankRing.vimの載っている記事を見て*1あの操作感が羨ましくなったので、それっぽい挙動をするプラグインを作ってみました。

NeoBundle 'LeafCage/yankround.vim'

副作用が(たぶん)起こらないように注意しましたので、ヘビーユーザーにも堪える作りになっています。

YankRing.vimっぽく使う

もしYankRing.vimっぽく利用するのであれば、以下のキーマッピングをして下さい。

nmap p <Plug>(yankround-p)
nmap P <Plug>(yankround-P)
nmap gp <Plug>(yankround-gp)
nmap gP <Plug>(yankround-gP)
nmap <C-p> <Plug>(yankround-prev)
nmap <C-n> <Plug>(yankround-next)

これで貼り付けを行った後に<C-p><C-n>レジスタ履歴を遡ってテキストを置き換えることが出来ます。
カーソルを動かすと候補が確定されます。


デフォルトの履歴取得数は30までです。

let g:yankround_max_history = 35

で変更できます。
Vim終了時に履歴のキャッシュを専用ファイルに保存しますがそのディレクトリはデフォルトで以下の場所になります。

let g:yankround_dir = '~/.cache/yankround'

<C-p><C-n>は貼り付け直後にしか有効ではありません。
もしもそれが勿体ないと感じるのでしたら、<expr>を使ったマッピングでyankround#is_active()を使うことで、普段は別の役割を持たせることが出来ます。
例えば、yankroundが有効でないときの<C-p>で、:CtrlPを呼び出すなど。

nnoremap <silent><SID>(ctrlp) :<C-u>CtrlP<CR>
nmap <expr><C-p> yankround#is_active() ? "\<Plug>(yankround-prev)" : "<SID>(ctrlp)"

CtrlPでレジスタ履歴を利用する

yankround.vimにはkien/ctrlp.vimの拡張も付属しています。
:CtrlPYankRoundコマンドで利用することが出来ます。

nnoremap <silent>g<C-p> :<C-u>CtrlPYankRound<CR>

レジスタ履歴が一覧表示されます。履歴を選択後、

  • <CR>で、その履歴をカーソル位置に挿入します。
  • <C-x>(<C-s>)で、無名レジスタ " にその履歴をセットします。
  • <C-t>で、その履歴を履歴から削除します。

※unite-sourceは時間がなかったのと面倒くさかったので作りませんでした。作りました。

貼り付けた部分をハイライトする機能も付けました。

こうして私に再びレジスタ履歴がアドベントしました。
もしも私と同じく、本当はYankRing使いたかったんだけど、キーマップを乗っ取られるのが嫌で利用を諦めていたのなら、ぜひyankround.vimをお試し下さい。

*1:実はunite-source-history/yankっぽいのをctrlp.vimで実装して、それをVACの記事にしようとしてすでにその記事まで書いていたのだが、YankRing.vimとの比較という項を書くためにYankRing.vimについて調べていたら、やっぱりYankRing.vimのインターフェイスの方が便利じゃねーかと思えてきて急遽YankRingっぽいのを作ったというのが真相。

ユーザに入力をさせるinput()のインターフェイスが不満すぎて仕方がないならctrlp.vim風の入力インターフェイスalti.vimを使おう

Vim Advent Calendar 2012 333日目の記事です。

alti.vimctrlp.vim風の操作感を持つ入力インターフェイスです。

もしもユーザに多少複雑めの入力を要求したい場合は、Vimの組み込み関数input()でそれを実現するのが苦しいことがあります。
なぜならinput()には

という弱点があります。他にも操作性の悪さなどが弱点に挙げられます。

input()やコマンドライン補完で複雑な入力をユーザに負担なくさせるのは難しいと気付き、unite.vimctrlp.viminput()みたいなことをするのも恐らく不可能だ*1と考えた私は、新しい入力インターフェイスを開発しました。ちょうどctrlp.vimを本格的に使い始めて、そのインターフェイスを気に入ったので、その影響をかなり受けています。補完の候補が常時、窓に表示されて、入力と共に絞り込まれていくような感じで。

基本の仕組みはctrlp.vimのものを踏襲しましたので、設定変数もctrlp.vimに似せています。
ヘルプに詳しく記しましたのでご参照ください。
操作法を簡単に説明しますと、<C-j><C-k>で補完候補を選択、<Tab>で補完候補を挿入、<C-f><C-b>でページ送り/戻し(補完候補が多すぎるときのみ)、<C-h><C-l>で左右移動、他はコマンドラインの標準の操作とだいたい同じです。<CR>で入力したコマンドを実行します。*2
alti.vimは拡張あって初めて動作するので、これから拡張の作り方を解説していきます。

*1:もしかするとunite.vimでは私がやり方を知らないだけで不可能ではないのかも知れませんが、向いてはいないでしょう。

*2:標準キーマッピングは予告なく変更する可能性があります。

続きを読む

俺が見たいのはメッセージの最後なんだ!:messagesを便利にするVimプラグイン

Vim Advent Calendar 2012 330日目の記事です。

Vimでエラーが発生した時にメッセージが表示されます。
そのメッセージを後から確認したい場合は:messagesでメッセージ履歴を表示します。
しかし:messagesにはVimが起動してからのメッセージが蓄積されているので、長時間起動しているとメッセージが長くなってしまい、最後の方にある目当てのメッセージを表示するためにスクロールさせるのが苦痛になってきます。
知りたいのはエラーが発生してからのメッセージ数行だけでいいのに、200のメッセージをスクロールしなければいけないかもしれないのです。

見ることのできるメッセージ数は、tiny バージョンでは20に、それ以外のバージョン
では200に固定されている。
:help :messagesより引用)

このメッセージは蓄積される数を変更することも出来ないし、消去することも出来ません*1。非常に不便です。

前々からフラストレーションを感じていたので、こんなのを作りました。

NeoBundle 'LeafCage/lastmess.vim'

これを使えば、

:LastMess

で、デフォルトで最後の10行のメッセージが表示されます。

:LastMess 12

または

:12LastMess

というように数値を与えてやると、最後の与えられた数字行のメッセージ(この場合は最後の12行)が表示されます。

表示される行のデフォルト値は10ですが、g:lastmess_default_countで変更することが可能です。

let g:lastmess_default_count = 15

<Plug>(lastmess)はキーマップ版です。例えばこれを

nmap mz <Plug>(lastmess)

というキーに充てておきますと、mzでデフォルトの10行のメッセージが表示されます。
15mzのようにカウントを与えると、その行数分のメッセージが表示されます。

カウントに999などの大きな数値を与えた場合は、メッセージが最初から表示されます(:messagesと同じですね。)。
これで:messagesを見るストレスが軽減され、特にプラグイン制作者は捗ることでしょう。

*1:for i in range(200)| echom ''| endfor みたいなことをすればメッセージをクリア出来るとおしょーさんに教えていただきました。 http://lingr.com/room/vim/archives/2013/10/26#message-17184693

lightline.vimをカスタマイズする

Vim Advent Calendar 2012 の325日目の記事です。
少し長めになりますので、お時間があるときにお読みください。

Vimのステータスラインを改造するプラグインが、Lokaltog/powerlinebling/vim-airlineに続いてitchyny/lightline.vimが登場しました。
私は今までステータスラインやタブラインは自前で改造していましたが、モダンなラインも経験してみたかったので、導入することにしました。

(当記事の内容)
続きを読む