| 2004/01 | ||||||
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
| 2004/02 | ||||||
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | ||||||
| 2004/03 | ||||||
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 | |||
top > かいはつにっき 2004 Q1
いまのところ Delphi で作っているわけなのですが、Delphi が置かれた現在の状況は、率直に言ってしまうと「緩慢な死」なわけで微妙に不安です。とりあえず Delphi .NET という最新版が用意されているものの、なんかあまりよい評判を聞かないし、逆に x86 ネイティブコードを吐くバージョンの Delphi というものはもう提供されないのか不明だし、Delphi 6 のバグが放置されっぱなしだし。。。とりあえずコード補完時に例外を吐くことがあるのをなんとかしてほしいのですが。
ということで仮に Delphi に見切りをつけた場合、何が代替になるのかしらというと。。。やっぱり C# あたりなのかなあ。どうなのかなあ。Windows は Longhorn で大いに変化するようなのですが、そこへ達する時点まであえて x86 ネイティブのままでいるのが正解なのか、早めに .NET に対応しておくのが正解なのか、ん〜さっぱり状況が見えないです。
メモ。WideCharToMultiByte() で UTF-16 から UTF-8 に変換させようとしたらなぜか失敗するので調べてみたら、どうも変換先が UTF-8 のときは lpUsedDefaultChar を nil(NULL)にしないといけないようなんですけど、MSDN には一言も書いてない。。。
ADSL が開通しました。わーい。24M なのに実質 2M しか出てない。超おそい。
バックアップファイルの作り方について。
いずれにしても、指定は拡張子クラスのプロパティで行うことになるのですが、例えば以下のような:
巨大なファイルを読み込んだときにどうなるか試してみました。青空文庫の「金色夜叉」を 30 回つないで 20MB のファイルを作って、読み込んでみる。すると。。。50,308 KB(49MB)消費。なんでこんなに食うの?? まだまだがんばらないといけないようです。無駄にメモリを使うのは、ダブルリンクトリストの宿命なのかな。。。
ちなみにほかのエディタでも試してみました。メモリ消費が最も少ないのは、ファイル自体が 20MB あるのにメモリは 9 〜 13MB くらいしか食わないという某エディタでした。なんだこれは? ものすごい高度なメモリ管理をしているようです。すごい。逆に最も多いのは。。。ええと 308,036 KB(300MB)消費の某エディタでした。
一応計算してみると、ファイルは 122430 の段落(改行までの 1 行)で構成され、萌ディタで読み込んだときの折り返し行数は 382262 になります。ファイルは Shift_JIS で、ほとんど 2 バイト文字で記述されているので、UTF-16 になっても変わらないはずだからやっぱり 20 MB 。段落 1 つにつき、16 バイト必要で、折り返し 1 行につき 16 バイト必要だから、テキストそのもの以外の付随情報に 122430 * 16 + 382262 * 16 = 1958880 + 6116192 = 8075072 バイト = 8M バイト弱、も必要です。ここまでは Delphi のメモリマネージャを通して管理されるヒープですが、メモリマネージャ自身が必要とするリストやパディングとかの分もあるので実質 1.3 倍くらい、36MB としてみます。で、起動しただけで 8M くらい使ってて、壁紙に 4M 使っていたので、全部合わせて 48 MB ? まあ合ってなくはないのかな。
キャラクタセットまわりを大体固めました。実を言いますと、いままで 1 度しか公開していないというのは、読み込みはできても保存が不安定なので、いまいちエディタとして機能してないというのがあります。とりあえず一通りエディタとしての機能ができれば頻繁に公開できると思うんですけどね。。。
保存処理をデバッグしてて落ちると、ファイルの中身が消えてしまうのがあまりに悲しいので、対象のファイルが例えば foo.txt ならばとりあえず #foo.txt# で書き出して、すべての書き出した成功した時点でリネームするようにしてみました。わりと安心。
なぜ IsValidCodePage() = true となるコードページでも、GetCPInfoEx() でコードページ名が空で返ってくるのがあるのかなあ。コントロールパネルのように日本語で取得するのはどうするのかなあ。dwFlags (must be 0) が怪しいのかなあ、例えばどこかのビットを立てると現在のコードページで取得する〜、とか。intl.cpl(コントロールパネル「地域のオプション」)でしっかり GetCPInfoEx を使っているようだしなあ。
けっこう書いたと思ったのだけど、25000 行くらいだった。まあ開発をはじめて実質 4 〜 5 ヶ月くらいなのでこんなものかなー。例えばサクラエディタはちょっと前のソースでも 78000 行近くある。。。Pascal と C とか、クラスライブラリ使用と WIN32 API のみとかいう違いは、あるのだけど。先が長いです。
オートメーションオブジェクトのほとんどを実装してみました。一通りテストして、あとはキャラクタセット周りの仕様のあいまいな部分をクリアしたらまた公開を考えています。見た目はほとんど変わってないのですが。
すばらしいアイディアを思いついたけど、まだひみつです。
さまざまなエディタの、OLE D&D 中の動作を見てみて気づいたこと。コピー・移動の切り替えに使用するキーは Ctrl が圧倒的に多く(Explorer に似せてあるのでしょう)、Shift は少数派です。他のプロセスからのドロップ時は常にコピー扱いとするエディタがけっこうあります。Windows2000 に付属のワードパッドでは、Ctrl + Shift でドロップ禁止のカーソルになります。その状態でドロップしても、当然何も起こりません。ドロップのキャンセルは Esc を押すのが一般的だと思うのですが、結果的に同じことを Ctrl + Shift で行えるわけです。とても興味深い UI だと思います。
というのは、Esc というのはあからさまにキーボードの左側にあるので、ドロップを Esc でキャンセルするという動作はマウスを右手で操作する右利きの人にとっては行いやすいのですが、左利きの人だとかなり大変だと思うからです(やってみましたが、実際大変でした)。左右どちらにもある Shift と Ctrl でも同じことができれば、ドロップのキャンセルに用いる修飾キーは利き手を選ばないことになります。
Microsoft の中の人が利き手のことまで考慮していたのかどうかはわかりませんが、結果的に良い UI になっていると思います。萌ディタでも真似してみました。
ファンクションキーについて。萌ディタの標準のキーバインドは Windows で一般的なもの、あるいはメモ帳がベースです。なので、ファンクションキーもそれを踏まえると。。。
| F1 | ヘルプ | F5 | 日付と時刻 | F9 | ? |
|---|---|---|---|---|---|
| F2 | バッファリスト | F6 | ビューの切り替え | F10 | ? |
| F3 | 次検索 | F7 | ? | F11 | ? |
| F4 | 次置換? | F8 | ? | F12 | ? |
ありゃ、後半がぜんぜん決まらないよ。そういえば F7 以降の標準的な割り当てってあまり思い浮かびません。
ところで、わたしは、ファンクションキーの表示というとどうしても黒地に白の MS-DOS 風なイメージを浮かべてしまうので(わたしは MS-DOS は使ったことはあまりないのですが、昔うちに X68000 というパソコンがあって、MS-DOS 風の OS が動いていました)、萌ディタでもそんな感じの表示をさせているわけです。
そこで X68000 で動いていたエディタはどうファンクションキーを割り当てていたのかなーと調べてみると、標準でついてくるエディタ 'ED.X' の場合だと
| F-1 | ファィルの先頭 | SHIFT F-1 | 新編集 |
|---|---|---|---|
| F-2 | ファィル最終行 | SHIFT F-2 | 再編集 |
| F-3 | 文字列の連続置換(確認なし)(前方) | SHIFT F-3 | 文字列の連続置換(確認なし)(後方) |
| F-4 | 文字列の前方↓検索 | SHIFT F-4 | 文字列の後方↑検索 |
| F-5 | カレント検索文字列の前方↓検索 | SHIFT F-5 | カレント検索文字列の後方↑検索 |
| F-6 | 行単位でのテキストの選択操作を開始(範囲) | SHIFT F-6 | ファィルの切り替え(昇順) |
| F-7 | 選択したテキストをカットバッファへ移動する | SHIFT F-7 | ファィルの切り替え(降順) |
| F-8 | 選択したテキストをカットバッファへ複写する | SHIFT F-8 | ファィルの読み込み |
| F-9 | 行カットバッファの内容をカーソル行の上に挿入 | SHIFT F-9 | ファィルの書き出し |
| F-10 | 行の二重化 | SHIFT F-10 | 子プロセスの実行 |
とのことです。Windows では(もともとは Macintosh の文化?)範囲選択は、Shift 併用でキャレット移動、というのが一般的だと思いますが、範囲選択とコピーやペーストなどをファンクションキーで行うのが面白いです。
萌ディタでは字単位の選択のほかに行単位、矩形形式での選択を行えるようにする(まだ作ってないが。。。)ので、F7、F8 あたりにはそれを割り当てることにしますか。キー入力ひとつで行のコピー・ペーストを同時に行える「行の二重化」も面白いので標準にしてみます。あとはまあ、空きでもいいかな。ということで、とりあえず
| F1 | ヘルプ | F5 | 日付と時刻 | F9 | |
|---|---|---|---|---|---|
| F2 | バッファリスト | F6 | ビューの切り替え | F10 | メニューをアクティブにする(Altと同じ) |
| F3 | 次検索 | F7 | 行選択開始・終了 | F11 | |
| F4 | 次置換 | F8 | 矩形選択開始・終了 | F12 | 行の二重化 |
でいきます。
今までの日記のとおり、萌ディタの細かい動作仕様を決めるときには手持ちのエディタをすべて見比べて参考にしています。テキストエディタ一般に普遍的な動作であれば積極的に準拠し、これは独自色を出していこう、とみなせるものはあえてはずした動作をさせてみたり。デファクトスタンダードばかり実装すると地味なエディタになってしまうし、ケレン味ばかり強くしては常用に向かない色物エディタになってしまうので、なかなか判断は難しく、また面白い作業です。
| Alpha 0.7.5.1a | BigEditor 1.16 | Dana 1.14.01 |
| えるの〜と 2.4 | EmEditor 4.01 | FirstPad 0.21b |
| GreenPad 1.04.2 | Jesty 0.34 | JmEditor 2.0.8 |
| K2Editor r.1.4.21 | MKEditor 3.7.8-J | otbedit 3.0.4.1 |
| Peggy Pad 4.14 | サクラエディタ 1.4.20 | したらびあん b4_0301031 |
| Space editor 2.44 | TEAD FreeEdition rel.1 | TeraPad 0.83 |
| TeXMi | ToMoEditor | VxEditor 0.3.0.9 |
| WZ Editor 4.00F | xyzzy 0.2.2.229 | 秀丸エディタ 4.10b14 |
| 真魚 1.44 | 萌え萌エ 1.20 | ワードパッド(win2k付属) |
| Word2000 9.0.6926 SP-3 |
今のところ参考にさせていただいているエディタは以上です。作者の皆様方に感謝。
まだマウス関連を作ってます。マウスを使って範囲選択をした場合、マウスのドラッグに従って動くキャレットが選択範囲の一方の端になります。このときマウスカーソルの位置からキャレットの位置を求めるロジックは、1/26 に採用したものです。つまり、カーソルが位置する文字の左側になります。
で、素朴な疑問です。感覚的には、ドラッグの開始位置から右にカーソルを動かした場合、カーソルの下にある文字が選択範囲に含まれるほうが自然なのかな? と。
根源的には、範囲選択中は、キャレットが指すものが、文字と文字の間の「点」から、左端の文字から右端までの文字で囲まれた「領域」へと意味が変わるところがミソだと思います。ポイントした点が領域の右端となる条件の場合は、キャレットはカーソルが指す文字の右側に置かれるのがほんとうは自然なのかも。
でもなーこのとおりに実装すると、それなりに直感的かもしれないけどマウス操作周りはかなり独自色が濃くなっちゃって逆に使いづらいかもしれないなー。特に改行の選択とか。。。選択時だけキャレット場所の算出ロジックが変わるのも変だし。。。
やっぱり今のままでいいや。
引越しが終わりました。スーパーへお買い物に行くのにすら車で数十分かかる、のどかというかなんと言うか。。。なところです。とりあえずダイヤルアップでしかネットに繋げません。。。なんか調べてみたら一応 ADSL が来ているようなので、手配してみる(ADSL とはいえ、たぶん、速くはない)。
しばらく開発から遠ざかってしまっていたので、まぬけなことに自分が書いたソースなのに何をやっているのかいまいち思い出せないというか。コメントをほとんど入れないので。
ちょっと考え直して、OLE D&D の際に適用した特別ルール(ビューの先頭行、末尾行を自動スクロールの対象とする)は常に適用するようにしてみました。つまり、ふつうにキャレットを動かすときには先頭行、末尾行に行こうとするとスクロールし(いわゆるスクロールマージンをとるということです)、マウスで範囲選択するときと選択した範囲をドラッグするときは先頭行、末尾行にカーソルを置くことで自動スクロールします。この方が全体的に統一されていいのでしょう、きっと。
それに、まったくの主観ですが、スクロールマージンのとってあるエディタは何かモダン(謎)な感じがするのです。
手持ちのエディタほとんどに共通している動作のひとつに、「行番号にカーソルを置くとカーソルが反転する」というのがあります。「テキストエディタ」にかかわらず、たとえば Microsoft 製の Visual Studio なんかも同じ動作をするのが興味深いです。暗黙の了解。
が、わたしは標準のカーソルのこの「にょろん」(謎)が気になってしょうがないので、
こういうカーソルにしているのです。そういう環境では、行番号にカーソルを置いたときに標準のカーソルの反転版が表示されると非常に違和感があります。。。なので、萌ディタでは反転カーソルを使わないことにします。
また、ほとんどのエディタはカーソルがビュー内に入ると有無を言わさずカーソルの形状が I ビームになります。でもこれは厳密に言えば違うんじゃないのかなーと思う。カーソルが I ビーム(つまり、キャレットを明示する)になるというのは、カーソル位置をクリックすることでその位置へキャレットが移動することを示していると思うわけです。そういう動作をするには、いわゆるフリーカーソルモードでエディタが動作していないと筋が通らないのではないか。まあ、屁理屈といえばそうなのですが。。。
しかし、萌ディタではフリーカーソルは実装しないつもりなので、ビュー上のカーソルはテキストの上にあるときのみ I ビームになるようにします(IE と同じです)。
OLE D&D について。このしくみを通すことで、プロセスをまたいだデータのやり取りが可能になるわけですが。素朴な疑問なのですが、Explorer でファイルを操作する場合、ドライブをまたいだ D&D はデフォルトでコピー、またがない場合は移動になります。この概念って文字列の D&D にも適用していいのではなかろうかと。つまり異なるプロセス間の文字列の D&D は、コピー動作がデフォルトでいいんじゃないのかなーと。
そいで例によっていろいろエディタで試してみると。。。ややデフォルト移動派が多いかな? うーん、どっちがいいのだろうか。
ところで意外に OLE D&D をサポートしているエディタって限られるんですね。秀丸エディタやサクラエディタのような有名どころが対応していないのはちょっとびっくり。それとも単にバージョンが古いのか、あるいは奥まったところに設定項目があるのか?
微妙に嘘。秀丸エディタは Ver4.10β9 から OLE D&D に対応とのことです。サクラエディタは今もう一度試してみたらなんか普通にできた(あれ?)。手持ちの中で多数派の TEditor 系エディタは、OLE D&D 対応に関しては少数派。奥が深い……。
OLE D&D 中の自動スクロールについて。同じ自動スクロールでも範囲選択とはまったく異なる処理なので動作をあわせるのが面倒です。んで、困った問題があります。
範囲選択の自動スクロールでは、ビューがマウスをキャプチャします。なんのことかというと、マウスがビューの外に出てもマウスのイベントをビューが受け取れるようにしているということです。自動スクロールはそれを利用している。ところが OLE D&D 中はビューがマウスをキャプチャしているわけではないのです(たぶん。できるのかもしれないけど、よくわかんない)。すると、ビューの外に位置するマウスの情報を取得することができないため、自動スクロールがそもそも不可能になってしまいます。。。
で、どうするかというと、OLE D&D 中の特別ルールとして、ビューの上下 1 行分にマウスカーソルが位置するときは自動スクロール「してしまう」ことにします。これはほとんどのエディタに共通する動作のようです。

マウスによる範囲選択について。
マウスで範囲選択しているときに、選択領域をウィンドウ外のテキストにまで広げたい場合、(萌ディタで言うところの)ビューの外にマウスカーソルを置くことで、自動スクロールする(さらに、ビューとカーソルの距離に比例してスクロール量が変化する)という動作が非常に一般的な UI となっているので、萌ディタも準拠します。
で、ここで気にかけるのは自動スクロールの速度なんですけども。例によって手持ちのエディタで試してみるのですが、なぜか猛烈な勢いで自動スクロールするエディタが多いです。あっというまにテキスト末尾や先頭に達してしまって目的の場所を通り過ぎてしまう。もうちょっとゆっくりでもいいのにな。。。ということで、萌ディタでは割と落ち着いた速度で自動スクロールすることにしました。
それから、また細かい話になります。マウスのドラッグによる範囲選択というのは、技術的には WM_MOUSEMOVE というメッセージ、自動スクロールは WM_TIMER というメッセージに対して反応し、キャレットをカーソル位置へ移動させる(スクロールの必要があればスクロールもする)、という形で処理すると思いますが、これらの組み合わせ方に注意深く気をつける必要がある。

ドラッグを開始した時点でタイマーを開始しますが、図で言うところの赤く色づけした領域ではタイマーは無視し、WM_MOUSEMOVE だけに反応する必要があります。逆に赤い領域外(緑で色付けした領域も含みます)では WM_MOUSEMOVE は無視し、WM_TIMER だけを処理する必要がある。そうしないと、ビュー外にマウスを置いてカーソルを動かすだけで自動スクロールの速度が変化してしまう(つまり、WM_MOUSEMOVE と WM_TIMER を両方処理してしまう)といった現象が起きてしまいます。「ターボ」的な動作なので、あるいは、そういう仕様だと主張することもありだとは思いますが。。。
ちなみに、このようなメッセージの排他的な選択はほとんどのエディタが処理しているようなのですが、単純にコントロールの内か外かで判定しているものも少なくないようです。そういうエディタは、図の緑で色付けした領域にマウスカーソルを置いている場合、カーソルを動かすことでやっぱり自動スクロールの速度が変化してしまいます。
ということで範囲選択とクリップボードとのやり取りは書いたので、OLE D&D に入るのですが。それ用のインターフェースを実装するだけでめまいがしそうです。。。COM と OLE の世界は難しい。
あ、上の図は説明のためのもので、こんなふうに半透明に範囲選択されるわけではないのであしからず。。。半透明選択は背景が隠れないのでなかなかいい感じだとは思いますが、ちょっと重すぎです。実際は下の図のように背景が隠れちゃいます。つまんないですね(汗)。

つらつらと面白くない話を書きます。
ウィンドウのメニューのカスタマイズをどんな感じにするか。まずどのレベルまでいじれるようにするかを考えます。やり方としては 3 つくらいのレベルが考えられて、
かなーと。1 はちょっと論外ですが。しかもこれだとメニュー項目に割り振られたショートカットをキーバインドに使用できなくなってしまう。3 は理想的なのかもしれませんが、あまりに自由度が高すぎするのもどうかな、という気がしないでもありません。
というか、キー入力に対する動作という意味ではすでに高すぎる自由度を与えているので、やりようによっては標準とまったく異なるキーバインドも書ける(かもしれない)わけで、同じ萌ディタでもぜんぜん使い方が違う〜というのはありえる話です。そうするとメニューのような基本的な操作系は逆に自由度を抑えたほうがいいのかな、と。また、単純な項目ならまだしも、子メニューを持つ項目なんかをカスタマイズするには、スクリプト側へ公開するインターフェースがそれなりに大げさになると思われるので、ちょっと大変というのもあります。
ということで 2 が落とし所かなと。まあもしかしたら「ビュー」と「ヘルプ」の間に「ツール」メニューでも設けて、そこだけは項目からカスタマイズできる程度の折衷はするかもしれないが。
そいで、ここからはさらに独り言に近くなるのですが。ほとんどのメニュー項目は実際はアクションを割り当てている。アクションはオートメーションオブジェクトとしてスクリプト側に公開するので、スクリプト側から見ればアクションをいじる = メニュー項目をいじる、とみなせる。それ自体は問題はないのだが、アクションのショートカットの扱いに困った点がある。萌ディタの基本動作としてはまずビューがキー入力を受け取らないといけないのだが、アクションに割り当てたショートカットはフォーカスを持つコントロールへ渡らないのだ。
なので、以下のような小細工が必要になると思う。
なにがなんだか。。。になってきましたが、スクリプト側から見るとこういうことになります。
//拡張子クラスの初期化
f.onInitProp = function (arg, classname, methodname) {
:
App.Actions('open').Shortcut = 'Ctrl+O';
App.Actions('open').Caption = '開くよ〜(&O)';
:
}
//'O' キーのハンドラ
f.onKeyO = function (arg, classname, methodname) {
//Ctrl+O で「開く」機能を呼び出す
if (arg & KEYMASK_CTRL)
App.Commands('open').Execute();
}
//'open' アクションのハンドラ
f.onActOpenExecute = function (arg, classname, methodname) {
//「開く」機能を呼び出す
App.Commands('open').Execute();
}
とまあこんな感じです。
ええと、引越しをすることになったので開発はしばし休憩ということで。
ものすごく細かい話です。表示されているテキスト上でマウスカーソルをクリックしたときに、どこにキャレットを位置させるかの話です。

と、このようにクリックした位置の X 座標(画像の赤い線)をまず基準にします。で、キャレット自体は基準線の左か右か、どちらかに位置することになるわけです。つまり、
の 2 とおりやり方が考えられます。ここでいろいろなエディタを試してみて、多いほうに倣おうと思ったのですが、手持ちのエディタではちょうど半々くらいでした。どうしよう。
思うに、画像の例くらい文字が大きければクリックした文字にキャレットを置くのが自然かなーと。何しろその文字をクリックしたわけですので。そうすると 2 つめのやり方は不自然なのか、ということになりますが、もしかしたら 2 つめのやり方は、文字を小さく表示しているときのマウス操作のぶれを考慮したものなのではないだろうか。
でもそうだとしても、そうすると逆に文字を大きめに表示させているときは余計な機能になってしまう恐れもあります。ということで萌ディタでは 1 つめのやり方、クリックした文字にキャレットを合わせるほうにしようと思います。
もうひとつ細かい話です。こんどは折り返して見た目が複数行になった段落の桁表示についてです。折り返したとしても、最初の行は 1 桁目から始まります。これは当然です。では、2 行目以降は?

というか、かなりどうでもよいので決め兼ねますね。。。これも手持ちのエディタで試してみましたが、やっぱり半々でした。しかも設定によって変えられるエディタは(たぶん)皆無。如何にどうでもいい話題かというのを物語っています。
まあ何を編集するかによってどちらがいいかは変わるだろうし、どちらか一方に決める理由も思いつかないので、これは設定によりどちらの表示もできるようにしてユーザ任せにしようかなーと。。。
いろいろな専用のコントロールがあるわけですが。普通 Delphi でコントロールを新たに起こすときは、コンポーネントパレットに登録するために専用のパッケージに入れて、exe のプロジェクトとは分離すると思いますが、萌ディタでは今のところコントロールは実行時にコードで生成させているので、そういうふうに作っていないです。
が、萌ディタの根幹を形成するようなもの(ビューとか。。。)はそれでいいと思うけど、もうちょっと汎用的なコントロールはやっぱりパッケージに分離するようにした。ついでにファンクションキー表示のコントロールを書いてみたり。ファンクションキーをそれぞれボタンにしてもよいのですが、やっぱりファンクションキーは黒地に白じゃないのかなーということで。
そろそろ範囲選択まわりに入ろうかなと。同時に OLE ドラッグ&ドロップも進めることになります。範囲選択まわりが固まれば対応するオートメーションオブジェクトのインターフェースも決まるし、クリップボードとのやりとりも書けるようになるので重要だなあー。
設定画面は大体できたような。設定が実際に反映されるようになりました。起動時に読み込むスクリプトやエンコーディング DLL の編集まわりはまだ。この辺をいじったら(追加はともかく、削除が問題)、読み込み済みのバッファに影響を当然与えるわけで、編集はできてもそれが反映されるのは次回起動時、とかにするかもしれないです。
Peggy Pad を落としてみました。なんでうちのマシンにはエディタが 22 種類も入っているのか。。。
ふと何の気なしに「萌ディタ」とかでぐぐってみたら、いくつかのサイトですでに紹介済みなんですね。ありがとうございます。
あと、萌ディタとは別に、萌え萌エというエディタがあるみたいです(サイト全体の更新は凍結されているようなので、とりあえずリンクは張りません)。しかもつい最近更新されたばかりじゃないですか。これは困ったぞ。。。
日記の順番をさかさまにしてみました。
設定画面は今のところこんな感じです。ここですごいことに気が付いた。標準のエディットボックスやコンボボックスも Unicode 対応にしないと意味がないのです。TNT を使っちゃおうかな。。。
プロパティの一覧はリストボックスを使っているのですが、目的のプロパティを選択するのにキーボードを使えると楽です。リストボックスには標準で文字列の1文字めを打つと最も近い項目を選択してくれる機能があるのですが、2文字め以降まで対応しているわけではない(つまり、一般的なインクリメンタルサーチになっていない)。自前で作るかな?
大変どうでもいいことなのですが、リストボックスの縦横のサイズと、内部の区切り(プロパティ名と、その値)の比は、はっきり申し上げて「勘」なのですが、比を測ってみたらほぼ黄金分割されていて感心しました。要は、赤の A:B と 緑の A:B の比率が同じだという。。。あ、どうでもいいですね。まあ黄金分割が隠された図形に人は安らぎを感じるそうなので、ある意味これも「萌え」の一種なのかもしれません(こじつけ)。
オートメーションオブジェクトに必要そうなものを(思いつきで)ざーっと並べてみましたが、こういうのってデファクトスタンダードみたいなものがないのかしら。ということで萌ディタに割と作りが近い? と思われる EmEditor と Alpha を見てみる。EmEditor は意外とあっさりした構成ですね。むしろ Alpha のほうが充実している。すごいです。
悪あがきは悪あがきでしかなかったようでした。。。IActiveScriptSiteWindow を実装してみます。あとビューのバグを退治。
ScriptControl を使わずに動くようになった。psvActiveScript をそのまま使いました。が、ひとつだけ、そのままだと萌ディタの仕様と合わないところがあります。
どうしたかというと、しょうがないのでソースを書き換えてしまいました。初期化が本当に必要なタイミングというのはたぶん 'ScriptLanguage' が変更されたときだと思うので、それが変更されたかどうかをフラグでもって、スクリプト実行の際に初期化するかどうかを判断するようにしました。
あとは細かいことですが、ScriptControl にある AllowUI や Timeout などのプロパティについての記述を萌ディタ側から削除。というか IActiveScriptSite 自体にはタイムアウト関連のインターフェースってないんですね。。。ScriptControl が独自に実装していたものなのかな。謎が深まる。
ともあれ、ウェイトはきれいになくなったようです。Serhiy Perevoznyk さん、萌ディタスレの乗り換えたい ◆cG3fPhugNg さんに感謝。ありがとうございます。
ウェイトの件で、IActiveScriptSiteWindow の直接実装例を示唆していただいた。こんなのがあったのかー、と。ところで最後の悪あがきに、App 以外のオートメーションオブジェクトを internal にしたり、WM_KEYDOWN でスクリプトを呼んだあとに Sleep(0) を入れてみたりしたらウェイトがなくなったような気のせいがするのですが、気のせいでしょうか。とりあえずこのまま様子を見てみるかな。。。
設定画面がこんな風になりました。ぜんぜんエディタらしくないなー。
それぞれの文字幅を取得する処理。面倒な処理なので忘れないように自分用に書いておきます。まずフォント(厳密にはフォントキャッシュへのエントリインデックス)を決めます。指定された文字から Unicode のブロックインデックスを求め、どのようなプロパティの定義がなされているかを調べる。定義がされていない場合、'font-default' を調べて、定義されていればそのフォント。定義されていない場合は親の拡張子に対して同じ処理を再帰的に続ける。だから plaintext の font-default は必ず定義されていないと、再帰がとまりません。
エントリが求まったらそのフォントキャッシュの文字幅テーブルを見る。テーブルが空ならブロックの文字数分確保する。次に指定された文字に対する文字幅を見る。値が 0 ならその前後 32 文字分と合わせてまとめて API で取得する。もちろんすでにテーブルとその値が構成済みならテーブルから値を引っ張っておしまいです。再帰的な走査とか、キャッシュにしては回りくどいことをしているけど毎回 API で文字幅を取得するよりは速い。
設定画面のようなものを作ってみる。たいてい、エディタの設定画面というとモーダルダイアログにタブシートが乗っかってて、必要なタブを選択して適当に設定という流れになると思いますが、昨今の高機能なエディタはタブの中身にしても、タブの数にしてもぎゅうぎゅうで、自慢じゃありませんが WZEditor を使っているときに「あ、この設定変えたいな〜」と思ってダイアログを出して、一発で目的のタブへいったことありません、わたし。
これはよくない。ということで萌ディタの設定画面は、記憶力に自信がないひと(自分だ)でもらくらく使えるようにしたい。そんなわけで設定画面の見た目は、前述の一般的なエディタのようなものにはならない見込みです。しいて言うと Delphi のオブジェクトインスペクタや、Visual Basic のプロパティをいじるような感じになります。項目を選択するごとに詳細な説明が表示される辺りは VB みたいですかねー。
とりあえずα版として公開してみる。といってもよくα版とかの基準ってわかりません。実装する予定のものがまだフルに実装されていないならα版といっていいのだろうか。なんかα版に達しているのかも自信がなくなってきたなあ。。。
萌ディタは DUnit(DUnitといえば2種類あるのだが、簡単なほう)でユニットテストを起動時に走らせるようになっているが、最近あまりテストケースを書いてないなあまずいなあ。でも画面の動きがメインになる部分って、それ専用のテストスイートじゃないとテストしにくいような気もする。
手をつけ始めなければならないものは目の前にたくさんあるのでどれから片付けていったものかな。とりあえず細かいところは置いといて、アプリケーション全体の骨組みをはやく固めてしまいたいです(そのレベルで試行錯誤しているのかよ、と突っ込みが入りそうですが)。
といいつつ単語単位のキャレット移動などという実に細かいものを考えている。それには、「単語」とは何かというのを定義しなければいけないわけですが。単語って何だろう。英語圏とかなら、空白で囲まれた、連続するアルファベットの列を単語というのかな。もちろん記号も考える必要はありますが。
が、それを日本語を含めた Unicode の全文字について当てはめられるわけは当然なくて、もっと複雑な定義が必要になると思う。こんなときは、他のエディタをいろいろと触ってみる。特に Unicode 対応を謳っているエディタはとても参考になります。しかしあまり触りすぎて便利に使ってると、「別に今更新しいエディタを作る必要ないのかも?」と恐ろしい考えになってしまうのでほどほどにしなければいけません。
萌ディタの特徴の1つが、JScript でほとんどの動作を記述できるということなのですが、そういうアーキテクチャで速度的にはどうなのかと指摘を受けたことがある。まあ COM の話になってしまうので正直よくわからないのですが、速くはないと思います。
といっても「遅い」というわけでもなくて、キー押下→スクリプト実行→萌ディタに戻るという1個のサイクル自体のスピードは許容範囲にあると思う。ただ、例えばカーソルキー押しっぱなしとかさせると、なぜかスクロールさせている途中に妙なウェイトが入ってしまうことがあるのです。萌ディタ側でウェイトを挟むような何かをしているわけではないので、ScriptControl の中なり、オートメーションオブジェクトの中なりで何かが起こっているとしか思えない。
実際、タスクマネージャで萌ディタを見てみると作った覚えのないスレッドが走っている。これは萌ディタがスクリプト側に提供するオートメーションオブジェクト専用のスレッドで、VCL がよきに計らってくれているものなのだろうけど、謎のウェイトも含めてなんだか気持ち悪いです。
で、JScript(javascript)での制御、というのを残しつつ、ほかの実装手段がないものかと探してみると、例えば DMonkey があります。VxEditor などにも組み込まれてて実績もあるし、Delphi 製だから exe に簡単にまとめられるし(exe が太るという意味でもあるが)、乗り換えるとしてメリットのほうがはるかに多そうなので、もしかしたらそうなるかもしれない。