hg commitを実行すると、コミットメッセージを編集するためのエディタが起動します。
このエディタにvimを使う場合に、いくつかの設定を行うことでプラスアルファの機能を追加しようという話です。
ありていに言うと committiaがすてきな感じなのでMercurialでも同じようなことができないか、という。
コミット対象のファイルを開く
そのまま開く
コミット時には、以下のようなテキストが一時ファイルに出力され、オープンされます。
HG: コミットログを入力してください。'HG:' で始まる行は無視されます。
HG: メッセージが空のままならコミットを中止します。
HG: --
HG: ユーザ: Iwata
HG: ブランチ 'default'
HG: tortoisehg/hgqt/repotreeitem.py を変更
HG: tortoisehg/hgqt/run.py を変更
このように、コミット対象のファイルがテキスト上に最初から表示されているので、そこにカーソルを合わせて <C-w>f
、<C-w>gf
などとすることで簡単にそのファイルを開くことができます。
が、カレントディレクトリがリポジトリルートになっていないとこれは使えません。
Mercurial自体はリポジトリルートをカレントディレクトリに設定した状態でエディタを起動してくれるのですが、Windows版のvimだと、ファイルパスを引数に与えて起動した場合カレントディレクトリがそのファイルの親ディレクトリに変わってしまうようです。
なので、この挙動を回避するために、vim/gvimを直接起動する代わりにこんな感じのバッチを起動するようにします。
gvim -c ":e %1"
unified diffを開く
以下のようなfunctionを用意して、ファイルパス上での ;d
でunified形式のdiffを表示できるようにします。(同じタブ内でウインドウを分割して表示します)
" カーソル下のファイルに対するdiffをunified diff形式で表示
nmap <buffer> ;d :call ShowHgDiffUnified(expand('<cfile>'))<CR>function!s:find_window(pattern)foriin range(1, winnr('$'))if bufname(winbufnr(i))=~a:pattern
returniendifendforreturn0endfunctionfunction! ShowHgDiffUnified(path) abort
letwin=s:find_window('^\[hg diff\]')ifwin==0botrightvnewelse
execute win . 'wincmd w'endifsetlocalfiletype=diffbuftype=nofile modifiablesilent! %delete
silent! execute 'file [hg diff] ' . fnamemodify(a:path,':t')silent! execute 'r!hg diff ' . a:pathsetlocalnomodifiableendfunction
- この辺のvimscriptはMercurialのコミットメッセージを編集する時だけ読み込まれればいいので、起動用バッチで
gvim -c ":e %1" -S hgcommit.vim
みたいに指定するか、autocmd FileType hgcommit
に引っかければいいと思います。
side by side diffを開く
さらに以下の設定で、同じく ;D
で別タブにvimdiffを表示できるようにします。
" カーソル下のファイルに対するvimdiffを新しいタブに表示
nmap <buffer> ;D :call ShowHgDiffSideBySide(expand('<cfile>'))<CR>function! ShowHgDiffSideBySide(path) abort
execute 'tabedit ' . a:pathletencoding=&encodingvnewsetlocalmodifiablebuftype=nofile
execute 'setlocal fileencoding=' . encodingsilent! execute 'file ' . fnamemodify(a:path,':t')silent! execute 'r!hg cat ' . a:pathsilent!1delete _
execute 'doautocmd BufNewFile ' . a:pathsetlocalnomodifiablewindodiffthisendfunction
コミットメッセージの挿入
GUIクライアントだと、最近入力したコミットメッセージを一覧から選択して挿入する機能があったりします。
正直あまり使いませんが、せっかくなのでこれもUnite sourceとして実装しておきましょう。
" 最近のコミットメッセージを表示するUnite sourcelets:unite_last_messages = {
\ 'name' : 'last-messages',
\ 'default_action' : { '*' : 'insert' },
\ }
function!s:unite_last_messages.gather_candidates(args, context) abort
let log = system('hg log -r "last(all(), 20)" --template "{desc}\n___SEP___\n"')let encoded = iconv(log,'cp932',&encoding)let splitted = split(encoded,'\n___SEP___\n')return map(splitted, '{
\ "word": split(v:val,"\n")[0],
\ "source": "last-messages",
\ "kind": "word",
\ "action__text": v:val,
\ }')endfunctioncall unite#define_source(s:unite_last_messages)
unlet s:unite_last_messages
nmap <buffer> ;m :Unite last-messages<CR>
これは単純に最新20コミットを対象にして検索する例ですが、「authorが自分」などの条件を加えてもいいかもしれません。
Windows + win32mbcs環境を前提にしているので文字コード変換(iconv)をかけていますが、Linux環境でvimのencodingもutf8ならこれは不要です。
TODO
commit --amendへの対応
diffの機能がcommit --amend時には無力なので、そこを何とかする。
と言ってもエディタ側からは通常のコミットなのかamendなのかは分からないので、両方のモードを用意して手動でスイッチする感じ?