2008/01/31


色んな人のvimrcを見ていて意外とmapされていないのがこの技。
元はと言うとKoRoNさんから教えて貰った技で、先日公開した私のvimrcにも入っています。
" expand path
cmap <c-x> <c-r>=expand('%:p:h')<cr>/
" expand file (not ext)
cmap <c-z> <c-r>=expand('%:p:r')<cr>
これを使って例えば # vi /path/to/file/file.txt
type some text...
:pwd
/path/to/file
な状態で、ファイルのある場所にカレントディレクトリを移したいならば :cd <C-X>  <= Ctrl押しながらX とコマンドモードで<C-X>をタイプすれば :cd /path/to/file/ と補完されます。あとはENTERで移動。
結構便利だったりします。またコマンドモードで<C-Z>とすれば編集中のファイルへの絶対パスに補完されますので、例えば編集中のHTMLファイルをFirefoxで確認したいならば :!firefox-remote <C-Z>ENTER で簡単に確認出来ます。書きはじめたjavascriptを試すにはいいですね。
※Windowsの場合はvimrcで「set shellslash」してあり、かつfirefoxまでのパスが通っている状態ならば「:!firefox <C-Z>」で行けるかもしれません。(確認してません)

応用として、例えばまだインストールしていないGreaseMonkeyスクリプトをvimで閲覧/編集中に「:!firefox <C-Z>」すれば簡単にインストール出来てしまいます。UN*XユーザでいちいちファイラからFirefoxにjsファイルをドロップ...なんてメンドクサイですよね。特にcoderepos等のCVS/SVNリポジトリでグリースモンキーを見つけ中身をvimで確認してすぐさまインストールしたい!なんて時には大活躍です。
おそらく他にも使い道は沢山あるかと思います。
皆さんもvimrcに加えてみては如何でしょうか。
Posted at by




昨日の記事「Publish::Jaikuをでっちあげた」でご紹介したソースコードは、最終的にはCodeReposにcommitする事にしました。
で、その際CodeReposのトップページで読んだコミットルール
Commit messege rule
svn ci -m "lang/LanguageName/BigProjectName: Commit messege."
svn ci -m "lang/LanguageName/misc/ScriptName: Commit messege."
svn ci -m "dotfiles/SoftwareName/Username-Filename: Commit messege."
を守ってcommit時にファイル名を一覧しました。
で、悩んだのが複数のファイルをcommitする場合。
色々な人のcommit logを見てたら、皆さん lang/LanguageName/BigProjectName,
lang/LanguageName/misc/ScriptName,
dotfiles/SoftwareName/Username-Filename:
  Added.
といった書き方をされていました。
でもこれってU*NIXなら"pwd"して、コピれば簡単ですが、Windowsの場合は"¥"になったり、部分的にチェックアウトしている場合には"pwd"で取得出来るものはなかったりと不便だったりします。
で、なんか楽出来ないかなと思いまして今回はこのcommit対象ファイル一覧を"svn commit"時のコメントとして出力してくれるvimscriptをご紹介します。
※というか、さっき作りました。

仕組みとしては、"svn info"を実行すると出力される
URL : http://host/root/path/to/dir
Repository Root : http://host/root
という部分の2行の差、「path/to/dir」を取得し、svn commit実行時にエディタに表示されている
--This line, and those below, will be ignored--

A    docs
A    docs/file1.txt
A    docs/file2.txt
A    docs/file3.txt
のファイル名部分の先頭に上記フォルダ「path/to/dir」を付与し path/to/dir/docs,
path/to/dir/docs/file1.txt,
path/to/dir/docs/file2.txt,
path/to/dir/docs/file3.txt:
というコメントを生成します。
あとはこれをFileTypeがsvnの場合に動作するようにautocmdを作ればsvn commit時に
path/to/dir/docs,
path/to/dir/docs/file1.txt,
path/to/dir/docs/file2.txt,
path/to/dir/docs/file3.txt:
 
--This line, and those below, will be ignored--

A    docs
A    docs/file1.txt
A    docs/file2.txt
A    docs/file3.txt
という画面が現れます。カーソルも":"の次の行に移動しますので、そこからコメントを書くと事が出来ます。
ツールは横着から生まれる物ですね!

vimscriptのコードは以下の通り
"=============================================================================
" File: svn_file_comment.vim
" Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
" Last Change: Fri, 12 Oct 2007
" Version: 0.1
"-----------------------------------------------------------------------------
" when editing comment for 'svn commit',
"  it append svn comment like following
"
"   root/path/to/dir/docs,
"   root/path/to/dir/docs/file1.txt,
"   root/path/to/dir/docs/file2.txt,
"   root/path/to/dir/docs/file3.txt:
"   <= cursor
"   --This line, and those below, will be ignored--
"   A    docs
"   A    docs/file1.txt    
"   A    docs/file2.txt    
"   A    docs/file3.txt    
"-----------------------------------------------------------------------------

function! AppendCommitFiles()
  let lstart = search("^--", "n")
  let lend = line("$")
  if line(".") > 1 || lstart != 2
    return
  endif
  let oldlang=$LANG
  let $LANG="C"
  let lines=system("svn info")
  let $LANG=oldlang
  let url=substitute(lines, '.*\nURL: \([^\x0A]*\).*', '\1', '')
  let root=substitute(lines, '.*\nRepository Root: \([^\x0A]*\).*', '\1', '')
  if match(url, root) != 0
    return
  endif
  let basedir=substitute(strpart(url, strlen(root)), '^\/*', '', '')
  let lcur = lstart
  let lines = ""
  let mx = '^\s*[A-Z]\s\+\([^$]\+\)$'
  while lcur <= lend
    let line = getline(lcur)
    if line =~ mx
      let lines .= basedir."/".substitute(line, mx, '\1', '')."\<NL>"
    endif
    let lcur = lcur + 1
  endwhile
  let lines = substitute(lines, '\n.', ',&', 'g')
  let lines = substitute(lines, '\n$', ':&', '')
  call cursor(0)
  let value = getreg("a")
  let type = getregtype("a")
  call setreg("a", lines, "c")
  execute 'normal! "ap'
  call setreg("a", value, type)
  silent! /^$
endfunction
autocmd FileType svn call AppendCommitFiles()
例によって、このソースもCodeReposのコノ辺に置く予定です。

追記
ちょこっと修正
Posted at by




vimを使っていて開いているバッファ全てからあるキーワードを検索したい場合、「vimgrep」コマンドを使っています。開いているファイルの拡張子を指定して :vimgrep /sometext/ *.c *.h
と実行したり、実際開いているファイル名を羅列したりする事があります。検索結果の一覧もクイックフィックス「clist」で確認出来ます。
でもこれだと保存していないと結果に現れませんし、幾ら拡張子で絞っても余計なファイルがマッチしてしまう可能性があります。

今日のtipsはvim-dev MLに流れたスレッドからご紹介

「vimgrep」を実行するとクイックフィックスが作成されますが、このクイックフィックスに検索結果を追加する「vimgrepadd」というコマンドがあります。
これを全てのバッファに対して実行するように「bufdo」コマンドを絡めます。
:bufdo vimgrepadd /sometext/ %
なるほどね...

ちなみにスレッドの中で「クイックフィックスをクリアするには単にcexpr ""でいける」とBram Moolenaar氏が書いてます。

見えてるバッファだけで実行する場合は「bufdo」の代わりに「windo」が使えますね。
Posted at by