Mysterious Color #2

とりあえず ace のソースなんかを見てみる。バッファへの編集は edit_session.js でやっていて、色分けのトークンの切り出しは background_tokenizer.js でやっている。切り出しの処理は setTimeout で分割される。

ソースを見た感じ、再解析は編集の行われた行以降? それでいいのかな。

 * * *

ところでスクリプティングやシンタックスハイライティングについて下調べしているわけだが、すぐ実装するわけではない。0.5 での目標は、まず安定して編集できるようにすること。textarea の拡張として常用できるようにすること。いろんな機能があるけど不安定なエディタなんて誰も使わないのだ。

その後でまず、モデルとビューを分離させたい。今はバッファはすなわち DOM の要素群であり、したがってビューを兼ねている。これはよくない。バッファは単に 1 行を要素にとる配列にし、ビューは見えている部分だけを描画させるようにしないと、数万行のテキストを編集する際にメモリ消費がひどいことになる(はず)。

 * * *

Webkit Opera のデスクトップ版っていつお披露目されるのかな。Opera が Webkit ベースになれば、つまり Composition Events ももれなくついてくるということなので、今やってるような気持ちの悪いエミュレーションはまったく要らなくなる。そうすればいろいろとコードをスッキリさせられる。かなり楽しみだ。

Mysterious Color

Syntax Hilighting のことを考えるのだが、いまいち実装のイメージが湧かない。ところで “Syntax” というけれど、巷のテキストエディタって文法的なものまで見ているものなんだろうか? あるいは、単にキーワードを識別しているだけ? まずそこからが分からない。それから、テキストの編集が行われると当然その行の解析をやり直すことになるのだけど、その行だけではなく、場合によっては編集した行の周辺の影響を受けたり与えたりする。むしろそのケースが殆んどかもしれない。その場合、再解析を行う行はカーソル行ではなく n 行遡った行、ということになるのだが。その n はどーいう理屈で求めるのか? それとも編集が行われるたび先頭行から解析し直すのだろうか。

vim に限って言えば、仕組みは :help :syntax すればだいたい分かる。しかし再解析行を指定できたりするのは自由度が高いといえば聞こえはいいが、実装の都合が見えすぎてる気も……。もしかしたら参考にすべき実装とはちょっと言えないのかもしれない。

もうちょっと色々なエディタのソースを見てみる必要があるかな。うーんめんどいなあ!

Opera migrates to WebKit

http://my.opera.com/ODIN/blog/300-million-users-and-move-to-webkit

Opera がレンダリングエンジンおよび javascript エンジンを Presto/Carakan から Webkit/V8 へ変更するそうです。ちょっと前から、Opera ICE という名で Webkit 版 Opera を開発していることは知られていたが、Presto との関係は明らかにされていなかった。今回、モバイル向け、PC 向けなどの Opera 全体のプロダクトの完全な Presto から Webkit への移行が発表された。

Extension は、Chromium ベースのものに移行させるためのチュートリアルやドキュメントを作成中だという。Extension の仕様自体が Chromium 準拠という形になるのか? はちょっと不明。

世の中びっくりすることばかりだね。

 * * *

Webkit に移行するとなると、Dragonfly はどうなるのかな。ディスコンするにはもったいないような。それを含めて、新しい Opera が Webkit Powered Opera になるのか、あるいは Opera flavored Chromium になるのかいまいちわからない。もちろん既存の Opera ユーザが望むのは前者のはずだが、より詳しい公式発表が待たれる。

 * * *

Opera の外の世界に目を向けると、現役のレンダリングエンジンから Presto が引退することで、Trident/Gecko/Webkit の 3 強時代になり、同時に Webkit 陣営の勢いがより増すことになる(Opera は Webkit への様々なコントリビューションを宣言している)。このような勢力地図の更新について、特に Mozilla がどのような意見を持っているのか、気になるところだ。

 * * *

Webkit の開発組織が、Opera が参入することでどう変質するのかも多少気になる。まあ間違っても、「蓋を開けたら Opera が Webkit を飲み込んだという構図になってた!」みたいなことは起こらないにしても。

Interception

ふたたび github の issue から。

  • Chrome で、オプションページから設定を変更しても既存のタブ上の textarea に反映されない?
  • github の issue がまさにそうなのだが、wasavi を起動するためのショートカットキーが textarea に結び付けれたページ固有のイベントリスナと競合することがある

後者について考えてみる。textarea 上でキー入力があった時、それが wasavi を起動させるためのものかを判断するために、あらゆるページで agent.js という小さなスクリプトを走らせている。この中で [cci]window.addEventListener(‘keydown’, …)[/cci] としてそこで判断している。

一方で、ページに付属するスクリプトが textarea や window や document に addEventListener() する場合もある。複数のイベントリスナは登録順に実行される。ここで [cci]Ctrl+Enter[/cci] を特別なキーバインドとして認識する複数のイベントリスナがあったとき、競合が起こる。github の issue では wasavi の起動とコメントの送信が同時に行われてしまう。

実は開発の初期の段階では、agent.js で window と document の addEventListener() のフックというなかなかの荒業をやっていた。addEventListener() を乗っ取り、wasavi が起動中なら wasavi に関連しないキー入力イベントは無効にしてしまうのだ。しかしたしかに荒業すぎるので、取り外していた。

とはいえ、やはりリスナの競合の回避はそういう方法を使わない限り難しい。ということで復活させた。フックの対象は window/document ではなく window.Node.prototype.addEventListener() にした。つまりあらゆるノードが影響を受ける。荒業どころではなく傍若無人なレベルに達している気がするが……。いや問題なく動くのなら別に傍若無人だろうといいと思うけど、似たようなエクステンションと共存させたとき、うまく動くのかな、とちょっと心配ではある。

wasavi 0.5.293 released

リリースした。

変更点
  • 可能なら限定的にブラウザのスペルチェッカが働くようにした
  • コンテキストメニューから起動できるようにした
  • 編集済みフラグが undo の状態に追従するようにした
  • en のメッセージを contrib されたもので更新した
  • ja のメッセージを en に合わせて更新した
ダウンロード

wasavi for Firefox is available

1月19日に AMO へアップデートを申請した wasavi 0.5.281 が今日フルレビューを通った。まるまる3週間かかったことになる。AMO からの素敵なお便りメールを受信する設定にすると、

Most updates are being reviewed within 2 weeks.

などと高らかに謳っている自画自賛メールがやたら届くわけだが、それはあくまで平均の数値であって実際にはなかなかそう上手くは行っていない。

別に Mozilla のそういうスタンスがダメだというわけではない。Chrome のように機械的にチェックするだけとか、Opera のようにおめーそれ体裁しかみてねーだろ! といったスタンスに比べたら、時間がかかってもひと通りソースコードを見てもらえるというのは良いことだ。とても良いことだ。

それにしてもちょっとレビューに時間がかかり過ぎじゃないですかね……ということなのだ。Mozilla って別に爪に火灯すような財政状況でもないと思うんだけど、なんでレビュアーを増やさないのかな。

Scripting #7

とりあえずの取っ掛かりとしてスクリプトを動かす基本的な部分は作った。が、このアーティクルではスクリプティングについて特に書くことはない。github で要望や pull request が来ていたという話なのだ。

  • スペルチェッカがほしい
  • コンテキストメニューから wasavi を起動できるようにしてほしい

こんなところである。また、pull request の方はメッセージや readme を自然な英語に書き換えてもらった。これは嬉しい。

さてこの中で興味深いのは、スペルチェッカだと思う。ピュアな vi にはそんな機能はない。また、nvi にもない。vim はある。ちなみに elvis にもあるらしい。

といっても、同等の機能を javascript で実装するのはなかなか面倒だ。実装というか、辞書を用意するのが大変だ。そこで、単にブラウザの機能で入力用の textarea の spellcheck 属性を true にすることにする。とりあえず input モード時、間違った綴りの単語を区別することはできるようになる。Opera では間違った綴りの単語に赤線が引かれる。
wasavi_spell_checker
ただ、たとえば Opera の場合、間違った綴りの単語の上でコンテキストメニューを出すと正しい綴りの単語が提示されて、単語を置き換えたりできるのだが、wasavi は個々の要素に対するコンテキストメニューを封じているので、置換はできないのであった。本当にただ、綴りが間違っているかどうかを知ることができるだけである。また、input モードを抜けると赤線は消去される。

spellcheck 属性は、html5 で規定されている。したがって html5 対応と謳うブラウザはだいたいスペルチェック機能を持っていると考えてよい(必須の条件ではない)のだが、どうせブラウザがスペルチェック機能を内包するのなら、javascript の API も規定してくれればいいのになー。

Scripting #6

すでに書いていると思うけれど、:script コマンドには 2 種類の書き方がある。:script の引数としてスクリプトコードを与える方法と、:scriptend までの間に記述する方法。前者を single-lined script、後者を multi-lined script としよう。

vim では、たとえば :lua と打つとその場で(つまり、コマンドライン入力モードのまま)スクリプトコード本体を打ち込めるようになっている。非常に賢い。でもそれを実装するのは面倒だなあ……。

というわけでとても乱暴なことに、wasavi 実行中に対話的に ex コマンドを入力するシーンでは :script は single-lined script のみ認めることにする。multi-lined script は exrc の実行、および :source でのみ有効となる(:source はまだ実装していないけど)。

 * * *

とりあえず、:script を含んだ exrc をエラーなく実行できるようにした。Chrome や Firefox でも同様に実行できるようにした。

それにしても新しく書かなければならないコードが多すぎてさっぱり進んでいる感じがしない。

Scripting #5

特に Chrome に対して重要な変更を施した。

wasavi が属する文書とスクリプトフレームが属する文書は、同一のオリジンである必要がある。これは、wasavi 側から scriptframe.contentWindow.dispatchEvent(ev) としたり、あるいは逆にスクリプトフレーム側から window.parent.dispatchEvent(ev); とするためだ。同一オリジンじゃないと dispatchEvent() は拒否される。dispatchEvent() を用いるのは、それが同期的に実行されるからで、postMessage() を使うといろいろと話がややこしくなる。

ところで Chrome では、wasavi が属する文書はエクステンション内のものにしていた。つまり chrome-extension://なんちゃら、という URL の文書。ところが、この URL に属する文書に付随するスクリプトは content script と同じ扱いになるのだった。この環境でスクリプトを動かすには、権限が高すぎる。

Opera や Firefox(Add-on SDK) では、エクステンション内の文書を通常のページの iframe の内容として表示することはできない(Firefox ではなにか方法はあると思うが調べてない)ので、appsweets.net 上の文書を参照している。これなら、スクリプトを動かす際に一般の web ページの権限が適用される。

ということで、Chrome でもその流儀に従うようにした。これは manifest の変更を意味する。ただしより強い権限を要求するのではなくその逆で、web_accessible_resources が不要になる。しかし一方でコンテキストメニューのために permissions に contextMenus を追加したので、次のリリースをインストールする際にはなにがしかのダイアログは出るはず。

ちなみに Chrome の不思議な特性として、コンテントスクリプトから、コンテントスクリプトの影響下にない素の Window オブジェクトにアクセスすることができない。つまり scriptframe.contentWindow を触れない。そういうわけなので、wasavi 側の文書で script 要素を生成し、以下のコードを text 属性に突っ込む:


document.addEventListener('WasaviScriptRequest', function (e) {
var ev = document.createEvent('CustomEvent');
ev.initCustomEvent('WasaviScriptRequest', false, false, e.detail);
document.getElementById('wasavi_script').contentWindow.dispatchEvent(ev);
}, false);

で、wasavi 側からスクリプトを呼び出す際は自らの文書に対してイベント起こす:


var ev = document.createEvent('CustomEvent');
ev.initCustomEvent('WasaviScriptRequest', false, false, {code:"console.log('hello, world')"});
document.dispatchEvent(ev);

Scripting #4

スクリプトの環境では、window.wasavi オブジェクトが事前に定義されていて、それを通して wasavi を操作する。たとえば wasavi.run(‘Ihello, world\u001b’); のような。

ここで面倒なのは、wasavi のコマンドの中には非同期に実行されるものがいくつかあるということだ。たとえばクリップボードレジスタを参照する場合や、:read、:edit など。スクリプトから呼び出す際は、これらのコマンドも同期的に動作させなければならない。そうしないと

wasavi.run(':r foo.txt\n');
wasavi.run(':Iwow!\u001b');

と言ったスクリプトが正しく動作しない。

とは言ったもののこれはかなり難しい。非同期的な処理を同期的に扱うのは、やはり ES6 の generators が欲しい。しかし generators を現時点で実装しているブラウザはないのだった。正確に言えば、Firefox は javascript 1.8 としての generators は実装しているが微妙に仕様が違う。Chrome は canary と dev で chrome://flags を操作することで試験的に使うことができる。Opera は……まあ Opera だからね!

ということで、スクリプトの機構は作っておき、さらにシンタックスハイライティングの定義をするインターフェースも作るが、wasavi に対してコマンド列を送る機能は各ブラウザに generators が実装されるまでおあずけということになると思う。

ES6 っていつ策定完了するのかなあ?