record key strokes #3

いろいろと修正。keyManager や mapManager を弄るのは、wasavi の動作が根本的にぶっ壊れる可能性があるので怖い。ちなみに「なんとか Manager」と命名されたクラスは悪い設計の兆候だという意見もあるらしい。うむむ。

前の記事の通り、@ コマンドや :@ コマンドで実行する文字列内で特殊なキーを示すためには私用領域の文字 U+e000 をヘッダにする。矢印キーなら “\ue000<down>” などといった感じだ。q コマンドで記録したストロークに特殊なキーが含まれていたとして、それを “ap とかすると普通に U+e000 の文字も貼り付けられる。どういう文字がレンダリングされるかは環境に依存する。

q コマンドに頼らない場合、適当な行にキーストロークを打ち込んでそれを yy する必要があるが、挿入モードでの ^V で任意のコードポイントを入力する方法は wasavi にはまだない。将来的にはできるようにするつもりだが、とりあえずあとまわし。

:map コマンドでマップ前とマップ後のストロークをそれぞれ指定する際は、U+e000 を明示的に打ち込む必要はない。<~> の文字列には自動的に U+e000 が前置される。これを避け、純粋に文字列としての <~> を指定するには、”<” の前に ^V そのものを前置する。つまり ^V^V と入力してから <~> を打つ。ストロークに空白文字を含める場合にも ^V を前置する必要がある。この辺は素の vi、あるいは vim でもだいたい同じだ。

 * * *

Chrome Web Store でのバグレポート、および Opera でのフィードバックで指摘されたのだが、”array[i]” とか打つと wasavi 内のとあるループ処理が終わらなくなってハングする。閉じ括弧に対応する開き括弧を点滅させる処理と挿入モードの下処理がかち合ってるために起こるバグだ。これは手元のソースではすでに修正してある。公開版では、とりあえず [cci]:set noshowmatch[/cci] することで回避できる。

Chrome Web Store でのバグレポは(たぶん)ニュージーランドの方からだったが、Opera 版のそれは日本の方からのようだ。で、その方のブログのエントリを見るとバグレポートを出すのに少なくない心の中の逡巡があるようなのだな。

これは日本人らしい奥ゆかしさの発露なのかもしれないが、バグレポートはまずそれが行われないことにはこちらに届かないわけなので、特に難しいことを考えず気軽にしてほしいと思った。「このエクステンションはゴミだな! 作った奴は死んだほうがいい! てか死ね!」とか書かれても特段なんとも思わないくらいの鈍感力は備えているので心配ない。

ちなみに各エクステンションのリポジトリにあるフィードバック機構はそんなにちょくちょく見てるわけじゃないので、もしアカウントを持っているなら github の issue を作ってもらえるか、ここのフォーラムに書き込んでもらうのがいちばん手っ取り早いです。

record key strokes #2

キーストロークの記録は、:map と間接的な関係がある。両者とも、キーストロークを文字列化したものを扱う。さてキーの中には、一般的なコードポイントに対応しないものがある。例えば Page Up とか F1 とかね。そういうキーをどう文字列化するか? というところが現在の wasavi の実装ではまだ不完全なのだ。

vim では、特殊なキーは CSI (Control Sequence Introducer, 0x9B) と呼ばれる特別なバイトを前置して区別している、ようだ。wasavi でも同じような形式にしよう。私用領域の U+e000 を 使用する。たとえば delete キーに対応するキーストロークは、文字列化すると “\ue000<delete>” となる。

:map では同じような、しかし逆の変換を実装することになる。:map の rhs で “<delete>” と書いたら、内部的には “\ue000<delete>” として扱わないといけないのだ。

record key strokes

@ コマンド、:@ コマンドはすでに作ってある。これらは、指定のレジスタの内容をそれぞれ vi コマンド、ex コマンドとして実行する。
ではコマンド列をどうやってレジスタに突っ込むかというと、素の vi では適当な行にコマンド列を打ち込んで yy することになる。

一方 vim では、q{register} コマンドが新設されている。これはエディタの状態を「キーストローク記録中」にする。この状態のキー入力は記録される。この状態を抜けるには、単に q を押す。すると記録されたキーストロークが {register} に保存される。この機能はつまり、インタラクティブにキーストロークを記録するものだ。

というわけでこれを実装する。

Opera and DOM3 Composition Events

こんなことを書いてそろそろ 1 年経つのだけど:

DOM3 Composition events、いつのまにやら Chrome(と、おそらく Safari)、IE9、Fx9 と実装済みのブラウザが揃っている 2011 年末。

さて Opera は何年後くらいに実装するの?

# そしてまさかの実装されない、というオチ

まさか 1 年たってもまったく状況が変わってないとは思わなかった。強いて変わった点といえば、Opera は 12.50 で DOM3 Events に準拠するようになるらしいということ。ただし開発版 Opera である Opera Next の最新ビルドでも、Composition Events はまったく実装されていない。さすがに最終的に「実装されない、というオチ」はないと思うけど。ない……よね?

ちなみに、Composition Events をサポートしていないとしても、たとえば google でやってるように、思い切りタイマーをぶんまわして textarea#value をポーリングすれば確かに同じようなことはできる。できるのだけど、ただ 1 つだけ問題がある。IME を通した入力サイクルを考えてみると、

  • 仮入力
  • 変換して候補を選択
  • enter を押して確定

の繰り返しだ。しかし実際は、確定として enter を押すことはそれほど多くない。(少なくとも MS-IME は)変換後の候補選択状態で、選択のための特定のキー以外のキーを押せば、暗黙的に確定が行われて仮入力状態に移行する。この暗黙的な確定が発生した正確なタイミングをタイマー方式では認識できない。

そういうわけで、wasavi には Composition Events がないブラウザのためのフォールバック機構は入れていない。つまり今のところ Opera で IME を通した入力は正しく動作しない。どうしたものかなあ……。

a difficult AMO #5

AMO の中の人の手元でもサーバーエラーになるそうなので、bugzilla に登録してもらった。

うーんこちらで直接登録してもよかった気がするが。まあでも中の人……というか「the Add-ons Developer Relations Lead for Mozilla」という肩書きのおかげか、あるいはアサインとかも最初から割り当てられてたせいか、すぐに修正されたようだ。あとは、そのパッチがレビューされて実際に適用されるのを待つだけということかな。

長かったなあ。

関係ないけど、wasavi の preliminary / full review をしてくれた方は Pentadactyl の開発者の一人ということで、vi 繋がりなのかと思ってたら、単にものすごく多くのアドオンをレビューしているだけだった。なーんだ。

beauty is relative #2

relativenumber を実装してみたが、カーソルから上の領域の行番号が負の符号付きになる件。これはこれでしかたないかなーと思っていたところ、コメント欄で間接セレクタを使えばいいと教えていただいた。

あー、間接セレクタね! うんうん間接! 間接……間接セレクタってなんだっけ?

バカにしないでくれる!? 知ってるわよそれくらい!!(ググりながら)

というわけで無事 vim の relativenumber と同様の見た目になった。ありがとうありがとう。

a difficult AMO #4

そういえばすっかり忘れていたが、AMO に新しい xpi をアップロードできない件。

(先週の)金曜になったら試してみてね! などと言うから期待していたのだが案の定同じサーバーエラーが帰ってくるだけだった。枕を涙で濡らしつつ、再び AMO の中の人にメールしたら、xpi を送ってみろというので送った。

個別に対応してくれるのはありがたいけど、サーバーエラー時のメッセージをもうちょっと詳しく出すように改修してくれないかなあ。次またエラー出たらまたこのやりとりしろというのだろうか。

お願いしますよ Jorge さん。

beauty is relative

「relativenumber、いいよね」「いい……」

vim の機能を全て知っているわけもないが、知ってる機能の中で、初めて知ったとき最も衝撃的だったのは relativenumber かもしれない。relativenumber 好きだ、大好きだ。お前が好きだ、お前が欲しい!

というわけでこっそりと wasavi へ移植する。

内部的には、wasavi の行番号は css のカウンタだ。したがって、操作できるのは counter-reset、counter-increment くらいで、それほど自由度があるわけではない。そういう環境下でカーソル行を 0 とした相対的な行番号ぽくするには、バッファの counter-reset を -(カーソル行位置+1) で初期化する。カーソルの上方向は負の符号付きになってはしまうが、これでだいたい目的は達せられる。

しかし実際に作ってみるとやっぱり負符号が気になる……。

a thought of syntax hilighting

現在 wasavi のメジャーバージョンは 0.4 だ。これがいつ増加するかというと、おそらく

  • モデルとビューを分離したとき
  • シンタックス・ハイライティングを実装したとき
  • プラグイン・システムを実装したとき

のそれぞれになると思う。さてこの中でシンタックス・ハイライティングであるが、面白い論があったので勝手に訳出。意訳多数、訳質未保証。

* * *

シンタックス・ハイライティング論

君はソフトウェアを開発する際、シンタックス・ハイライティングに頼っているか? もし頼っているならば、もしかしたら君は自ら「墓穴を掘っている」かもしれない。このポストでは、美しく魅力的なシンタックス・ハイライティングについてその表現形式に焦点を移し、それがコードを見て理解しようとする人々の障壁になっていることを議論しよう。

背景
シンタックス・ハイライティングは、大半の現在的テキストエディタや開発環境では標準的な機能で、その基本概念は、プログラマがキーワード、記号、変数名を簡単に識別できるように、いろいろな構文的要素の見た目の違いを強調することだ。

そもそも、なぜシンタックス・ハイライティングが発明されたのか。プログラマは全てのシンタックスが織り交ぜられたコードを読む際、「”)” は変数名かな、もしかしたらプリプロセッサの命令かな?」などと考えるだろうか? もちろんそんなわけはない。コンピュータ・プログラムを読むことは大概難しいが、この難しさはそのプログラムの複雑さからくるものだ。シンタックスではない。

読みやすさ
シンタックス・ハイライティングはおそらく、コード読解の過程を加速するために発明された。イエス、その通り。強調されたコードは読みやすいに決まってる。その結果、強調されたコードは色を持つようになった!

うーん、ノーだ。タイポグラフィの基本的な経験則の 1 つに「まとまったテキストを書く際は、1 つの書体を選び、そしてそれを固守せよ」というものがある。は読者の注目を集めるかもしれないが、しかし必然的にテキストを読みにくいものにしてしまう。テキストの自然な流れは破壊される。破壊されたテキストは、個々の文字を繋ぎ合わせて単語と意味を得るためにより脳を酷使させることになる。認識という視点では、読解の過程から無意識の度合はがわずかに減少し、わずかに意識的になる。つまり、実際にテキストを理解する際の、心の意識的な部分の余裕を減少させる。

文法よりも意味が重要
コードを読む上で最も重要なのは、「理解」することだ。段落をざっと眺めれば、その要点を得られる小説や新聞と違い、ソフトウェアは複雑さで満たされており、細部にいたるまで全てが重要である。必然的に、理解するには時間がかかる。理解するためには、コードを意味のレベルで見る必要がある。

また、開発者は、よく知っているコードからさえ、単なるシンタックス・エラーよりもメモリーリークやセキュリティーホール、非効率なアルゴリズムを発見(そして修正)しようとするだろう。どの道コンパイラによって見つけられるのだから、開発者はシンタックス・エラーを探して時間を無駄にするべきではない。しかし、もしシンタックス・ハイライティングが開発者の思考を、コードが意味するものに対してではなくコードのシンタックスへと偏らせたならば、結局彼らは正にシンタックス・エラー探しを行ってしまうのではないか?

私は開発者達は愚かだと言っているのではない。私達は皆あちこちのいろいろなバグを見逃している──誤りは誰にでもあるものだ。せっかく作るのなら、ミスを助長するよりもミスの発見を助けてくれるツールを作るほうが良いと私は思う。

学習曲線
おそらく、シンタックス・ハイライティングは経験豊かなプログラマ向けのものではない。たぶんズレたピアノ教師が鍵盤に色つきのステッカーを貼るように、初心者にとっての学習曲線をなだらかにする意図でもたらされたのではないだろうか。ピアノ教師がそういうことをするのは、コミュニケーションを円滑にする(「さあ F を鳴らして!」より「さあ黄色い鍵盤を押して!」)ためなのかもしれない。彼らが本当に子供たちが音階名を覚えることなど無理だと思っているかは知らないが、子供たちは結局、音階名を覚えて、その後色つき鍵盤を忘れなければならない。

同じ現象がウィザードというユーザーインターフェースで見られる。高度な操作、例えば画像を扱うプログラムは複雑で、新しいユーザをまごつかせるが、ウィザードのダイアログボックスへ入力しさえすれば、柔軟性を犠牲にしていくつかのステップは省略あるいは自動化される。しかし結局、ユーザーは複雑な機能自体ではなく、ただ単にウィザードの使い方を覚えるだけで、そして特別な柔軟性は失われる。これは学習曲線をまったくなだらかにはしていない。学習していないのだ。

もし君が色のある環境でソフトウェアを書くことを学んだら、おそらく色なしの同じコード、あるいは異なるカラースキームのそれですら、理解にしにくい(あるいは、少なくとも不便だ)と感じるだろう。そう考えるとシンタックス・ハイライティングは教育の行き止まりだ。それは補助輪のついた自転車の乗り方を覚えるようなものだ。覚える過程で得た技術を捨て去るまで、普通の自転車には乗れないだろう。

例外
シンタックス・ハイライティングが実際に役立つケースが 2 つある。1 つめは複数行コメントに関連する。たとえば対話的な検索・置換操作の過程でソースコードファイル中を飛び回り、最後に巨大なコメントアウトブロックの真ん中で終了したら? 君はそれをコードだと思って読み始め、しばらくしてコメント終了のトークンにぶち当たる。そこで君はずっとコメントを読んでいたと気がつくわけだ。このケースでは、全コメントが異なる色で描画されることでミスは防げただろう。

しかしまあ、これは近視眼的な解決法だ。コードをコメントアウトするのは非常に一時的なデバッグ手法であって、コメントアウトされたコードは遅かれ早かれ削除か書き直さないとダメだということに多くの方々は同意する。視界から追い出すためにコメントアウトコードの色を変えるのは、まるでカーペットの下にゴミを隠すようなものなのだ。

2 つめは、主に C 言語に関するケースだ。たまたま「==」の代わりに「=」と書いてしまう、これは特に、長時間腰を据えてコードを凝視し、実際に目で見るまではなかなか発見しにくいバグになる場合がある。この状況のシンタックス・ハイライティングは、コードを意味論の文脈よりもシンタックスのレベルに焦点を当てることで有益になりうる、私が知る限り唯一のケースだ──それが「=」と「==」を異なる色で区別できるならば。やった! シンタックス・ハイライティングを実装するいい理由だ! だが……(おそらく君はここで驚いたりはしないと思うが)私が見つけた全てのカラースキームは、「=」と「==」を同じ色で強調している。

まとめ
シンタックス・ハイライティングはコードの読みやすさを改善せず、コードを理解させるのではなくざっと読ませるよう助長してしまう。シンタックス・ハイライティングは実際のバグではなくシンタックス・エラーに注目させ、それは学習の邪魔になる。おそらく、コメントアウトされたコード塊の削除をずるずると先延ばしさせたりもする。そして、現在の実装は「=」と「==」の区別(シンタックス・ハイライティングが有用だった唯一のケース)をしない。

一体誰がこんなひどい機能を発明したんだ? 推測するに、シンタックス・ハイライティングは実装して楽しいクールなアイデアとして始まった。今では、それはセールスポイントになった。人々は、例えそれ以外の機能が豊富だったとしても、シンタックス・ハイライティングをサポートしないエディタには眉をひそめる。これはたとえば半透明のコンソールとか、見ていて楽しいものについて共通する、十分に一般的な現象だ。

私は、例え苦くとも良薬を飲むよう勧める: シンタックス・ハイライティングなしでコードを書く、あるいはただ 2 色(コメントとコード)のみ使うという清貧的アプローチを受け入れる。警告: カラフルな見た目なしでは、君のコードはちょっと醜いかもしれない。しかし少なくとも、君が見ているものが現実のコードなのだ。

「この時、王様は裸でありません。王様はすばらしく色とりどりの道化師の服を着ていたのです」

handling wrapped rows #2

ということで、表示行単位でカーソルを上下に移動させるコマンド gj、gk を実装した。また、オプション jkdenotative を追加した。これがオンの状態では、単なる j、k が表示行単位で移動し、gj、gk は物理行単位で移動することになる。そして重要なことに、jkdenotative の初期値はオン、にしようと思う。

それにしても jkdenotative ってものすごく覚えにくいな。なんかいいのないかな。

さて vim では gj、gk のほかに g0、g^、g$ なんかもある。というかもっと他にやたらある。全部はいらないので、g^ と g$ くらいは作るかな。これらも jkdenotative の影響を受けることになる。とても重要。