最終的に 508 項目のテスト、2044 個のアサートとなった。Opera、Chrome、Firefox の各ブラウザにおいて、ペンディングになっている 2 点ほどを除いたその他のテストにパスした。
Category Archives: Uncategorized
the last
ex コマンド最後のテスト、@ コマンド。
@ コマンドは、指定のレジスタに格納されている文字列を ex コマンドとみなし、実行する。vi コマンドにも @ があり、vi コマンド版 @ は ex コマンドを含むことができるのでつまり上位互換ということになっている。ex コマンド版の @ はレジスタの内容をあくまで ex コマンドとして実行する。
[addresses]@register
レジスタが省略されたか、文字 @ が指定された場合は、最後に実行されたレジスタ名が用いられる。レジスタの実行がまだ 1 度も行われていない場合は、エラーになる。
addresses で指定された範囲の各行について、まず現在行( . )にセットされ、そしてその時点で @ コマンドが実行されたかのように、名前付きレジスタの内容が ex コマンドとして実行される。ex コマンドパーサは、行指向で保存されたレジスタの各行と、文字指向で保存されたレジスタの最終行以外の行は、末尾に改行がついたものとして扱う。
処理の間にエラーが発生した場合、または addresses で指定された行がそれを現在行としてセットする段階で存在しなかった場合、または addresses として複数行が指定されかつバッファの内容が(たとえば ex コマンド edit によって)置き換えられた場合、エラーとなり、エラーメッセージが表示され、このコマンドの実行は打ち切られる。
* * *
最後の段落以外は、特に問題はない。最後の段落は実はよくわからない。たとえば現在行の次の行を削除するような ex コマンド(+1d とか)を、複数行を対象に、@ コマンドで実行したとする。すると、仕様で言っているような addresses には含まれているが、レジスタの内容を実行する段階では存在しない行というのが確かに生まれる。仕様では、そういう行を見つけたら即エラーにすると言っている。それはどうなのか? その動作は global コマンドとも異なっている(global コマンドはマッチした行を覚えておくフェーズと、それらの各行に対してコマンドをは実行するフェーズで構成される。第 2 フェーズのループ内では、第 1 フェーズにおいて覚えておいた行が存在しなくてもエラーにせず、次の行へスキップする)。
また、レジスタに格納されている ex コマンドが明示的に addresses を含んでいる場合、@ コマンドに対する addresses とどう折り合いをつけるかは仕様では示されていない。置き換えるのか、マージするのか、レジスタのそれを優先するのか?
vim はこの点について、@ コマンドに付随するアドレスは addresses ではなく実質的に address であるという仕様にしているようだ。これはちょっと特殊で、コマンド自体は複数行の範囲を受け付けるが、実行はその先頭行のみに対して行われる。先頭行を現在行に設定しレジスタの内容を実行する、それで終わり。ヘルプを読む限りでは将来的には複数行に対応するかもねということになっているが、posix による定義が曖昧なのが解決しない限り対応は難しそうだ。
ということで、wasavi でもそれに従う。
under the control
コードポイント U+0000 から U+001F はいわゆる制御文字とかコントロールコードと呼ばれる文字を表す。
この中で、今日日プレーンテキスト内によく使われるのは CR、LF、TAB、FF、VT くらいで、その他の文字はほとんど使われることはないのだけど、それでもなお存在はしている。
vi では、入力モード中や ex コマンド入力中に特別なシーケンスを用いて制御文字を入力することができる。まず ^V を押し、次に入力したい文字を押す(U+0000 から U+001F までは ^@ から ^_ に対応している)。
textarea に書き込むテキストにもまた、それらの制御文字が必要だとは思えないが、wasavi でも ^V によるエスケープを用いた入力に対応している。ただし、vim のように ^V + 8 進数によるコードポイント入力には未対応。
さて入力できたとして、それをどう表示するかが問題になる。本来は表示上も ^K とかいう形式にしたいのだが、wasavi では 1 行の表示はブラウザ任せなので、なかなかそこまで制御できない。制御文字に対応する部分を
^K
のような形にすればいいのだが、まだそこまでやっていない(編集するテキストが span によって分割されていることを前提にするのは、たぶんシンタックスハイライティングの実装とセットになるので)。
そこで、Unicode には Control Pictures というものがあるので、とりあえず wasavi が管理するバッファ内の制御文字は U+0000 -> U+2400 みたいな変換を施して保持している。もちろんバッファ内のテキストを外部に出力する際は本来の制御文字に逆変換する。
ただ、これだと Control Pictures の各文字が等幅じゃなかったり、ブラウザによって見た目が違ったり、下手すると表示されなかったり、制御文字ではなく U+2400 ~ U+241F そのものを扱えなかったりするわけなので、まあ本当に「とりあえず」の仕様だ。
ところで「等幅」の読みって「とうふく」だと長年思っていたら、なんかググると「とうはば」らしいですよ。大ショック。
quit, wq
ex コマンド quit は vi を終了させる。
q[uit][!]
コマンド名に文字 ! が後続していない場合:
- 最後に完全な保存が行われてからバッファが変更されていれば、エラーにする
- vi の起動時に与えた引数リストのうち、現在参照しているファイル以降の編集待ちファイルが待機しており、かつ、最後に実行したコマンドが quit、wq、xit、ZZ のいずれでもない場合は、エラーにする
コマンド名に文字 ! が後続している場合は、編集セッションを終了する。
引数リストというのは、
$ vi foo.txt bar.txt baz.txt
などというコマンドラインで vi を起動した際に与えたファイル名の配列 [foo.txt, bar.txt, baz.txt] のことだ。さて、foo.txt の編集中に :q する。すると、(vim の場合)2 more files to edit などというエラーになる。残りの bar.txt と baz.txt どないすんねんと怒っているわけだ。ただ、:q してさらに :q した場合などは、なんやそないに終了したいんなら言うとおりにしたるわ、と妙にユーザーフレンドリーな振りまいをし、終了する。
なお wasavi は引数リストをサポートしていないので、このルールは関係ないし関西弁でしゃべったりもしない。
* * *
というわけで write と quit コマンドがあるのだが、実際にファイルを編集、特に数行編集して即 vi を抜けるなんていう場合、2 回 ex コマンドを投入したり、あるいは :w|q と打つのが面倒だということなのか、wq というコマンドが用意されている。
wq は write をまず実行し、成功したら quit を実行するという処理をひとまとめにして行う。wq のシンタックスは write と同じである。
See the write
ex コマンド w、q、wq、x。
これらのコマンドは、編集中のバッファの内容を書き出したり、vi 自体を終了したり、その 2 つのの動作をひとまとめに行ったりする。バッファの内容を書き出すことと vi を終了することには、本質的には強い関連性はないのだけど、実践的なコマンドの使用頻度を鑑みたのか、ex コマンドの体系では結び付けられている。
基本となるのは w(write) コマンドと q(quit) コマンド。
write
[addresses]w[rite][!][>>][file]
w コマンドはバッファの内容をファイルに書き出す。
通常、addresses を明示せずに ex コマンドを実行した場合、対象となる行は単にカレント行であるが、write コマンドは global や v コマンドとともに規定値がバッファ全行になっている。
ファイルへの書き込み
w コマンドのコマンド名に空白文字が後続していない、または file が文字 ! で始まっていない場合は、書き込みはファイルに対して行われる。
- 引数 >> が指定されており、かつ file がすでに存在している場合、バッファの内容はそのファイルの内容を置き換えるのではなく、追記される。>> が指定されているにもかかわらず file が存在していない場合、>> が指定されなかったものとして振る舞うか、書き込みが失敗するかは未定義である。
- readonly オプションがセットされている場合、書き込みは失敗する。
- file が指定されているが、それがバッファに結び付けられたファイル名ではなく、かつ file が存在する場合、書き込みは失敗する。
- file が指定されなければ、バッファに結び付けられたファイル名が用いられる。バッファにファイル名が結び付けられていなければ、コマンドは失敗する。
- バッファに結び付けられたファイル名が用いられ、かつそのファイル名は file または read コマンドによって変更されたものであり、かつそのファイルが存在する場合、書き込みは失敗する。一旦書き込みが成功した後は、後続する書き込みはこの理由で失敗してはならない(再びファイル名が変更されない限り)。
- バッファ全体を書き出せず、かつ書き込み先ファイルが存在する場合、書き込みは失敗したとみなす。
コマンド名に ! が続いている場合、ルール 1.、2.、3.、5. において書き込みは強制的に行われる。
writeany オプションがセットされている場合、ルール 2.、3.、5. において書き込みは強制的に行われる。
この他の実装依存の条件判定により書き込みが失敗することもある。
バッファが空である場合、空の内容で書き込みが行われる。
書き込まれた行数とバイト数の情報がメッセージとして表示される必要がある。
プログラムへの書き込み
コマンド名の後に 1 文字以上の空白が続き、かつ file の先頭が文字 ! である場合、文字 ! の後の残りの文字列は、文字 %、#、! について展開が行われる(展開の詳細は省略)。
ex/vi は shell オプションで指定されるプログラムを起動し、2 つの引数を渡す。1 つめは -c である。2 つめは write コマンドへの引数(展開済み)が単一の引数として渡される。バッファ内の指定された行は起動したプログラムの標準入力へ書き込まれる。プログラムからの標準エラーや標準出力があれば、print コマンドの出力のように表示される。出力の最後の文字が改行でなければ、改行が出力される。
write コマンドに続く文字 ! はバックスラッシュによって効果を打ち消すことができる。
finding a max z-index
wasavi の新しいビルドはだいたい週末にここにアップし、さらに某掲示板でアナウンスしているわけなのだが、その中に
クロームでふたクロ使ってると
フローティングのテキストエリアの下にviの編集ウインドウ開いちゃうね
調節する方法あるのかな
これわさびで入れてみたよ
というリプライがあった。ふたクロというのはその某掲示板向けの Chrome 用拡張だ。
さてこれは要素の上下関係の問題だ。具体的には、2 つの要素のそれぞれの z-index プロパティの値の関係だ。確認してみると、ふたクロが生成する textarea のその親となる form の z-index は 2000000013 とかそんな感じだった。20 億飛んで 13。一方で、wasavi が生成する iframe には 16777215 すなわち 0x00ffffff を入れている。したがって wasavi のほうが隠れるというわけだ。
直接的には、20 億飛んで 13 を超える z-index 値、たとえば 0x7fffffff を割り当てるだけの話だが、そんなんでいいのか? という気も。まずこの値は経験則的な最大値でしかない。32bit バイナリでブラウザを動かして、z-index がとりうる値は負の値を含む数値で……なんてところだとまあ最大値はたぶんこれだろう程度のものだ。しかし CSS2.1 の仕様では z-index の最大値には特に記述がない。すると、もしかしたら 64bit バイナリなブラウザではさらに大きな z-index 値を指定できる可能性もなくはないということになる。そうすると 0x7fffffff を指定したところで意味がない。
実はある時期までは、wasavi の起動時に全要素を舐めて、その時点での最大の z-index 値を算出し、それを超える値を wasavi に与えていた。これならどの環境でも問題ない。手法としては、やはりこれが正道だ。しかし、全要素を舐めるわけなので当たり前なのだが、算出処理がとても重いのだ。100ms オーダーで時間を要する。
次善の策として、全要素ではなく、対象となる textarea 要素をその親へ遡った部分ツリーだけを算出の対象にするという方法もある。これならまあせいぜい数 10 個の要素を舐めるだけの話だ。ただこれだと必ず最大の z-index を得られるわけではないんですけどね……まあしかたないかな。
そういうわけでそう修正。
set me free
ex コマンド、set のテスト。
set [option[=value] | nooption | option? | all]*
単純なコマンドに見えて、意外に奥が深い。
引数がまったくない場合、デフォルトの値から変更されているオプションが表示される。
引数が all を含む場合、すべてのオプションが表示される。posix では all が排他的とは定義されていない。つまり、:set report all などと入力すると report の値を表示し、次に全オプションを表示する……ような実装が定義にもっとも素直に従っている。vim もそう動作する。これに対し、wasavi では最初に引数を走査し、all を含んでいたら他の引数は無視し、単に全オプションを 1 度だけ表示する。
オプション名に続き、文字 ? を入力した場合、現在のオプションの値が表示される。? とオプション名の間には 0 文字以上の空白を挟むことができる。2 値タイプのオプションでは、現在のオプション値を表示するのに ? の入力は必須である。2 値タイプ以外のオプションでは、? を付けても付けなくても、代入式でない限り現在の値を表示する。
2 値タイプのオプションが set option の形式で指定された場合、option の値はオンになる。一方、set nooption の形式ではオフになる。2 値タイプ以外のオプションで nooption 形式を指定するとエラーになる。
2 値タイプ以外の、数値や文字タイプのオプションでは set option=value 形式で値を与えることができる。このとき、value 内に空白を含めるには、空白の前にバックスラッシュを置く必要がある。1 文字以上の空白は引数の区切りとみなされる。これにより、単体の set コマンドで複数のオプションをセットしたり表示したりできる。オプション名と = の間には 0 文字以上の空白を含めることができる。
Firefox freezes with Flash 11.3
Firefox でテストしようとして起動したら即固まった。
なにやら巷でも問題になっているようだ。話には聞いていたが、Firefox はめったに使わないので対岸の火事だった。
保護モードを解除する、セキュリティアップデートだけは提供されている旧バージョンに戻すなどの回避策があるらしい。が、とりあえず flash プラグインを無効にした。
で、無効にして適当に web サイトをめぐってみて気付いてしまったのだけど……。
flash のない web って意外に普通に困らないな。
substitute!
ex コマンドの華、s コマンドのテスト。
[addresses] s[/pattern/replacement/[options][count][flags]]
指定された範囲 addresses の各行について、正規表現 pattern にマッチする箇所を replacement で置換する。pattern を囲む区切り文字は / の代わりに \、|、改行、” 以外の非アルファベット文字を用いることができる。\ は区切り文字や \ そのものなどの特殊な文字をエスケープすることができる。
pattern、および replacement の直後の、コマンドラインの末尾となる区切り文字は、省略することができる。pattern と replacement が両方省略された場合、最後に実行された s コマンドが繰り返される。pattern が指定されないか空の場合、vi 全体で最後に使用された正規表現が用いられる。replacement が指定されないか空の場合、pattern にマッチする箇所は空文字列で置換される。replacement 全体が % である場合、最後に s コマンドで使用された置換パターンが用いられる。
replacement 内でのキャリッジリターン(ex モードでは \、open/vi モードでは ^V によるエスケープで入力)は、入力箇所で行を分割してバッファ内に改行を生成することを意味する。キャリッジリターン自体は無視される。
options が文字 g(global を意味する)を含んでいる場合、行内において pattern にマッチする範囲が互いに重ならない形式ですべて置換される。
options が文字 c(confirm を意味する)を含んでいる場合、確認モードになる。pattern にマッチした箇所が画面に現れる。vi はユーザーからの反応を待つ。肯定的な応答(y など)が入力されると置換が行われる。他の入力では行われない。
検索方向が未保存の場合、s コマンドはそれを「前方」にセットする。
s コマンドの亜種として & コマンドがある。& コマンドは
s/pattern/replacement/
として置き換えられる。このとき pattern および replacement は前回の s、&、~ コマンドで使われたものを用いる。
もうひとつの亜種として ~ コマンドがある。~ コマンドは
s/pattern/replacement/
として置き換えられる。このとき pattern は vi 全体で最後に使用された正規表現、replacement は前回の置換(&、~ を含む)で使われたものを用いる。
コマンド終了後、カーソル位置は、置換が行われなかった場合は変化しない。置換が行われた場合は、最後に置換が行われた行の、最初の非空白文字に置かれる。
replacement の書式
文字 &(magic オプションがセットされていない場合は \&)は、pattern にマッチし置換されるべき文字列を示す。文字 ~(magic オプションがセットされていない場合は \~)は前回の s コマンドで使用された replacement を示す。\n(n は整数)は、pattern で指定される後方参照式に対応するものを示す。n は後方参照式の出現インデックスを示す。対応する後方参照式がない場合、\n は空文字で置き換えられる。
\l、\u、\L、\U は置換文字列内の要素(リテラル、&、\n)の大文字小文字を操作する。\l と \u は後続する 1 文字の大文字小文字を操作する。\L と \U は後続する文字列を \e または \E が現れるか、置換文字列の最後まで、大文字小文字を操作する。
この他の文字はその文字そのものとして扱われる。
……だそうです。
Opera 12 is landed
Opera 12 がリリースされた。
せっかくなので、64bit 版をインストールしてみた。
32bit から 64bit へ自動的に移行とかはしてくれない。32bit 版をアンインストールして 64bit 版をインストールした(といっても排他的ではなく両方同時に実行可能だと思うけど)。
プロファイルに完全な互換性があるのかは不安だったので、新しいプロファイルを生成させた後、wand.dat とメール関連のファイルだけを元の 32 bit 版から移植した。wand.dat はだいたい以下のような感じの場所にある:
C:\Users\akahuku\AppData\Roaming\Opera\Opera_x86
akahuku とか Opera_x86 とかは適宜自分の環境に置き換えるべし。ふつうは Opera_x86 じゃなくて単に Opera だと思う。
メール関連は Roaming ではなく
C:\Users\akahuku\AppData\Local\Opera\Opera_x86
内の mail ディレクトリに入っている。アカウント情報とかも入っている。したがって単に mail ディレクトリを x64 版側のプロファイルへ移動させれば移行完了。また、Local プロファイルには widgets ディレクトリという extension のデータも入っている。これも x64 版プロファイルへ移動させれば移行できると思うが、未確認。
とりあえずこれで 64bit 版 Opera を起動させ、あとはちまちまと設定しなおす(フォントとか)。それでも Opera Link のおかげでいろいろと手作業での移行も楽になっている。
というわけで 64bit 版 Opera 12.00 で書いているのであるが。とりあえず気付いたところは:
- 終了時にプロセスが完全に消えるまで何やらゴリゴリとディスクアクセスして、下手すると完全終了まで 30 分くらいかかることがあったのが、今のところすんなり終了するようになった。64bit 化の恩恵なのか、12 で修正されたのか、インストールしたてだからなのかは不明
- 全体的には速くなってると思う。たぶん
- Hardware Acceleration が実験的に実装されているが、うちの環境(gforce 9500 GT)では Direct3D バックエンドが有効になるものの、なかなかに不安定。あと、H/A 環境ではフォントのレンダリングが薄味になって見にくい
- Opera と関係ないのだが、IE9 が何をどうやってもページを互換モードで開く動きをして困っていたのが、32bit Opera をいったんアンインストールしたらそれがなくなった。アンインストールしたと同時にデフォルトのブラウザの切り替えをしたと思うのでそのときにうまい具合に何かが初期化されたのか?
- スクリプトやら iframe の広告やらがてんこ盛り系のサイトでよく起きていた気がするのだが、ページ遷移の履歴に不明な空履歴が複数入ることがあって、つまり何回も「戻る」を押さないと、本来の遷移元ページに戻れないことがよくあった。それが直っているような気がする
ところで DOM3 Composition Events は……。