Category Archives: vim

vim

vimでカーソルの下にある単語をgrepする

ハタさんのブログ : vimのgrep(vimgrep)が素晴らしすぎて泣いた。で検索するのはいいけど、検索する単語をいちいち入れるのはいやなので * みたいにカーソルの下の単語を入れたくて調べた。

たぶん難しくて覚えられない。

コマンドラインでCtrl-R Ctrl-Wを入れると、カーソルの下の単語が入力されることになっている(Tip #305 – Best of VIM Tips (VIM’s best Features) : vim onlineより)。

なので

:vim 

まで入れてCtrl-R Ctrl-Wを入れて

:vim setAttribute * | cw

なかんじ。

検索結果のウインドウはQuickFixと呼ばれていて、いろいろコマンドがあるんだけど(Vim documentation: quickfix)検索結果の各行の上でEnter(Ctrl-M)を2回押せばジャンプしてくれる。

けどctagsが使えるならそれでいいんじゃないのかこれ。jsだとctagsがうまく動いてくれないので(新しいやつは動くっていうのを読んだ気もするけど試してない)grepしてるだけで。

vim set ambiwidth=double

HTMLとかを編集しているときに、中に☆とか※とか入っているとvimが半角なのか全角なのか扱いに困ってそれより右側の文字でカーソルの位置と表示が一致しなくなったりする。そんなに困らないけど煩わしいなーと思っていたのですが

Emacs22 + UTF-8 における文脈依存な文字幅の問題についてのコメントで

vimでは、set ambiwidth=double でいけませんか?

と書かれているのを見つけてやってみたら※問題解決しました。うれしいです。

vimでファイルの種類判別ルールを追加する

.jslibというsuffixをjavascript扱いしてほしくて調べたことのメモ。
そういえばずーっと前に.hdmlをhtml扱いで色を付けてもらうために ~/.vim/filetype.vim にコマンド書いてた。いまVim documentation: filetypeを読んだら

ファイル$VIMRUNTIME/filetype.vimは変更するべき
ではない。そのファイルは新しいVimをインストールする際に上書されるのだから。

って書いてあったのでやめる。vim7にしたときにこのファイルが上書きされたかどうか覚えてないけど、上のページに書いてあるたくさんの解決策の中から最も安易そうな .vimrc

au BufRead,BufNewFile *.jslib            set filetype=javascript

って書く方法で解決。

vim用窓使いの憂鬱ルール追加

splitしたウインドウ間をAlt-↑/↓で行き来できるように。

window VTWin32 /ttermpro\.exe/ : Global
key A-Right = C-RightSquareBracket C-N
key A-Left = C-RightSquareBracket C-P
key A-Up = C-W K
key A-Down = C-W J

上2つはscreen用です。screen入門参照。screenはあんまり活用してないけど、わりと使うようになりました。

うーん、これかなり不便。切り替えたいタイミングはコード書いてるときなので、↑/↓に手を持ってくのは煩わしい。

vimのmapとmap!の違い

screen再挑戦中。今回はscreen使ってるというよりも、単にscreenをttsshのタブ代わりに使っているだけなので定着しそうです。そういえばzshもとりあえずtcshと同じことができればいいやレベルでスイッチしてそこから全くレベルあがってない。

スイッチしたらvimで検索文字列のヒストリが↑↓で出てこなくなったのでいろいろ調べて(Ctrl-P/N使えっていうのは勘弁してください)

map!    ^[[A    <Up>
map!    ^[[B    <Down>
map!    ^[[C    <Right>
map!    ^[[D    <Left>

っていうのを追加して解決。↑↓で出てくるようになりました。

マップコマンドとモードの対応表 によると、mapとmap!でマッピングが有効になるモードが違うそうで、全面的に全部のモードでマップしたかったら両方書かないとダメっぽい。自分はテンキーもわりとつかうんだけど、テンキー使うとvimが変になったりして困ってたのでwindowsのキーマップ変えて対処してた。今後はmapとmap!で対処しよう。

vim7.1 released

vimが1年ぶりにアップデートされたそうです。vim.org からたどっていくとなぜかアナウンスが yahoo groups にありました。

vimannounce : Message: Stable Vim version 7.1 has been released

newsのページには

There are many bug fixes and updated runtime files. No amazing new features. Upgrading from a previous version is highly recommended: a few crashing bugs and a security issue were fixed.

バグがいろいろ直ってるからアップグレードしてねって書いてありました。

問題なく動いているのをアップグレードするのはめんどくさいので、いままでもとも入っているvim6.2を使い続けていたOSXにソースからインストール。

./configure -prefix=$HOME/bin/vim71 \
-enable-multibyte -without-x -disable-gui -disable-gpm \
-enable-cscope -enable-ctags -with-features=big -enable-perlinterp \
-enable-rubyinterp -enable-pythoninterp

変わったところは :help version-7.1 で見てねって書いてあるので見てみましたが、たしかにたくさんの bug fix があって、ほかには syntax file や indent file が追加がされているだけみたいです。

RoRの15分ムービーで使われているTextMateのsnippetsもどきなvimプラグインsnippetsEmu

Ruby on Rails の15分ムービーで使われている、ハイテクないまどきのOSXのGUIのエディタ TextMate の補完機能はいいなーとおもっていたところで おぎろぐはてな – (PHP)プログラマのためのVIM (11) – PHP向けカスタマイズ(3) Andreiがつかってるプラグイン(Andreiはvimを作っているひとです)の中に

TextMate(mac用のエディタ)のSnippets機能のいくらかをエミュレートしてくれます

というのがあるのを見つけて、試してみなければと思いつつ放置していたのをようやく試しました。英語でも日本語でもあんまり情報がなくて、動くようになるまで苦労しました。

なにができるか
いろんなモードでインテリジェントないろんな補完が可能です。
とりあえずHTMLモードの場合
doc4t<TAB>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

に展開されたり、script<TAB>

<script type="text/javascript" language="<javascript>" charset="">
// <![CDATA[
<{}>
// ]]>
</script>

に展開されたりします。

そんな単純な展開だけでなく、textarea<TAB>

<textarea name="_" rows="<{}>" cols="<{}>"><{}></textarea>

と補完されて、さらにname=""の部分にカーソルが移動します。nameを入力してTABを押すと、次はrowsの入力になり、もう一度押すとcolsの入力になって、もう一度押すと</textarea>の後ろにカーソルが移動してくれるので、ちょっと楽ができます。perlであればclass<TAB>で、パッケージのコンストラクタに展開してくれたり、というようなのが言語別にはじめからいくつか定義されていて、もちろん自分で定義することもできます。

自分で定義するときは、展開ルールを vim script で細かく記述できるので、入力された値を加工して出力する、ということもできます。(vim scriptが書ければですけど)

インストール
snippetsEmu – An attempt to emulate TextMate’s snippet expansion : vim online から version 1.1 をダウンロードしてきます。
拡張子が .vba なのでWindows専用?と思ったのですが、これは VimBAll の略だそうで、この拡張子のプラグインは、

vim snippetsEmu.vba
:source %

でインストールすることができます。はじめて知りました。
そうそう、snippetsEmuはvim7でないと動かないらしいので、いまどき古いvimを使っていたら新しいのにかえる必要があります。

.vimrcの設定
デフォルトではTABで補完されるようになっています。
もとのAndreiの資料では”TABだとうざいからリマップしようね”って書いてあるけど、書いてある通りに

if exists('loaded_snippet')
    imap <C-B> <Plug>Jumper
endif

するとなぜか^Bが入力されるだけなのでTABのままで使っています。

はじめ、いくらTABを押しても何の反応もなくて困っていたら ~/vim/doc/snippets_emu.txt

SNIPPETSEMU TROUBLESHOOTING                     *snippets_emu-troubleshooting*

Problem:    Bundles are not loading.
Answer:     Ensure that you have filetype plugins turned on. Include the
            following in your vimrc: <>

                filetype plugin on

と書かれていました。
なので、書いてない場合 .vimrc に

filetype plugin on

を付け加えます。もっと目立つところに書いてほしかった….

snippetsEmu.vimの修正
TABを押すと確かに補完されるようになったものの、はじめに入れた展開用のキーワードが削除されないまま残った状態になりました。doc4t<TAB>と入力すると

doc4t<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

になっちゃいます。

これだとめっちゃ不便なので、読めないながらも vim script を追ったところ
snippetsEmu.vim の

    " if this is a mapping, then erase the previous part of the map
    " by also returning a number of backspaces.
    let bkspc = substitute(origword, '.', "\<bs>", "g")
    call <SID>Debug("Snippy: Backspacing ".<SID>StrLen(origword)." characters")

の部分で bkspc に、キーワードの文字数ぶんBackSpaceが入って

 return "\<Esc>:set paste\<CR>a".bkspc.delEndTag.initial.rhs."\<Esc>:set nopaste\<CR>?".initial."\<CR>".strlen(initial)."xi\<C-r>=<SNR>".s:SID()."_NextHop()\<CR>"

でキーワードが文字数ぶん戻ってキーワードが消えるようになっているはずなのですが、なぜか消えていないのがわかりました。

正しく書き直すには知識がなさすぎるのでとりあえず

@@ -773,7 +773,7 @@
     let rhs = substitute(rhs, "\<CR>", "&".tab_text,'g')

     call <SID>Debug("Snippy: ---------------- End of Jumper ----------------")
-    return "\<Esc>:set paste\<CR>a".bkspc.delEndTag.initial.rhs."\<Esc>:set nopaste\<CR>?".initial."\<CR>".strlen(initial)."xi\<C-r>=<SNR>".s:SID()."_NextHop()\<CR>"
+    return "\<Esc>:set paste\<CR>bcw".delEndTag.initial.rhs."\<Esc>:set nopaste\<CR>?".initial."\<CR>".strlen(initial)."xi\<C-r>=<SNR>".s:SID()."_NextHop()\<CR>"
   else
     " No definition so let's check to see whether we're in a tag
     if <SID>CheckForInTag()

にしたら、補完時にキーワードがちゃんと消えるようになりました。

というわけで vim7ユーザ定義補完関数を使ってみる でうまくいかなくてあきらめていたvimでの任意文字列補完ができるようになったのでうれしいです。

vimでPHPの === と !== をハイライト表示させる

I’m sorry, but PHP sucks! にPHPのいまいちなところがたくさんあげられていて、その中に

Now that’s just nasty. Please note the explicit casts. Even in a dynamically-typed language this shouldn’t happen, because you’ve just explicitly “statically-typed it”. Of course the opposite of this flawed creation also evaluates to true: (boolean)false == (string)”0″.

というのがありました。なんとPHPでは (boolean) false == (string)"0" がtrueとして評価されるそうで…. 知らずに使っていました。それはいかにも泥縄な感じで ===!== という、厳密に同じかどうかを比較する演算子(PHP: 比較演算子)があるので常に ===!== を使えばいちおう解決です。

そうすると今度は (int)0 === (stirng)"0" がfalseになったり (booelan)false === (int)0 になったりしていろいろ不便になって

This means: if you want to predictably compare two variables and you don’t control their input range (i.e. one of them contains user input, for example), you have to compare them by identity, but then you have to explicitly convert them, not typecast them. So, in this context, PHP suddenly is not a dynamically typed language anymore. What’s not to love?

と書かれている通り、ぜんぜん動的型付け言語じゃなくなってjavaのコンパイラおばさん状態に。

それよりなにより ===!== はvimで色がつかないので、まずは色を付けましょう。
ふつうに ~/.vim/syntax/php.vim に書くとなぜか色がつかないので調べていたら 既存の文法ファイルへの追加~/.vim/after/syntax/ に置きましょうという記述が。これに従って ~/.vim/after/syntax/phpvim を作って


syntax  match phpRelation "[!=<>]==" contained display

と書いたら === !== にも色がつくようになりました。

falseとか0の話で思い出したけど ホワイの(感動的)Rubyガイド :: 4. 浮いている小さなコードの葉っぱ を読んでてrubyのifは、評価した式が nil か false 以外のときにブロックを実行する、っていうのもはまりそうだと思った。nil か false 以外のときなので式の値が0の時は実行される。難しいなあ。

vim7ユーザ定義補完関数を使ってみる

vim7の売りのシンタックスハイライティングはホーリーにいろいろ助けてもらって


autocmd FileType php  :set omnifunc=phpcomplete#CompletePHP
autocmd FileType html,javascript :set omnifunc=javascriptcomplete#CompleteJS
autocmd Filetype *
        \\   if &omnifunc == "" |
        \\       setlocal omnifunc=syntaxcomplete#Complete |
        \\   endif
endif

と書いておけばいいのがわかったので、もうひとつ?の売りであるユーザ定義の補完関数をいじってみた。
補完のルールを自分でかけるので、日頃からテスト用のコードを書くために <html といれてタブを入れると <html ….</body> まで補完してくれるとか、 <meta とタブで <meta http-equiv=”content-type” content=”text/html; charset=utf-8″ /> と入るとか、へんなスクリプトをたくさん用意していたのを全部きれいに書き直せるかと思って。(sdnとタブで style=”display: none;” に展開するのようにしているのがちょっとすき)
foo.vimを参考にベタベタに書いていたので、これをユーザ定義の補完を使ってかたづけられるとうれしい。

ドキュメントの *complete-functions* を参考にして vim script はまったく知らないけど見よう見まねで、
vimスクリプトを書くExpression evaluationを参考にいじってみた。
オプションでshowmatchを設定していると、<> の対応を表示してくれちゃってクソ遅くなるので一時的に外したの以外は vim script の文法を知っていればさくっとできるんでしょうけど知らないのでちょっと大変でした。


fun! UserdefinedCompletionFunc(findstart, base)
  if a:findstart
    " locate the start of the word
    let line = getline('.')
    let start = col('.') - 1
    while start > 0 && line[start - 1] =~ '\a'
      let start -= 1
    endwhile
    return start
  else
    " find months matching with "a:base"
    let bk = &showmatch
    set noshowmatch

    let res = []
    let ar = [
\ "html>  \\n\\n\\n\\n",
\ "script type='text/javascript'>\\n",
\ 'meta http-equiv="content-type" content="text/html; charset=utf-8" />',
\ 'style="display: none;"'
\ ]
    for m in ar
      if m =~ '^' . a:base
    call add(res, m)
      endif
    endfor
    let showmatch = bk

    return res
  endif
endfun

これで ht とか html とか入れて C-X C-U で html….</body> が補完されるようになりました。
が、どうしても改行を入れることができません。ダブルクオートの中に \n と書けば改行が入ると書いてあるけれど、\x00が入ってしまって改行されません。\<Enter>と書いてみてもダメだしもうお手上げ。
誰か助けて!

vimで対応するHTMLタグへのジャンプ

知らぬは己ばかりなり!

HTMLを編集している時に必要なことと言えば、絶望的にネストされているタグがどこと対応しているのか、わからせてくれること。ふつうにコードを書いているときに % を押すと対応するかっこにジャンプしてくれるのと同様、HTMLタグでも対応しているとこ ろにジャンプしてくれればいいのに! と思うのが普通。

それをやってくれるのが xml.vim で、これをダウンロードしてきて ~/.vim/plugin/ に入れるとHTMLタグのところにカーソルがある状態で ¥% と入れると、対応するタグにジャンプするように! 当然ネストされているタグがあっても正しくジャンプしてくれます。
ただ ~/.vim/plugin/ に入れると、ファイルタイプに関わらず毎回ロードされて気持ちが悪い。HTMLやPHPの時だけロードされるように ~/.vim/scripts/ にxml.vim を置いて .vimrc に

autocmd FileType html,php,xml :source ~/.vim/scripts/xml.vim
と書くことで、 html, php, xml ファイルの時だけロードされるようになります。ただpluginに置くものを無理矢理動かしているので、よくみると /doc にディレクトリが作れない、とかと言うエラーが出ています。 困らないけど気になるので xml.vim をみると、

execute l:mkdir_cmd . l:vim_doc_path

というあたりでこのエラーが出ているのですが、これだけコメントアウトするとほかでエラーがでるようになるので

if (!(filewritable(l:vim_doc_path) == 2))
  ...
endif

の部分をまるごとコメントアウト。これでエラーは出なくなりました。

あとは % が < と > にも対応してくれるようになるという
set matchpairs=(:),{:},[:],< :>
も書いてみたけど便利なのか不明。まだ使ったことない。

2006.2.24補記
このxml.vimですが、単純なHTMLだときちんとジャンプできるものの、複雑になるとジャンプできず。実用には堪えませんでした。