brushing up, input mode

引き続き、input モードに不足している部分を補っていく。

ちなみに input モードというのは、i とか a とか押すと遷移する例のモードのことだ。vi が起動してすぐの状態は “command モード” だと一般的に浸透している(と思われる)のに対し、例のモードは “insert モード” とか “edit モード” とか、微妙に表記が定まっていない気がする。しかし posix の定義に倣うならば、例のモードは “input モード” で、とりあえずそう書くことにする。正確には input モードは総称で、実際には insert モードと overwrite モードがある。

input モードで何がめんどくさいかというと、backspace/delete の振る舞いおよび、一部の特殊なキー入力(矢印キーなど)がサポートされている点だ。

input モードでは、以下の情報が逐一更新される。

  • 入力開始位置
  • 入力したテキスト。これは input モードを抜けた後にレジスタ “.” に格納される
  • 入力したコマンド。これは input モードを抜けた後に “.” コマンドで再生されるべきもの
  • undo ログ

これらの更新と、backspace/delete および特殊なキー入力による機能が矛盾なく両立させないといけない。また、abbreviation も考慮する必要がある。”f” を “foo” に展開するような abbrev があったとき、キーボードから “if bar” およびエスケープキーを入力すると:

  • 入力したテキストは [cci]f^Hfoo bar[/cci] となる(vim では)
  • 入力したコマンドは [cci]if bar^[[/cci] となる

ちなみに map の展開はこの前の段で完了しているので、入力されたテキスト、コマンド共に格納されるのは map 展開後の何かだ。ところで abbrev の展開が ^H 付きの構造になってるのってどういう意味あるのかな。別に単に展開後の文字列に置き換えても構わない気がする……。

repository relocation

いろいろなプロジェクトのソースはすべて Subversion で管理している。実は Subversion を入れている Linux PC をリプレースしようかと画策しているので、とりあえず一時的に Windows PC にリポジトリを移動させておきたい。

実際には、Windows PC でも Apache を動かしているので、単にそれに svn を dav のバックエンドとして組み込んで、Linux でダンプしたリポジトリを Windows でロードするだけのことだ。

ただ、以前 www.apachehaus.com には x64 でコンパイルした Apache とか、それに対応した svn 一式とかあってすごいなあと紹介した割にまったく試していなかったので、せっかくなので使わせてもらおう。つまり Apache 自体の入れ替えから作業することになる。

というわけで、Apache を更新し、svn を組み込み、リポジトリを移動させた。PHP は FastCGI で動かしてるので Apache が 新しくなろうが x64 版になろうが基本的に影響を受けないのがうれしい。

minifying

Chrome 版と Opera 版 wasavi のエクステンションパッケージは、javascript ソースを minify して格納している。

そもそもローカルファイルシステムに展開されるソースを minify して効果あるのか? と考えると、ほとんどないわけだけど、前にも書いた気がするが、closure compiler のような変態的な変換を行う可能性もあるので、とりあえずそういうプロセスを経由してビルドするようにしている。ただし Forefox 版は、minify するとレビュアの人に怒られるので、そのまま。

で。

minifier はいろいろあるのだが、いまのところ Microsoft 製の Ajax Minifier を使っている。一方最近、wasavi のソースは strict mode に移行した。さて AjaxMinifier は strict mode に適合する出力を行うのか? というとどうもそうではないようだ。文字列リテラル中に \uxxxx のようなものがあると、AjaxMinifier はそれを可能なら(というより短くなるなら)\x + 8 進表記に直す。しかし strict mode では 8 進表記は禁止なのだった。したがって、そのソースを含んだ wasavi をインストールしても起動しない。

どうするか。まず AjaxMinifier に渡すオプションに -strict:true を明示すると……変化なし。そうではなく、-minify:false を含めるといいようだ。これを含めても、コメントと改行の削除は行われる。なんだか限りなくバグに近い仕様のような気もする。-strict を指定したなら出力も strict mode に適合させるようにしてほしいところ。

それはそれとして、とりあえず生成したパッケージがそれぞれのブラウザで動くところまでは確認した。この辺も自動化できるといいんだけどなー。

entering code point #2

コードポイントの入力モードに入った場合にそれを抜けるには、最大入力文字数に達するかコードポイントの構成文字以外を入力するか、いずれかを満たす必要がある、というのは前の記事の通り。

しかしこれはちょっと不便ではないか。コードポイントの入力を途中でキャンセルしたいとか、明示的に確定したい+余計な文字は打ちたくないといった要求に応えることができない。前者は esc の押下、後者は enter の押下あたりが自然だと思う。しかし意外なことに vim ではどちらもそういう動作をしない。

ということで、そういう風に動作するようにした。

entering code point

というわけで、wasavi.js を分割した。

  • extension_wrapper.js
  • classes.js
  • classes_ex.js
  • classes_search.js
  • classes_subst.js
  • classes_ui.js
  • classes_undo.js
  • init.js
  • utils.js
  • wasavi.js

の複数のファイルで成り立つようにした。

 * * *

挿入モードでテキストを入力する際、vi には以下の ctrl 併用のショートカットが定義されている。また、vim では [cci]:help ins-special-keys[/cci] で参照できるが、以下のリスト以外にも(それはもう膨大に)ショートカットが用意されている。

  • ^D: shift
  • ^H: カーソル左の 1 文字削除
  • ^J, ^M: 改行
  • ^T: unshift
  • ^U: 入力のやり直し
  • ^V: リテラルの入力
  • ^W: カーソル左の 1 単語削除

  • wasavi ではまだ完全に実装できていない。この中で、^V について考えてみる。

    ^V は後続する文字の特別な意味を打ち消し、単なる文字としてバッファに挿入する。ここまでは、wasavi でも実装済みなのだが vim ではこの機能が更に拡張されている(:help i_CTRL-V_digit)。すなわち、

    • ^V [0-9]{1,3}
      10進でバイトを入力
    • ^V [oO] [0-7]{1,3}
      8進でバイトを入力
    • ^V [xX] [0-9a-f]{1,2}
      16進でバイトを入力
    • ^V u [0-9a-f]{1,4}
      16進で Unicode コードポイントを入力
    • ^V U [0-9a-f]{1,8}
      16進で Unicode コードポイントを入力
    • ^V (上記以外の 1 文字)
      入力した 1 文字そのものを入力

    という感じ。これを wasavi に持って来たい。

    まず javascript アプリケーションなので、取り扱う文字は UTF-16 に固定される。したがってバイトの入力であっても Unicode のコードポイントとして扱う必要がある。つまり x/u/U の違いは最大入力文字数だけになる。

    ^V の次に [0-9oOxXuU] を入力しコードポイント入力モードに入った場合、それを完了させる方法は 2 つある。まずそれぞれのモードの最大入力文字数に達した時点で、自動的に完了する。次にそれぞれのモードが受け付けるコードポイントの構成文字以外の文字 c を入力すると、その時点で蓄えられたコードポイント文字列から文字を生成し、それがバッファに入力される(コードポイント文字列が空の場合は何も入力されない)。入力される場合は、abbreviation の展開処理を迂回する。その直後 c が入力される。こちらは abbreviation の展開処理を経由する。

    なお vim では U プリフィクスを使用した場合、最大 8 桁の 16進数(ただしヘルプでは最大値は 0x7fffffff とのことだ)を入力できるそうだが、でも Unicode って最大 U+10FFFF だよね。クリップしてエラーにしたほうがいいのかな?

    またもちろん、U+10000 以上のコードポイントを入力した場合は、サロゲートペアに分割して 2 文字を入力する必要がある。

    だいたいこんな感じの仕様でいいかな!

ant fix

build.xml を書くのがどうも苦手だ。

たとえば trunk/frontend/ の下の 10 個程度の javascript ソースを minify して、指定のディレクトリに置きたい。そういうタスクはないので、自分で書くか、既存の minifier を exec することになる。

とりあえず簡単なほう、つまり既存の minifier を呼び出す方で行ってみるのだけど、1 つの js ソースだけならともかく複数ある場合はどうしたら? 仮に jsminify みたいなタスクがあって、それが子要素として fileset を受け付けるならば、こんなイメージになるはず:





しかしそんなタスクはない。なので、直接 minifer を呼ぶのではなく、適当な php スクリプトを呼び出すようにして、その中でディレクトリを読み、見つけた js ソースを片っ端から minifier にかけるようにしている。

こんな調子で ant だけではできなさそうな箇所は全部 php スクリプトを挟んでいるのが今の状況なのだった。いやまあ php はいっぱしのグルー言語なのだから、そういう使い方は間違ってないといえば間違ってないと思うけど。なんかとても中途半端だ。

と思ったらこういうのがあるんだね。ant 上で foreach 的なことができるのか。あらやだ素敵!

Wake me up

全体の電源がオフ状態でも、NIC にだけは通電しておき、外部からの信号によって電源をオンにする Wake on LAN というものがある。以前何度か試してさっぱり動いた試しがなかったのだが、最近の PC はもしかしたら普通に可能なのかもしれない。

WOL は BIOS、OS、NIC のそれぞれを適切に設定する必要がある。うちの PC のマザーボードは Biostar の A7GM-S とかいうやつだ。BIOS に入り、電源関係の子メニューから Resume from LAN だかなんだかを Enabled にする。NIC は内蔵の蟹さんマークのやつで、OS のデバイスマネージャからプロパティを開き、やはり WOL 関連を Enabled にする。最後に OS は、NIC のプロパティの「電源の管理」タブで適当に設定する。

別の PC で、とりあえず RemoteRebootX を起動させる。以下の形式の内容を持つ適当なテキストファイルを読み込ませる。

target-host-nickname#MAC_address

つまり “main_pc#ff:ff:ff:ff:ff:ff” とか。

ターゲットの PC をスリープさせる。S3 ステートに入る。別 PC の RemoteRebootX から WOL パケットを飛ばすと、電源が入る、はず。

ということでうまく行った。スリープではなく完全な電源断からの wake ができるかはまだやってない。

ということで最近の PC はしゅごいという話。ただ PC 自体よりも、Ethernet で繋いだプリンタとかの電源をリモートで操作できるとうれしいかも。ていうか普通にできるのかな?

Tsure-dure

徒然と何点か。

^L の処理を書き直した。vi や vim では、これは画面全体の再描画を行う。特に vim なんかでシンタックスハイライトさせている場合に、ときどき間違った色付けが間違って表示されることがある(たぶん、解析を見えている範囲の近辺部分でのみ行うからだと思う)。そんなときに ^L を押すとだいたい直る。直らないときもある。

一方 html ページに構築される wasavi において、再描画って? という話になる。そもそもそんな機能、不要なのだ。しかしそれはそれでもったいないので、^L を押すと 0.5 秒の間、wasavi を隠すことにした。つまり wasavi の下にある textarea/input をちょっとだけ確認できる。それの何が便利なのかは、よく分からない。

 * * *

入門 vi のテストをちょっとだけ(2 テストだけ)書いてみた。2 章のものなので、基本的なモーションというレベルだ。この辺は既存のテストと丸被りしているのであまりする意味はないかもしれない。

 * * *

:edit コマンドはスタンドアロンモードでのみ有効にしていたのだが、textarea を拡張した場合でも、引数なしで実行する(つまり、それまでの編集を全て捨て、textarea の元の内容で編集をやり直す)ことはできるようにした。

 * * *

ところで iframe 内で実行される wasavi の本体は wasavi.js に全部入っている(正確には agent.js でも使用する部分は extension_wrapper.js に分離してある)。そうすると当然ながら、wasavi.js が超巨大になっている。現在 12751 行ある。これはよくない。github でソースを見るときもブラウザがほとんど固まってしまうし、pull request してくれる人(がいるのか知らないが)には弄りにくいだろうし、全部込みの弊害で割と変数をフリーダムに参照しているのもよくない傾向だ。とあるところで

an insanely complicated 11K line JS file

などと呆れられているが、「そのとおりでございます」と言う他ない。

これを上手く分割したい。

Lerning the vi Editor, 6th edition

O’Reilly に表題のようなタイトルがある。日本語版は「入門 vi」だ。一丁前のブログぽく広告なんかを出してみると、

こんな感じ。ちなみにこの本は持っていて決して損はない、とても分かりやすいいい本だ。

なんでいきなりステマかというと、この本の中に記述されている vi/ex コマンドの実例をテストケースとして起こして、だいたい全てのテストに通ることを保証したい。つまり巷の vi 本が、そのまま wasavi のチュートリアルとしても通用するようにしたい。とそういうわけです。

pulling strongly

wasavi.js、agent.js、extension_wrapper_js、background.js を strict mode にした。

と言ってもそんなに弄る必要もなかったのだけど、arguments.callee を追い出す必要があった。そもそも strict モードは、コードを堅牢にしたりセキュアにしたりするためのものだ。しかし arguments.callee の参照禁止という点では、副作用的に jit コンパイルがより深いレベルで行われるとかで、速くなる(可能性がある)、そうな。へー。

 * * *

wasavi 0.4.207 をそれぞれのブラウザのエクステンション向けに公開した。Chrome が即時、Opera がだいたい 1 日なのは今までの通りとして、Firefox がとりあえずまず validation が滞りなく進み(やっと)、Full Review 待ちになった。ここからだいたい 10 日かかると見ていたら、3 日くらいでレビューが通った。なんだー早いなー。

それはそれとして、レビュー結果で、ソース中のとあるコメントに対して

This is not even remotely true.

つまり「ぜんぜん間違ってるんですけど?」と一言あったのだけど、そのコメントは複数の文からなるものなのだ。えーとどの部分が間違ってるのか書いてほしい……。レビュー結果のメールに返答して返事が返ってくるものなのかな? なんか機械的に送られてきてる気がするけど。