2017/03/22 7:27 pm
Promise and Generator #2
Uncategorized, , ,

そういうわけでちまちまといじっている。

とりあえず vi コマンドを回す部分に関しては修正した。これで非同期の処理だろうが同期の処理だろうが不自然なく呼べるようになった。それはいいのだが、vi コマンド群は本丸ではない。qeema が発生するキーボードイベントから、各 vi コマンドのハンドラに達するまで、せいぜい 4〜5 の関数がネストするだけであり、ただそれを Promise を使うようにすれば済む。

難しいのは ex コマンドの方なのだった。

ex コマンドは、ex コマンド列をコンパイルして中間コードの配列に落とし、それを逐一実行するという構造になっている。なので、修正するとしたら ex コマンドごとに Promise をつなげていく、ex コマンド自体はそれぞれ resolve() でコマンドの終了を通知するといった形になる。

ただいくつか面倒な点がある。

  • write、read、edit などバックグラウンドに処理を投げるファイルシステム系のコマンドは、読み書きの進捗イベントをバックグラウンドから複数回返される。従来は、この複数回返されるメッセージというのは ex コマンドのハンドラの外で処理していた。というのも非同期的な ex コマンドを実行する際は一旦そのコマンドの同期的な部分のみを実行したあと executor を一時停止し、バックグラウンドから処理完了メッセージが到着したら executor.resume() で再開するようになっていたからだ。これは処理が分散しているといえばそうなので、若干不自然ではある。

    個々の ex コマンドを Promise によって駆動するのであれば、複数回返されるメッセージの扱いというものも ex コマンドのハンドラ内で完結できるわけで、そうすべきだと思う。具体的にはハンドラ内で long-lived connection をその都度行い、コマンド完了時に閉じればいい

  • シグナルの扱い。シグナルというと若干語弊があるのだけど、つまりやはりファイルシステム系の時間がかかるコマンドの実行中、^C が押されたらキャンセル扱いにする処理のことだ。これも Promise 化によって中身がかなり変わる。

ちなみに非同期で実行される ex コマンドとしては

  • cd
  • edit
  • read
  • c オプションが付加された s
  • 非同期とマークされたオプションの値の変更を含んだ set
  • write

となっている。また、レジスタを指定できる ex コマンドで * レジスタが指定された場合も非同期になる。レジスタを指定できる ex コマンドは、

  • delete
  • put
  • yank
  • @
  • *

となっている。非同期とマークされたオプションは以下のとおり。

  • fullscreen
  • syncsize
  • columns
  • lines

2017/03/17 8:27 am
Promise and Generator
Uncategorized, , ,

Migemo Server for Google Chrome™ というものがある。これ自体は migemo のライブラリのように動作し、外部の拡張からのリクエストを受け入れ、適切な結果を返す。

これに対応してみようかなとコードを頭の中で組み立ててみたのだけど、すぐに行き詰まってしまった。というのも拡張から拡張への通信というものは非同期に行われるからだ。一方で wasavi がキー入力を処理する構造は同期ベースで、非同期な動作を組み入れるのはとっても大変なのだ。

この辺を、Generator と Promise を組み合わせて使うようにすればとてもすっきり書けるのだが。なぜ今までそうしなかったかと言えばすなわち Presto Opera でも動かすためだ。Opera 12 は Promise の Polyfill は動くが、Generator は無理なのだ。

しかし、もう wasavi/0.6.657 で Presto Opera のサポートは終了した。従っていよいよそのへんを書き直す頃合いだ。これは割と大掛かりな仕事になるかもしれない。

2017/03/16 7:15 am
Unicode data updated
Uncategorized, , , ,

wasavi は内部(unicode_utils.js)にいろいろと Unicode のプロパティの情報を持っている。それらの情報は、例えば f/F/t/T コマンドにおける検索対象の判別とか、textwidth オプションを介した自動的な折り返しの際に適切な折り返し位置を見つける処理とか、さまざまなところで役に立っている、なくてはならないものだ。

今までは、それらのプロパティは Unicode 6.2.0 ベースだった。6.2.0 といえば 2012 年の話であり、さすがにちょっと古くなり始めた感が否めない。そういうことで今回 9.0.0 に引き上げた。同時に、プロパティを javascript のコードに変換するスクリプトを今までは PHP で書いていたが、javascript で書き直した。これで、wasavi 本体は当然として、ビルドスクリプトも、テストスクリプトも、データ生成スクリプトもほぼ全てが javascript になった(なったからどうというものでもないが)。

ところで Unicode の各種プロパティのバージョンを引き上げて、それでおしまいというわけではない。データを使用する javascript のコードも Unicode 9.0.0 に合わせる必要がある。ということで合わせた。とても疲れた。

Unicode 絡みで言うと、unicode_utils.js 以外に Unistring というライブラリも使っている。こちらもとても重要なものだ。Unistring が文字列を grapheme cluster 単位に分解することで grapheme cluster 単位のカーソルの移動を実現している。これがなくては、テキスト中に絵文字が 1 つあっただけでカーソル移動がめちゃくちゃになってしまうのだ。

ということで Unistring が持つ内部のテーブルも 9.0.0 に合わせた。4351 件のテストにもパスする。

2017/03/12 8:14 pm
Unit testing
Uncategorized, , ,

wasavi の動作の保証として Selenium を用いた機能テストを通してからリリースしているわけだが、まとまった、自動化された形でのユニットテストは行っていなかった。これはけっこうイケてないので、ユニットテストの仕組みを構築したい。

そんなわけでいくつかのユニットテストコードを追加した。特に難しいことはなく

$ mocha src/unit-tests/strftime.js

などとする。

2017/03/11 5:08 pm
Specifying an offset
Uncategorized, , ,

/ および ? コマンドには、デリミタに続けてオフセットを付加することができる。オフセットには符号を先行させてもよい。つまり

/foo/+
/foo/1
/foo/+1

はいずれも、カーソル行以降の foo を検索し、その次の行にカーソルを移動させる。同様に

?foo?-
?foo?-1

はカーソル行より前の foo を検索し、その前の行にカーソルを移動させる。

オフセットを付加したとき、モーションは行志向であるとみなされる。ところでこのオフセット機能は POSIX で定義されているものなのだが、オフセットを付加した時の桁位置はどうなるのかというとなぜか記述されていない。大抵の場合、行志向のモーションはカーソルをその行の最初の非空白文字に置くので、そうした。vim もそうなっている。

ちなみに POSIX ではデリミタ以降にオフセットではない余計なものがついてたらエラーにしなさいとか、オフセットを計算した後の行位置がバッファの先頭行や最終行を超えていたらエラーにしなさいとか、オフセットの他に z コマンドも有効としなさいとか言っているのだが、その辺は実装していない。vim も実装していない(たぶん)。

2017/03/09 4:04 am
Increment and Decrement #2
Uncategorized, , ,

ノーマルモードでの ^A^X を作った。このコマンドは . の対象にもなる。

次に、bound モードでの動作を考える。vim では visual/visual line/visual block モードでも増減ができる。ノーマルモードではカーソルが位置する数値文字列が対象になるが、visual 系(謎)モードでは、選択された領域の各行の、最も左端にある数値文字列が対象になる。これは若干違和感がなくもない。選択された領域内のすべての数値文字列が対象になってもおかしくないのではないのか? 後で考える。

ちなみに、それを作るときにも書いたが、vim における visual 系モードは wasavi では bound/bound_line モードになっている。なぜモード名を変えたのかといえば、そもそも vi というものが ex の visual モードにほかならないからだ。命名がダブっている。

 * * *

bound モードでも動作するようにした。vim と違い、領域内の全ての数値文字列が増減の対象となるようにした。

それから、vim のように set nrformat+=octal などという特殊な代入をできるようにするかどうかだが、とりあえず、保留。

2017/03/06 5:21 am
Vim and IME
Uncategorized, , ,

最近日本語の文章をちょっと多めに書く機会がある。そのために端末上の vim を使っているわけなのだが。

いまさら書くまでもないのだが、vi と IME を経由した入力の相性はとっても悪い。特に、ノーマルモードにいる状態で IME がオンになっている場合にぐぬぬとなる。せめてこれだけでもなんとかならないのだろうか。

IME が fcitx 上で動いている場合、/usr/bin/fcitx-remote コマンドによって IME の状態を操作することができる。なので、vim のそれっぽいイベントに自動コマンドを引っ掛けて fcitx-remote を適当に呼んでやる。

autocmd InsertLeave * silent! !fcitx-remote -c

こうすると insert モードを抜けた時、必ず IME がオフになる。これでいくらかましになるかなー。

ちなみに wasavi の場合、ノーマルモードに戻るとやはり自動的に IME が無効になるようにしてある。実はノーマルモードでキーボード入力を受けるのは、隠された input[type=”password”] 要素なのだ。大抵のブラウザが、この要素がアクティブなときは IME を無効にすることを利用している。

残念ながら、IME の状態を直接的に制御するような API は javascript にはまだない。

2017/03/02 5:04 am
Increment and Decrement
Uncategorized, , ,

issue #145

これは、vimの ^A および ^X が欲しいよという要望だ。これらは、カーソルの下にある数値らしきものを指定したカウンタの分だけ増減させる。^A は増加させ、^X は減少させる。

オプション nrformats の値によって動作をカスタマイズできる。これはカンマ区切りで文字列を格納する前提になっていて、以下のコンポーネントが意味を持つ:

  • alpha – \b[a-zA-Z]\b をアルファベットのリストアイテムと認識する。大文字か小文字かで分類し、それぞれ [a-z] と [A-Z] をローテーションする
  • bin – 0b[01]+ を2進数表記と認識する
  • hex – 0[xX][0-9a-fA-F]+ を16進数表記と認識する。大文字か小文字かどちらかを取るかは、マッチした文字列の最も右端に位置するアルファベットに依存する。アルファベットがない場合は、2文字目が x か X かに依存する。
  • octal – 0[0-9]* にマッチし、かつ、0[0-7]* にもマッチする部分を8進数表記と認識する。なぜこれだけ判定がややこしいのかというと、00018 のような文字列を 0001 と 8 に分割されてしまうのを避けるため。またこのコンポーネントを有効にすると、どうでもいいことだが C 言語と同様 0 は8進数の0と認識される

これらのコンポーネントに対するマッチの最後に、必ず -?[0-9]+ を10進数表記と認識する処理が入る。で、カーソル行に対してマッチした文字列群のうち、カーソルの桁位置を内包するものが処理対象になり、指定したカウンタの分だけ値を増減する。基本的には以上だ。

いくつか気を付けるべきポイントがある。

  • 0 で始まる、10進数以外の数値文字列の場合、値を増減してもできるだけ元の桁数を維持するよう適宜左に 0 をパディングする
  • 10進数と認識される数値文字列(これには、0で始まるが [89] を含む数値文字列も含む)の場合は、逆にいかなる場合も先行する 0 をすべて削除する
  • vim の仕様だと、-0001 みたいなのは octal を含んだ nrformats の場合に若干不自然な動作になる。つまり負の符号が先行しているが、正の8進数文字列と認識される。これはいいのか?
  • Selenium のテストで、あるテスト中に複数のアサーションを行う時、”#1-1″ とか “#1-2” とかラベルをつけている(そもそも複数のアサーションを詰め込むべきでないとか、もっと自己記述的なラベルにすべきとかはこの際置いといて)このラベルの右端の数値を増減させたい場合、ハイフンが邪魔になり動作が反転してしまう。これはなんとかならないのか。つまり負の符号ではなくハイフン、あるいは減算の演算子であるかを判別できるといいんだけど
  • vim では、nrformats の型は文字列だが、実質的にはカンマ区切りの配列構造として扱うことになる。これは身近な例で言えば DOM における className と classList の関係に似ている。全体をまるごと書き換えるのでなければ、classList を通して操作するほうが圧倒的に便利だ。同じことが vim にも言えて、set nrformats+=foo とか、set nrformats-=bar のような演算子が用意されている(vim の、というか vi の set 構文はいわゆる普通のプログラミング言語とは若干趣が異なるので演算子と言っていいのかはわからないが)。これを wasavi でもサポートすべきか?

2017/02/26 2:02 pm
implicit addressing
Uncategorized, , ,

たとえば

foo
bar
foo
bar
foo
bar
foo
bar
foo
bar

という 10 行のテキストがあり、カーソルは最終行にあったとき、テキスト全体をコピーして末尾にペーストしたいとする。

vi コマンドであれば、ggyGGp で 6 手である。ex コマンドにおいても :1,t.<enter> と 6 手。個人的には行単位のコピーは ex コマンドを使うほうが多い。

ところで :%t.<enter> のほうがさらに 1 手少ないが、別に vi/ex ゴルフがこの記事の主題ではない。上記の ex コマンド中、t はコピー命令であり、その直前までが行の範囲を示している。開始行は 1 で、カンマが続き、そして終了行は省略している。省略するとカーソル行が割り当てられる。その処理を wasavi に入れ忘れていたので、入れた。

2017/02/24 9:48 am
migrating Dropbox API v1 to v2
Uncategorized, , , ,

Dropbox側の修正を終えたのでテストしてみたところGoogle Driveに対する読み書きでコケる。なんで?

OAuth2による認証が成功した直後、自身のプロファイル情報を得るAPIを呼び、認証に成功したIDと一致することを確認している。Google Driveの場合は、

https://www.googleapis.com/oauth2/v1/userinfo

に対してPOSTして返ってくるjsonを参照している。このエンドポイントが404を返すようになった。11日前にwasaviをリリースした際にはもちろんすべてのテストが通ったことを確認してあるので、その間になんか変わったようだ。

Googleが提供するAPIの包括的なリファレンスというのは、どこにあるのかよくわからない。しかしAPI Explorerというものがあり、実質的にここでAPIの仕様を確認できる。ということで Google OAuth2 API v2 を見てみると確かにuserinfoはない。その代わりoauth2.userinfo.v2.me.getというものがあるのでこれがどうも最新のようだ。エンドポイントは

https://www.googleapis.com/userinfo/v2/me

だ。これにどのフィールドを参照するかのクエリ文字列(今回の場合は?fields=id)を付加して、GETで取得すると結果が返ってくる。

API Explorerで参照できるAPI名らしきものとエンドポイントのURLの構造が微妙に似ているような似てないような感じになっているのは何なんだろう。わからん。それと、この最新のAPIを使ったとしても、POSTだとやはり404が返される。ちゃんと書いてあるとおりにGETじゃないといけない。

アーカイブ