clipboard access #4

vim にあって vi にはない、insert/overwrite モード、および ex コマンド入力時の特殊なショートカットして、^R をプリフィクスとしてレジスタの内容を貼り付ける機能がある。それを作る。

タイトルの通り、これにはクリップボードレジスタ “*” も含まれる。クリップボードを指定された場合は非同期的にそれを読みだしつつよきに計らう仕組みにする必要がある。それから、paste イベントのハンドラはクリップボード以外のレジスタを指定された場合にも実際に貼り付けを行う窓口として流用できる(文字列中の改行を調整したり、特定の文字を予めエスケープしておく処理は共通なので)。

そのためには、paste イベントハンドラを機械的に発生させられる必要がある。これは W3C の Clipboard API では、window.ClipboardEvent コンストラクタを使用することで可能だ。従来は、この手の定石は document.createEvent() でイベントオブジェクトを生成し、initEvent() とか initUIEvent() とかその他もろもろで初期化し、任意のノードで dispatchEvent() という手順だったのだが、deprecated みたい。コンストラクタでイベントオブジェクトを生成する場合はパラメータをディクショナリで指定したりするところがナウいと思う。
var pasteEvent = new ClipboardEvent('paste', { bubbles: true, cancelable: true, dataType: 'text/plain', data: 'My string' } );
document.dispatchEvent(pasteEvent);

さて、この ClipboardEvent をブラウザが備えてないと困るわけだけど…… Opera と Firefox は備えている。意外なことに Chrome が備えていない。paste イベントは認識するのに ClipboardEvent も WebKitClipboardEvent もない。どういうことなのかな。webkit のソースを見るとそれっぽいものはあるようなので単に安定版 Chrome にはまだ来ていないということなのか?

too strict review

AMO へ wasavi 0.5.329 をレビューに出してかれこれ 2 ヶ月くらい経っているのだが、音沙汰がない。レビューに出している間に何度かメールでのやり取りをしているのだが、dropbox に対しての読み書きについてテストの手順を教えてくれとのリクエストに 7 月 30 日に返事して以来音沙汰がない。キューの位置は 10 of 145 である。よほど巨大なアドオンが前に詰まっているのか?

あまりに時間がかかるので、AMO へ提出する Firefox 版は当分ベータバージョンにするかもしれない。つまり 0.5.351beta のようになる。

ctrl-v

vim から拝借してきた機能の一つにプリフィクス付きの文字入力というものがある。

insert/overwrite モード、あるいは ex コマンド入力中に ^V を押すと、次に入力する文字がその文字そのものとして入力される(ただし insert/overwrite モードで ^M、^J を入力した場合のみは enter を入力した場合と同様に改行が行われる)。これはおもにコントロールコードの入力に使用されるのだが、wasavi では ^V に続けて数字、または o/O/x/X/u/U を押した場合はさらに特殊な状態に遷移する。

  • 数字: 最大 3 桁まで入力でき、10 進文字列として評価した値をコードポイントとしてみなした時の対応する文字に変換される
  • o/O: 最大 3 桁まで入力でき、8 進文字列として評価した値をコードポイントとしてみなした時の対応する文字に変換される
  • x/X: 最大 2 桁まで入力でき、16 進文字列として評価した値をコードポイントとしてみなした時の対応する文字に変換される
  • u: 最大 4 桁まで入力でき、16 進文字列として評価した値をコードポイントとしてみなした時の対応する文字に変換される
  • U: 最大 6 桁まで入力でき、16 進文字列として評価した値をコードポイントとしてみなした時の対応する文字に変換される

^VU でのコードポイント入力は Unicode の BMP を超えた先も対応していて、その場合はサロゲートペアが生成される。

What wasavi is, and is not

昨日の記事を書く過程で wasavi に言及しているブログなんかをぐぐってみた。で、何件かあった。それ自体は、非常にありがたいことである。あるのだけど、その中にちょっと気になるものがあった:

これは、テキストエリアを編集中に規定のキー(例:Ctrl+Enter)を押すと、Vimモードになり、:q を入力するまで、Vimのキーバインドを提供してくれるもの。

vimscriptによるプラグインは使えませんが、Vimとしての再現度はなかなかよいと思います。

何が気になるといえば、つまり「Vim」の一語だ。

wasavi は vi のクローンであって、vim の何かではない。vim からいくつかの機能を拝借してはいるが、wasavi は vi のクローンであって、vim の何かではない。

したがって、vimscript が動かないんですけお! と言われても困るし、「vim の再現度」について評価されても「えっなんのこと?」としか答えることができない。なにより説明で “vi editor for any web page” と言っているのだ。なぜ vi ≒ vim という取り違えが起きるのだろうか?

これはつまり、現役の vi 系エディタのデファクトスタンダードが決定的に vim であるという現実がやはり根底にあるのだと思う。古い人間なら、vim なんて遅れてきた vi クローンの上にやたらめったら魔改造を施された、ある意味での異端児だ、などと思うだろう。つまり彼らにとっては、vi と vim は明らかに別のものである。しかし新しい人間にとっては、vi といえばつまり vim であり、vim のオリジンは vim 自身であり、historical vi はそのタイニー版でしかないということなのではないか。

将来 wasavi にスクリプティングやシンタックスハイライトの機能を実装するとして、その仕様はおそらく vim のそれとはかなり違うものになると思う。つまり今以上に「vim となんかちがうんですけど」的な扱い難いクレームが増えるかもしれない。これはなかなかに由々しき問題だ。

promote an extension

wasavi は Chrome、Opera、Firefox にそれぞれリリースしている。その中で、Chrome と Firefox はアクティブユーザー数を知ることができるのだけど、それぞれ 300 人台とか、100 人台とかである。これは、他のエクステンションを適当に眺めてみる分には、かなりつつましい数字だ。

これをたとえば万のオーダーにするには、やはりどこかのサイトで紹介されて爆発的に知れ渡る的なイベントが必要なんだろう。そして、それが起こるのを待つと言うよりはむしろ、こちらからいろいろな IT 系ニュースサイトに「wasavi を紹介してくださいお願いします」といった営業活動をしなくてはならないんだろうと思う。

しかしめんどくさそーなので別にやらないのであった。そもそもよく考えたら、ユーザー数が増えても別にメリットないじゃん。

the beast

Selenium に実行させるテストの総数が 666 になった(アサーションの総数は 2700 くらい)。

全コードの 66% が wasavi、33% がテストコードである。うーん半々くらいに持ってきたいところだが……。

clipboard access #3

クリップボードを介した貼り付けについて、Clipboard API をちょっと使用してみた。

貼り付けなので、ctrl+v か、shift+insert を押した場合に document に対して paste イベントが発生する。イベントハンドラの中で e.clipboardData.getData(‘text/plain’) とかすると貼り付けようとする文字列が得られる。その文字列を vi のコンテキストに従って適切に貼り付ける。また、e.preventDefault() してデフォルトのアクションは取り消しておく。

ただし、ctrl+v は挿入モードや行入力モードでのエスケープシーケンスの入力開始文字とかぶっている。そこで、貼り付けイベントを認識するのは shift+insert だけにした。この特別扱いを行うと、そのキーを再マップできなくなってしまうので、なおのこと ctrl+v は明け渡すことはできないのだ。

これにより、Presto Opera で wasavi を動かしている場合でも、限定的にクリップボードを使用することができるようになった。限定的というのはまず、書き込みはやはりできないということだ。また、コマンドモードで shift+insert した場合でもとりあえずクリップボードからの貼り付けを行うようにしたのだが、内部的には [cci]”*p[/cci] を実行するだけであり、エクステンション側でクリップボードの読み書きが自由にできない Presto Opera では動かない。

ついでと言ってはなんだけど、キーボード入力のハンドラで入れ子になっているコールバック関数を外に出した。つまりキー入力ごとに関数の評価を行なっていただろう箇所を取り除いたのだけど、なんか目に見えて入力のスピードが速くなった? えっそんなに差があるの。

wasavi 0.5.342 released

リリースした。Google Drive への対応と ex コマンド入力時の各種補完がメインになっている。

ファイルをアップロードするために Google Drive が提供する API を呼び出す際、Exponential Backoff なる方式にするといいよ、と google 先生は言う。

なにやら難しい専門用語である。exponential とは指数のことだ。しかし内容はわりと明快で、ファイルをアップロードした際に何らかのエラーが発生した場合のリトライの待機時間をべき乗則にするといいんじゃね? ということである。

wasavi ではこれは実装していない。書き込みが失敗したらエラーだよ♪ と表示されてそれだけだ。ファイルへの書き込みはユーザーが明示的に指定するので、エラーが発生したらユーザーが再度指定すればいいのである(このインターフェースには異論はあるかもしれない)。

Google Drive #6

ex コマンド filesystem を実装した。最短は files。最初の引数がコマンドであり、以下の種類がある:

  • default: ドライブ名を省略した場合に使用されるデフォルトファイルシステムを取得・設定する。
    取得
    :filesystem default
    設定の例
    :filesystem default gdrive
  • status: 現在使用できるファイルシステムの一覧を表示する。
    :filesystem status
    *** available file systems ***
    * dropbox /
    gdrive /foo/
  • reset: 指定のファイルシステムのアクセストークンを破棄する

また、ex コマンド pwd、chdir、cd も実装した。機能は読んで字の通り。

Google Drive #5

dropbox、google drive と、wasavi から複数のオンラインストレージを読み書きできるようになる。その場合、ストレージの種別を区別させる必要が出てくる。そのため、wasavi 上でのファイルパスは接頭辞を付けることができる。[cci]dropbox:/path/to/file[/cci] とか [cci]gdrive:/path/to/file[/cci] というような感じだ。

このようにファイルパスを操作するとき、ストレージ・プリフィクスは省略可能である。ということは省略したときはよきに計らってくれるデフォルト値が必要ということであり、すでに内部ではそれを持っている。ただし今のところ dropbox 固定であり、変更する手段がない。どういう変更手段を設けるべきか?

ex コマンドを新設し、[cci]:filesystem default dropbox[/cci] などと指定できるようにするか? あるいは、そうではなく、単にオプションを増やして、[cci]:set filesystem=dropbox[/cci] とさせるか。

うーん、後者が自然かな。ただし一方で、デフォルトのファイルシステムの指定、のようなメタな設定は他に

  • 取得したアクセストークンの破棄
  • 現在有効なアクセストークンに関連付けられたアカウントの情報の表示

のような機能はいずれ必要になる。そうすると、「ファイルシステムのメタデータを管理する ex コマンド」に一本化したほうが長い目で見ればいいのか?

省略可能といえば、パス自体も常に絶対パスで指定しなければならないわけではない。つまり仮想的なカレントディレクトリもまた内部に持っておき、相対パスが入力されたらカレントディレクトリと結合する必要がある。というわけで、カレントディレクトリも内部で持っているのだが、これもまた wasavi 上から変更する手段がまだない。どうするか?

vim であれば、vim 上のカレントディレクトリを参照するには [cci]:pwd[/cci]、変更するには [cci]:chdir path[/cci] である。

こちらは、素直に ex コマンド新設コースかもしれない。pwd とか cd コマンドがあまりにもポピュラーすぎてそこから一線を画す理由がない。[cci]:set cwd=/[/cci] なんてなんだか奇妙だ。特に、相対パスでカレントディレクトリを変更する場合の [cci]:set cwd=../foo[/cci] のようなものは実際の動作とも食い違う(cwd が代入した値そのものになるわけではない)ので奇妙以上におかしい。