Vim: <SID>とs:の使い分け

2008-06-30T07:08:00 / vim / comment

Vimの関数呼び出しでは場合によって<SID>s:を使い分けする必要があるが、実はどのケースであっても<SID>を使えば動くには動く。ただ<SID>というプレフィックスはs:に比べて見辛いため、できればs:を使いたい。ではどの場合にどちらを使うべきか。答えは以下の通り:

s:
:autocmd:command:function/:endfunctionの中で使う(推奨 - <SID>でも動くには動く)。
<SID>
:map系か:menu系コマンドの中でのみ使う(必須 - s:では動かない)。

Vimのカスタマイズに手を出し始めた頃は何故このような使い分けが必要なのか分からなかったが、今、この記事を書いていて思い付いた。:map及び:menuの定義時に与えられた{rhs}だけでは、その中に出現するs:の意味・用途を正確に判定することができないからだ。例えば以下のような定義があったとして:

nmap =x  =:=call=func=return
nnoremap =:  :
cnoremap =call  call<Space>
cnoremap =func  s:func()
cnoremap =return  <Return>

=func{rhs} s:func()は、=xから実行された場合には<SID>func()として扱ってほしいが、それ以外のケースではそのままs:func()と扱うべきなのかどうか判断できない。だから明示的に<SID>を用いる必要があるのだ。

またMacBookがブラックアウトした

2008-06-29T16:09:00 / mac, diary / comment

またMacBookがブラックアウトしました。先月にMacBookのブラックアウト現象について書いてから久々に発生しました。今回は、というか今回もスリープ中にiPodを外した後の復帰時に発生しました。やはりスリープ中のUSB機器の取り外しが原因なのでしょうか。

ただ気になるのは、今回のブラックアウト以前にもスリープ中にiPodを外したことが何回かあり、そのときにはブラックアウトしなかったということです。iPod取り外し以外で気になることと言えば、今回のブラックアウト発生のスリープ前、iPodの接続時にエラーが発生したことです。でもそのエラーは今まで2回しか経験したことがなく、それに比べればブラックアウトの回数は多いので、関係あるのかないのか。後はiPodを取り外したタイミングくらいしか思い付きません。今回はスリープさせてから取り外すまでの間がいつもより短かったのです。でもこれも関係あるのかないのか。

ううむ、何が何やら。

追加情報: 実稼働時間が9日程でした。いや、あまり関係ないかな。

git-{subcommand}は非推奨だった

2008-06-29T15:55:00 / git / comment

なんとなくgitのリリースノートを見ていて気付いたのですが:

From v1.6.0, git will by default install dashed form of commands (e.g. "git-commit") outside of users' normal $PATH, and will install only selected commands ("git" itself, and "gitk") in $PATH.

という訳でgit-{subcommand}は非推奨のようです(それも2006年の早期から)。確かに他のバージョン管理システムと比べて変だとは思っていましたけど。でも、元々どういう理由があってあの形式にしていたんでしょうね?

Vim: 若かりしあの頃(Re: vim で任意のオプションの有効・無効を切り替える)

2008-06-29T01:50:00 / vim / comment

先日、大昔に書いた「vim で任意のオプションの有効・無効を切り替える」にはてなスターが付いていて吹いたのですが、改めて記述内容を見直してさらに吹きました。これはひどい。真似したり参考にしたりしては駄目ですよ! 4年越しの今、修正をするとしたら以下のような感じになります:

function! s:toggle_option(option_name)
  execute 'setlocal' a:option_name.'!'
  execute 'setlocal' a:option_name.'?'
endfunction

nnoremap <silent> \  :<C-u>call s:toggle_option('wrap')<Return>

しかし当時の自分に「何故こう書くべきか」を理解しろというのは少々重荷、かなぁ。一つ一つは大したことではないのだけれど、それら全てを把握しておけというのは難しいです。しかもこの手の知識は:helpに明記されていませんし。だから皆で共有して全体のレベルを底上げできれば良いのではないかと思いました。具体的に言うとvimグループのキーワードなんか使うと良いと思います。さああなたも今すぐ参加! ただいま全手動Vim script修正キャンペーン中です(宣伝)

Vim: 7.2aで一部のVim scriptがエラーになる原因、あるいはVim scriptがいかにカオスであるかの一例

2008-06-29T01:40:00 / vim / comment

Vim 7.2aでFloat (浮動小数点数)がサポートされたのですが、これが原因で一部のVim scriptでエラーが発生します。既に修正パッチはリリースされているのですが、それを見て吹きました。

Patch 7.2a.007 
Problem:    ":let v = 1.2.3" was OK in Vim 7.1, now it gives an error. 
Solution:   Don't look for a floating point number after the "." operator. 
Files:      src/eval.c

ああ、そういうことか。そりゃそうだわ。別にこれに限らず、Vim scriptは微妙なレベルでどうパースされるのか分からないケースがあります。私がよく遭遇する例としては以下のようなものがあります:

let foo = 'echo'

execute foo (1 + 3)      " Error, treated as calling a function "foo"
execute foo ' ' (1 + 3)  " Okay

:executeの引数はいちいち文字列結合の演算子(expr-.)を使っていると見難くなるので前者のスタイルに統一しているのですが、上記のケースだと関数呼び出しとしてパースされてしまいます。他にはDictionary-function関連でパース結果が変わるケースもあります。この辺は何と言うか、Vim scriptのカオスな面が表れていますね。

元々Ex commandsは対話用途の代物なので、それを無理に拡張して今の(言語としての) Vim scriptに進んだことは間違ってます。vi cloneから出発し、拡張のための言語を搭載しようとする場合、Ex commandsをベースにするのは一つの選択肢として考えられなくはないのですけどね。

Vim: flydiff 0.0.1 has been released

2008-06-29T01:10:00 / vim / comment

Vim plugin flydiff has been released. This version includes many minor bug fixes.

Vim: getbufvar(bufnr, '')の戻り値が間違っている

2008-06-26T10:26:00 / vim / comment

vim-flydiffを書いている最中に気付いたのですが、getbufvar(bufnr, '')の戻り値が間違っています。変数名を空文字列にすると、バッファbufnrのローカル変数のスコープを表す辞書が返されるべきなのですが、何故か常にカレントバッファのローカル変数のスコープを表す辞書が返されるのです。ソースを見たところ、単純なミスだったのでパッチを書いてvim_devにポストしました。

--- ../vim-7.1.300/src/eval.c  2008-06-26 10:32:40.000000000 +0900
+++ src/eval.c  2008-06-26 10:32:40.000000000 +0900
@@ -9901,16 +9901,13 @@
 
     if (buf != NULL && varname != NULL)
     {
+       /* set curbuf to be our buf, temporarily */
+       save_curbuf = curbuf;
+       curbuf = buf;
+
        if (*varname == '&')    /* buffer-local-option */
        {
-           /* set curbuf to be our buf, temporarily */
-           save_curbuf = curbuf;
-           curbuf = buf;
-
            get_option_tv(&varname, rettv, TRUE);
-
-           /* restore previous notion of curbuf */
-           curbuf = save_curbuf;
        }
        else
        {
@@ -9920,10 +9917,13 @@
                 * find_var_in_ht(). */
                varname = (char_u *)"b:" + 2;
            /* look up the variable */
-           v = find_var_in_ht(&buf->b_vars.dv_hashtab, varname, FALSE);
+           v = find_var_in_ht(&curbuf->b_vars.dv_hashtab, varname, FALSE);
            if (v != NULL)
                copy_tv(&v->di_tv, rettv);
        }
+
+       /* restore previous notion of curbuf */
+       curbuf = save_curbuf;
     }
 
     --emsg_off;

Vim 7.2a.002として取り込まれました。まあ些細なミスの修正で、大したことはなかったのですが、いずれはもっとデカい獲物を仕留めてみたいものです。参考: Patch 7.2a.002 - vim_dev | Google Groups

Vim: flydiff 0.0

2008-06-26T10:13:00 / vim / comment

Vim plugin flydiffをリリースしました。

画面の左半分に編集中ファイルを、右半分にgit-diffの該当部分が表示されたら超便利じゃないかなと思った。

というujihisaさんの発言が元ネタです。このコンセプトを実現するとこんな感じになるというサンプル。

個人的にはgit-diffの実行で画面がちらつくのが嫌ですね(でもこれはどうしようもない)。今のところgit限定ですが、他のバージョン管理システムをサポートしても、それのdiffが遅いとストレスが溜まるのではないかと思われます。そういう意味ではgitは良いですね。

Vim: narrow: 同一バッファを異なるウィンドウで別々に:Narrowしたいのだけど

2008-06-25T02:08:00 / vim / comment

同一バッファを異なるウィンドウで別々に:Narrowしたいケースが時々あるので、narrowを修正しようかと思ったのだけど、どうやって実装すればいいかで困った。今のところ、:Widenのための復元情報をバッファ毎に持たせているので(b:narrow_original_state)、それに対して「どのウィンドウで:Narrowされたのか」というキーも含めれば取り敢えずは解決する。ただ、:Narrow済みのバッファを表示しているウィンドウを:splitした場合、新たに作成されたウィンドウが:Narrowされているかどうかが簡単には判別できないし、さらにどのウィンドウを:splitして作られたかが判別できないという問題があるので、完璧とは言えない。そもそも個々のウィンドウはbufnr()のような一意に識別可能な値を持たないので話はさらに面倒になる。

まあ、ウィンドウ(とついでにタブページ)の識別番号については既に対策は用意してあるし、:Narrowされているかどうかの判別も不可能ではないのだけど、:split元の判別はどうしよう。最初は漠然と:autocmd BufEnter等で対処できるだろうと思っていたけれど、そもそもウィンドウがどういう方法(:new:split:tabnew等々)で作成されたのかを判別できないので、不可能だということに気付いた。

と、ここまで書いてて、別に:splitに限らずとも、異なるウィンドウで:Narrow済みのバッファを表示させた場合(例えば:{range}Narrow | new | edit #等)に同様の問題があることに気付いた(さらに言えば同一バッファを表示しているウィンドウの各種オプションやfoldsが異なる場合、新たにウィンドウを作成してそこにそのバッファを表示させた場合、どちらの値が引き継がれるかが不明であることにも気付いた。挙動からして、恐らく最後にアクティブだったウィンドウの値が優先して引き継がれている)。ということは「異なるウィンドウで同一バッファを別々に:Narrowする場合、期待通りの:Widenが行われない可能性がある」で妥協しないと駄目なようだ。まあ、「期待通り」でないと言っても、問題が起こるのは&foldmethod == 'manual'のときだけなので、個人的には実害がなくて済む、かなぁ。

「Software Design 2008年7月号」のVim特集をdisる

2008-06-22T16:45:00 / vim, book, dis / comment

Vim特集があると聞いて「Software Design 2008年7月号」を購入しました。最初は立ち読みで済ませようかと思いましたが、id:taku-oさんが記事を書いていると知ったので、これは買わざるを得ないということになりました。という訳で各記事をdisるとします。

1章 - Vimスクリプト入門 / 吉田佳宏

P143 - ローカル変数
g:s:等の接頭辞のない変数のスコープは文脈によってグローバルかローカルかが変わる
(これは最初から挙げるような話題ではないが)無接頭辞の変数のうち、名前が定義済み変数(v:)と同じものは後者の変数として扱われる。この点はP143の「定義済変数」の節でも触れていない。
本文中の説明では、無接頭辞の変数のスコープは全てローカルであるようにしか読めない。
そもそも何に対してローカルなのかの説明が一切ない(l:は関数内部でのみ有効)。
P144の図3の説明(スクリプトの実行が終了した後も変数の値は記憶されたままです)も踏まえると、著者の理解がどうなっているのか怪しい。
P143 - レジスタ変数
Vimにはレジスタという変数がありよりは「Vimにはレジスタという概念あり、それも変数として扱える」の方が正確。
リスト4の例は:printを使う方が効率的だけど、まあこれはどうでもいいか。
P143 - 配列変数
配列ではなくリスト(List)と記述すべき。同様に連想配列は辞書(Dictionary)と記述すべき。意味は通じなくはないが、不正確な用語を使うと:helpを引く際や他との意思疎通の面で困る。
そもそもこの節は「変数の型」のようなタイトルにすべき。他の説明と比較してここだけ浮いている。
P144 - 比較演算子
説明が不味い。===~等の各種演算子の後に、'ignorecase'に関する挙動の違いで各々3種類あることを書くべき。
P148 - リスト15
記述ミス。autocmd BufRead *.txt call Autosave()でないと動作しない。
P149 - keymapで実行
用語が間違っている。正しくはkey mapping。「keymap」では全く別の機能の'keymap'と混同される。
特殊キーの表記については:help key-notationを参照すること。:help keymap'keymap'についての説明であり、key mappingとは全く関係がない。

2章 - オススメVimスクリプト紹介 / 小見拓

困った。内容的に「nanasi.jp出張版」なのでツッコミを入れる箇所がない。強いて言えば一般的なプラグインのインストール方法について説明があればと思ったが、それは1章の担当ということになるのか。

3章 - VimでPythonスクリプトを徹底活用 / 恩田伊織

全般 - 「Pythonコマンド」
:pythonと記述すべき。
P160 - ワンライナーを実行
実行結果の標準出力先はステータスバーですとあるが、'statusline'と混同される恐れがあるので別の用語を用いた方がいい。ただこれは:helpでの表記がはっきりしていない。強いて言えばコマンドライン(the command-line)と呼ぶべき。
P160 - ヒアドキュメントの実行
構文がシェルのヒアドキュメント風なだけであって、ヒアドキュメントではない。Pythonスクリプトを標準入力からヒアドキュメントとして受け取りますとの記述もあるが、そもそもPython Interfaceで標準入力は利用できない。
P161 - 図16、図18、図21
記述ミス。:pyf[ile]:py[thonと記述されているが、括弧は不要。
P161 - Vimモジュール
モジュール名はvimなので、それに合わせて表記すべき。
vim.command()の説明でVimモードのコマンドを実行しますとあるが、単に「コマンド」ではEx commandのことなのかNormal modeでのコマンドなのか区別が付かない。そもそも「Vimモード」が意味不明。
P162 - 図23
記述ミス。括弧が抜けている。正しくは:call PostTwitter()

最近のデスクトップ @ 2008-06

2008-06-13T18:42:00 / desktop / comment
Real Desktop

最近は左WindowsマシンでBGM(という名のえろげオートプレイ)を流しつつ右のMacBookで何か作業をしていることが多い気がする。デュアルモニターって便利だなー、と思ったり思わなかったり。

ただモニターに関してはMacBook内蔵のものより左のモニターの方が良いので、できればそちらで作業しつつ、右でBGMを流したいのだけど、どうしたものかな。やはりグレア加工は駄目だ。

黒き使者の幻影

2008-06-13T18:38:00 / diary / comment
黒き使者の幻影

いやー、寝起きや薄暗い時間帯だと、この手の黒い箇所という箇所が結構な確率で例の古代昆虫に見えてしまうので、もうなんかつかれた。

AquaSKKがTerminal.appに対してだとしばしばキー入力を取り損ねる

2008-06-07T19:01:00 / mac, software / comment

Terminal.appがアクティブなときにAquaSKKで日本語入力をしていると、キー入力の一部が失われるのか、しばしば意図しない結果になります。よくあるのはhaと入力したつもりがhが落ちてaのみ入力されたことになり、結果としてが入力されるパターンです(別にhaに限らず、あらゆるケースで発生し得る様子)。他には変換を確定したはずが何も入力されないというケースもあります。

今まで使用してきた感じではTerminal.app以外では発症していないため、Terminal.app固有の問題か、あるいはTerminal.app内で日本語入力をするのはGNU screen内で起動しているVimに対してしか行なわないといってもいいくらいなので、GNU screenかVimが原因ということになります。何が何やらさっぱり分かりません。

Vim使いのセンスというか使い方というか

2008-06-07T19:00:00 / vim / comment
:silent bufdo !git-add %

この辺りにVim使いのセンスというか使い方というかが表れていると感じました。id:secondlifeさんはGNU screenでウィンドウをぽこぽこと作っては各々の中でVimを起動して使っているため、こういうコマンドやyanktmpなどのプラグインが有用なのでしょう。

in my terminal

私の場合、Vimのプロセスは常に一つだけ起動しておき、作業内容毎にtab page(と同時に各々のカレントディレクトリ)を分けておき、コマンドラインでの作業が必要な場合は:suspend (実際には別ウィンドウに切り替えた後、適切なディレクトリにcd)しているので、:bufdoなどは使いものになりませんし、yanktmpは役に立ちません。

先日のVim勉強会#2ではこの辺りの認識の違いを目の当たりにして一人で感心していたのですが、それを抜きにしても、他の方がどういう風にVimを使っているかが気になります。「このプラグインはLife Changingだぜ!」とか「このtipsはイケる!」といった話なら腐るほど目にしますが、使い方自体の話となるとほとんど目にしないので。

耳が退化してきた

2008-06-05T21:42:00 / mus / comment

MacBookと同時に購入したiPodのおかげで、昔購入したCDを色々と聞いたりするようにはなったし、iTunesはiTunesでそこそこ便利かなと思いはしたのだけれど、全体として自宅外でiPod+添付されてたヘッドホンで聞く割合が増えたことと、iPodに転送するためリッピングしたデータがlossyなためか、耳が退化してきました。今日は何となくちゃんとしたヘッドホンを装備してCDを直接再生してみたのですが、もののみごとにiPodから流れる音と区別が付かなくなりました。むー。

ある意味では、このまま区別が付かない方が幸せなのかも知れませんが、何か悔しい。

Vim: <C-h>にdelete-backward-charとhelp-commandを共存させられるのはVimだけ

2008-06-01T21:49:00 / vim / comment

先日のKansai.pm懇親会で話したネタその1: EmacsだとC-hにはデフォルトでhelp-command (ヘルプ関連の機能のプレフィックスキー)に割り当てられており、これは色々な意味でありえないのでdelete-backward-charに割り当てなおすことがmy .emacsの記述の第一歩だったりしますが、Vimだと両者を共存させられます。

nnoremap <C-h>  :<C-u>help<Space>

普通、:helpを引く際は:h {subject}と入力しますが、上記の設定を用いて1キーで行なえるようにするとかなり便利です。些細な違いですが:helpを引く機会は結構あるので、長い目で見るとなかなかの効果を発揮します。

Kansai.pm第9回ミーティングに参加しました

2008-06-01T18:50:00 / perl, off / comment

Kansai.pm第9回ミーティングに参加してきました。実のところPerlについては基本的な知識がversion 4止まりで、さらにここ5年くらいはノータッチだったので全速力でアウェーでしたが、各発表の内容にはついていけましたし、なかなか楽しめました。

特に気になったのはid:hakobe932さんのMooseについての発表です。Mooseについては名前程度なら知っていましたが、Class::MOPが存在していて、それのラッパーだということについては知らなかったので、「だからid:typesterさんとかid:cho45さんがMOPがどうこうと発言していたのか」と一人で納得していたりしました。逆にMOPという単語が出てくるまでは「マクロでできる程度のことなのに何故あれこれ騒がれていたのかな」とばかり思っていました。

他の発表については、説明の分かり易さやPerlの文法の変遷や特定の箇所の実装はどうなっているだろうか等と考えながら聞いていました。人によってはid:naoyaさんのMapReduce関連の発表が目的だったのでしょうけど、個人的には結構前にオリジナルの論文を読んでいたので今一新鮮味がなくて残念でした。

懇親会では色々な方とお話をしましたが、特にid:hakobe932さんとお話しました。Vim勉強会#2に来られていなかったというのもありますが、Vimに限らず色々と。特にMac OS Xでデフォルトのウェブブラウザの設定が可能だということを教えてもらったので5回程インクリメントしました(Windows版Operaだと初回起動時にダイアログが出るのですが、Mac版Operaだと出なかったので、これはSafariを使えというAppleの陰謀なんだろうなぁ、と今まで結構不便な思いをしていました)。

参加前はPerlを知らないと辛いだろうかと思っていましたが、全然そんなことはなかったですし、普段なら全然接触のない方達と色々とお話できたので十分楽しめました。

Vim勉強会#2に参加しました

2008-06-01T16:42:00 / vim, off / comment

Vim勉強会#2に参加してきました。Vimを使いこなしたいと頑張る人からVimに取り憑かれた病人まで、とにかくVimについて並々ならぬ思いを抱いた人達が集合していました。参加人数は13名。なかなかに充実したイベントでした。

前半 - extreme reading

前半はテキストである「Vi IMproved - Vim完全バイブル」の8章から13章までをextreme readingしました(GUI版限定の解説である10章は除外)。実のところextreme readingは未経験でしたし、発言するにしてもタイミングや内容のレベルの適切さを図り辛かったので、話題の提供は他の方に任せて、私は他の方からの疑問に答える形で読み進めていきました。

以下、当日の流れと主な話題:

8章 - :abbreviateが長い
省略して:abでも構わない。
他のコマンドでも同様に省略形がある。
9章 - :printは何に使えるのだろう
:globalと組み合わせると便利な場合がある。例: :global//printで現在の検索パターンにマッチする行を表示(限界まで省略すると:g/)。
Vimの祖先の祖先のedの頃なら現役バリバリだったのでは。
9章 - :substitudeって何だろう
:sのこと。誰もフルネームで覚えていない。
11章 - 自動改行やフォーマットについてあれこれ
129Pの上端の解説次のコマンドをタイプすると80文字目で改行を行うことになりますは間違い。'textwidth''wrapmargin'は排他的で、前者が優先される。なので本文中の設定では70文字目で改行が行われる。
フォーマットに関する細かい指定は'formatoptions'で行う。
フォーマット関連は基本的に英文用。日本語の途中で改行してほしい場合は:setlocal formatoptions+=mと設定しておく。
編集しているファイルの種類に応じて'formatoptions'やその他のオプションは適宜設定されている。コメントの記号も正しく認識されたりする。
11章 - rot13
ネタバレ防止機能。
12章 - 「自動完了」?
:help usr_24Vim can automatically complete words on insertionの一文があるので、原著ではそこから章題を「automatic completion」としているのだろうけど、何をどう間違ったのかcompletionを「完了」と訳してしまったらしい。
[これはひどい]
12章 - i_CTRL-Xの補完あれこれ
i_CTRL-X_CTRL-Fのファイル名補完はさりげなく便利。
他にも色々ある。
でもi_CTRL-X_CTRL-Ei_CTRL-X_CTRL-Yは謎すぎる。
13章 - 「オートコマンド」?
11章は「自動完了」だったのにこちらはカタカナのままで謎。

後半 - tech talk

後半はid:Sixeightさんによるtech talk (Vimとの出会いなど)、id:secondlifeさんによるtech talk (Vimとの出会いなど/雑多なtipsの紹介)、残り時間でid:YAAさんによるlightning talk (vimperatorのデモ)がありました。

ある意味、今回の目玉はid:secondlifeさんのお話なのですが、ところどころ妙な読みがあって吹かざるをえません。enableは「いなぶる」、/\v (very magic)は「べりーまっち」、fuzzyは「ふぃじー」など。最初の2つは納得できなくはないのですが、「ふぃじー」には負けました。他には「アルファベット27文字」が破壊力抜群でした。

id:secondlifeさんは残り時間でご自身の.vimrc紹介では意外とツッコミどころがあって個人的には楽しかったです。特定のキーバインドを無効にするためには<Nop>にマップすべき、検索時のハイライトを一時的に消すには:nohlsearchを使うべきなど。実は他にも指摘できるところはありましたが時間が時間なので黙っておきました。

番外編

勉強会後はid:ns9tksさんとid:secondlifeさんとお話したり、11人程で適当なお店に行って一緒に昼食をいただきました。色々とVim関連のお話ができて楽しかったです。

本当はまだまだ話をしたかったのですが午後のKansai.pmの時間が迫っていたので中途半端に終ってしまいました。特にid:ns9tksさんとはあまり話せなかったので悔しいかぎりです。これはもうKansai.vimなどを主催せざるをえませんね!