README.mdをVimのヘルプファイルから生成する
この記事はVim Advent Calendar 2012の341日目の記事です。
前回(84日前)Vimプラグインのスクリプトファイルからヘルプファイルを生成するというのをやりました。
しかしGitHubではREADME.md
ファイルがリポジトリの窓口であり、説明であり、これによってそのプラグインの概要を知り、それを導入するかどうかが判断されます。
README.md
を置いていないとプラグインの詳細を知るためには、リポジトリトップから2クリックもかかるdoc/xxx.txt
を見に行かなければいけませんし、リポジトリトップにはGitHubがREADME.md
を置けと勧めてきます。
つまり我々はREADME.md
を書くことを暗に強いられているのです。
しかし、すでにhelpに概要含め色々書いているのにさらに別の場所で二重に概要を書かなければいけないなんて苦痛です。
なぜhelpに書いたことを改めて書かなければいけないのでしょうか。
そこでLeafCage/vimhelpgeneratorに:HelpIntoMarkdown
というコマンドを追加しました。*1
ヘルプファイル内でREADME.md
に含めたいところをビジュアル行選択(“概要”や“使い方”などを選択すると良いでしょう)して、
:HelpIntoMarkdown
を実行すると、
そのヘルプファイルの上にあるREADME.md
ファイルが開かれます。*2
ここでP
すると、先ほど行選択されたテキストがmarkdown形式に変換されてput
されます。(README.md
を初めて作成するときにはプラグイン名と説明もhelpファイルの第1行目から生成されます。)
手直しした後、:write
しましょう。
:HelpIntoMarkdown
はアンダースコア(_)のエスケープには対応していません*3。自力で対応させて下さい。
もしもヘルプファイルを改修したときには改修した箇所をビジュアル行選択して:HelpIntoMarkdown
して下さい。その部分の変換結果がレジスタにセットされるのでREADME.md
にて貼り付けて手直しして下さい。
これでヘルプファイルとREADME.md
を管理する手間を大幅に減らすことが出来ました。
:VimHelpGeneratorVirtualでヘルプを仮想バッファに出力する
vimhelpgeneratorには、:VimHelpGeneratorVirtual
というコマンドも加わっています。
:VimHelpGenerator
が生成したバッファをそのまま書き込むのに対し、:VimHelpGeneratorVirtual
は仮想バッファに出力します。
これにより、vimhelpgenerator
の、ヘルプファイルを初めて作るときにしか使えなかったという欠点を解消しました。
プラグインに機能を追加するなどしてヘルプの改修の必要性が生じたとき、:VimHelpGeneratorVirtual
を実行して、出力された仮想バッファ内で必要な部分だけを、既存のヘルプファイルにコピーペースト(Vim風に言うとヤンクプット)すれば良いのです。
単純にVimHelpGenerator
の出力を確認したいときにも利用できます。
:VimHelpGenerator
を実行したときにすでにヘルプファイルが存在している場合もこのモードで出力されます。
throw "ERROR"のチェックの簡潔な記述
t9md:
if Check1()
throw "ERROR"
endifこういうチェックをいっぱいやる場合に
http://lingr.com/room/vim/archives/2013/11/03#message-17268337
Check1() && throw "ERROR"
Check2() && throw "ERROR"
をやりたんですが、出来ない。
manga_osyo:
function! Check1()
return 1
endfunctionfunction! Check2()
return 1
endfunctioncommand! -nargs=* Checker if
| throw "ERROR" | endif
Checker Check1()
Checker Check2()こうするのが楽かなぁ。ただし、スクリプトローカル関数は使えないけども
もしくは
function! s:throw(exp)
throw a:exp
endfunctionlet _ = Check1() && s:throw("ERROR")
let _ = Check2() && s:throw("ERROR")
とか書くのは前者の方が楽、使い勝手は後者の方が楽
後者なら
function! s:checker(check, ...)
let expr = get(a:, 1, "ERROR")
if a:check
throw expr
endif
endfunctioncall s:checker(Check1())
http://lingr.com/room/vim/archives/2013/11/03#message-17268353
call s:checker(Check2(), "ERROR Check2")
の方が楽そげ感
Lindan:
スクリプトローカルなコマンドが定義できれば ThrowIf {condition} みたいなコマンドを自作するのも良さそうだけれど…コマンド名,グローバルにしか定義できないので,他のプラグインとかぶらないようにしないといけないのが辛いですね…
http://lingr.com/room/vim/archives/2013/11/03#message-17268374
t9md:
http://lingr.com/room/vim/archives/2013/11/03#message-17268401
これまでは、if cond | hoge | endif を一行にして、Alignしてたけど。
後者もいい。 osyo さん、サンクスです。
便利メモにメモっとこう。
そもそもの目的は、textmanip でもうやることがない(動かせない)ときのチェックをスッキリ書きたかった。
https://github.com/t9md/vim-textmanip/blob/master/autoload/textmanip.vim#L154-L173
http://lingr.com/room/vim/archives/2013/11/03#message-17268438
コマンドを使った方法を経て
最終的にこうなっていました(結局関数を使った方法に)
isは型の違いも見る
manga_osyo
http://lingr.com/room/vim/archives/2013/11/03#message-17267099
echo 0 ==# "homu" => 1 になってつらぽよ…
Lindan
http://lingr.com/room/vim/archives/2013/11/03#message-17267119
リストで包んで,[0] ==# ["homu"] ならちゃんと型チェックされます(バッドノウハウ)
thinca
http://lingr.com/room/vim/archives/2013/11/03#message-17267133
is 使いましょう
Lindan
http://lingr.com/room/vim/archives/2013/11/03#message-17267137
ですね,is があった
thinca
http://lingr.com/room/vim/archives/2013/11/03#message-17267156
is は型の違いも見る
ウィンドウを分割させて新しいバッファを表示させる系のコマンドを含む関数内での: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をお試し下さい。