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 では動かない。

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

yet another vi clone #4

javascript 製の vi というものをググってみると、以前から JS Vim なるものがひっかかるのだが、概要に述べられているリンクが 404 だったり、ドキュメントの類が一切なかったりで、何者がどういう意図で作ったものなのかよくわからず、気になっていた。

どうも ここ が現時点で有効なサイトのようだ。ページ上に実装済みの機能が示されているが、それほど多くはない。また、ex コマンドのたぐいはまだ実装されていない。

作った人の位置づけとしては vi clone ということらしいのだが、個人的な感覚で言えば、ex コマンド群を実装せずに vi clone と名乗るのは良くない。それはせいぜい「なんちゃって vi clone 見習い心得」くらいのものだ。

それはそれとして、sourceforge 上のソースは 2.0 だが、件のページでは 3.0 と地道に更新されているようなので、頑張ってほしいと思った。

Opera Next 16.0

Opera Next 16.0 が公開されていた。それほど目新しい新機能が追加されているわけではない(開発中のものは opera://flags から幾つか試すことができる)。

Presto Opera ユーザーが納得する出来に到達するには、Opera 18、いや 20 くらいまでは待つ必要があるだろう。

15、16、17 と…… Opera の人生暗かった。

wasavi 0.5.342 released

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

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

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

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

upgrade VirtualBox

Windows Vista から導入された UAC というものがある。それにともない、Administrator 権限を持っているユーザーであっても通常は制限された権限、必要なときは権限のエスカレーションを行う、といった *nix 的な作法に慣れていると無駄に複雑だなーと思える機構が導入された。同じユーザでもコンテキストによって権限が行ったり来たりするのである。

一方で Administrator 権限を持つアカウント、一般ユーザー権限のアカウントをそれぞれ作り、通常は一般ユーザーでログオン・作業し、必要なときは Administrator 権限を持つアカウントのユーザーのパスワードを入力する、という運用もできる。コマンドプロンプト上でのシンボリックリンクの作成が、こちらの運用方法じゃないと機能しないので、うちではそうしている。

さて数日前 VirtualBox の新しいバージョンが公開されたというので、一般ユーザーでログオンしている状態でダウンロードし、インストーラを実行させた。すると、インストール自体には成功して GUI のフロントエンドは起動するのだが、VM を立ち上げようとすると Kernel Driver が云々といったエラーで実行されなくなってしまった。また、extension pack を更新しようとしても、何やら権限が足りません的なエラーが出る。

これはおそらく前述の、一般ユーザーでログオン + インストーラ実行時に Administrator 権限のユーザーに仮想的にスイッチ、という環境特有のものなのだと思う。おそらくインストーラが複数のプロセスで構成されていて、子プロセスに正しく権限が継承されないまま実行されてしまっているのではないか? と考えて、Administrator 権限を持つユーザーでログオンしなおし、VirtualBox のインストーラを再度立ち上げ、修復インストールした。すると、一般ユーザーでログオンした状態でも正しく起動するようになった。

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 が代入した値そのものになるわけではない)ので奇妙以上におかしい。

Google Drive #4

  • 前回の記事で Google Drive 上のファイルを読み出すために 3 回のアクセスが必要と書いたが、パスの構築時に basename も含めることでこれを 2 回に抑えることができた。
  • あるファイルがその親ディレクトリを複数持てるというのは、そのままの通りの意味のようだ。ハードリンクみたいな感じか。ちょっとこれは面倒なのでちゃんと対応するのは後回し。現状では、パスの構築時は親は 1 つだけの前提にしている。
  • ファイルの実体を読み出す際、ファイルのメタデータに含まれる downloadUrl が指すアドレス(たいてい https://*.googleuserconent.com/*)を参照することになる。一方で、OAuth 2.0 による承認を行う際、スコープと呼ばれる識別子を送る。[cci]https://www.googleapis.com/auth/drive[/cci] が最も強い権限、[cci]~/drive.file[/cci] がファイルの操作、[cci]~/drive.readonly.metadata[/cci] がメタデータの読み込み、みたいな。

    このうち最も強い権限を持つ drive スコープはほんとうに必要な場合のみ使ってね! とドキュメントにも明示してあるのだが、どうも downloadUrl からの読み込みは drive スコープじゃないと行えないような。drive.file だと 404 が帰ってくる。これは……バグじゃないのかな。というわけで drive スコープを使わざるを得ない。そんなような問いと答えが stackoverflow にもあった。

残るのはファイルの書き込み。

Google Drive #3

Google Drive 上の、あるファイルへのパスが与えられたときそれを読み込む手順は以下のとおりとした:

  • パスを dirname と basename に分割する
  • dirname をディレクトリ名ごとに分割し、各フラグメントを [cci]title=’ディレクトリ名'[/cci] に変換し、[cci]or[/cci] で結合してクエリ文字列を得る。[cci]/foo/bar[/cci] は [cci]title=’foo’ or title=’bar'[/cci] となる
  • File:list API を呼び出す。このとき q パラメータは上のクエリ文字列を与える
  • API の結果から、目的のパスに合致するメタデータの並びを得る。上の例で言うと、まずディレクトリ bar があり、その親 ID を持ち、かつタイトルが foo であるものを抜き出す。その処理をルートに向かって再帰的に行い、ルートに達した(分割したディレクトリの個数 == 抜き出したメタデータの個数となった)らパスが決定する
  • File:list API を呼び出す。このとき q パラメータは dirname の最後のフラグメントの fileID を親に持つファイル、とする。つまり [cci]’fileID’ in parents[/cci] とする。これは Children:list API でもよい気がするが、Children:list は指定のファイルの子供の ID しか返さない。
  • API の結果から、basename に一致するものがあれば、その downloadUrl を用いてファイルの内容を読み込む。なければ新しいファイルの編集とみなし、空文字列を wasavi へ返す

つまり 1 つのファイルを読み込むのに 3 回のリクエストが必要になる……それにしてもイケてないなー! もっとうまい方法はないのかしら。

あと、ひとつ気になる点がある。あるファイルのメタデータ内に、その親ファイルの ID が格納されているのだが、名前が parents で、型は配列なのである。あるファイルが複数の親を持つことができる? どうやって?