>net user 俺
によれば Event Log Readers/HelpLibraryUpdaters/Netmon Users/Performance Log Users/Performance Monitor Users/Remote Desktop Users/Users というローカルグループに属しているらしい。ローカルセキュリティポリシー>ユーザー権利の割り当てによれば名指しで システムパフォーマンスのプロファイル/メモリ内のページのロック/リモートコンピュータからの強制シャットダウンの3つが許可されている。その他にもシンボリックリンクの作成やらなにやらを Users に対して許可していたりする。何かの割り当てが引っかかったのだろうか。最近(つまり先月の Windows Updateに伴う再起動以後に)変更しただろうか。■とりあえず権利の割り当てと参加グループを変更してはログオフを繰り返して試行錯誤してたら UACに名前が出てこなくなった(最終的になんの権利も放棄していないのに!)。めでたしめでたし?For class and private DCs, GetDC leaves the previously assigned attributes unchanged. However, for common DCs, GetDC assigns default attributes to the DC each time it is retrieved. For example, the default font is System, which is a bitmap font. Because of this, the handle to a common DC returned by GetDC does not tell you what font, color, or brush was used when the window was drawn.」。ダイアログのウィンドウハンドルを使って得る DCが「
common DC」なのかって聞かれると自信がないけど。あるいはまだ一度も SelectFont(SelectObject)してなかっただけとか。■r3879はフォントに高さを聞いたがそれを知らない俺はリソースファイルがうまくやるやり方に従った。オーナードローコントロール以外はそれで文字が切れたりしてなかったから。カスタムDPIでもうまくやるかは知らない。■ちなみに MapDialogRect(※先のスクリーンショットに写しておきました)を使うのは3番目の(それで最後の)案で、その前には引数を4つ(left,top,right,bottom)も取らない GetDialogBaseUnitsを検討した。実際 MapDialogRectで使ってるのは bottomと topの2つだけだし、それが GetDialogBaseUnits関数は引数をひとつも取らないって言うんだから、これで間に合うならこれを使おうとするだろう。……でもひとつも? ダイアログのウィンドウハンドルもいらない? 実行コンテクストを参照してマジカルな方法で答えを返すとでも? 答えはここに>「GetDialogBaseUnits is a crock – The Old New Thing」 crockは「ナンセンス、でたらめ」という意味が何番目かに載ってる。■WM_MEASUREITEMに反応してオーナードローアイテムの高さを変える方法は邪道ではある(が、適切なデフォルトを設定しているだけだとポジティブに考えたい)。変更対象のファイルが個別のプロパティシートに対応したものではなく、基底クラスのもの(prop/CPropCommon.cpp, typeprop/CPropTypes.cpp)だということからそれが知れる。WM_MEASUREITEMは WM_INITDIALOGより前に呼ばれるから、基底クラスが派生クラスにディスパッチする仕組みが働かないんだよね(だから基底クラスのファイルに直に書いた)。これが同じ事情を説明してる>「OnMeasureItem will be called only if the control's class is created at run time, or it is created with the LBS_OWNERDRAWVARIABLE or CBS_OWNERDRAWVARIABLE style. If the control is created by the dialog editor, OnMeasureItem will not be called. This is because the WM_MEASUREITEM message is sent early in the creation process of the control. If you subclass by using DDX_Control, SubclassDlgItem, or SubclassWindow, the subclassing usually occurs after the creation process. Therefore, there is no way to handle the WM_MEASUREITEM message in the control's OnChildNotify function, which is the mechanism MFC uses to implement ON_WM_MEASUREITEM_REFLECT.」 邪道だろうがなんだろうが、ツールバータブの個別対応コードを削るだけでダイアログのフォントを正しく変更できたのだから嬉しい。「やってやったぜ!」■これはなんだろう>「Imp: ダイアログのフォント変更設定追加 · mocaskr/sakura@af39f17」 リソースからコンパイル済みのダイアログテンプレートを読み込んで、それからダイアログを作成するまでのあいだにフォント指定を書き換えるってこと? うへぇ、こんなんMS Pゴシックにも Meiryo UIにも満足できないこだわり派のユーザーも黙っちゃうよ。そうか、実行時に変更できるのか。■「履歴を読んでるだけで楽しい」とか書いていてもそれは楽しそうだ、というだけのことで、実際に読んではいなかったり。「列を指定してソート。たしか秀丸にあったことで知った機能」というのもそうだし、「ダイアログのフォントとしてMeiryo UIが指定可能」というのも、検索に引っかかって初めて気付くわけで、検索可能なオンラインのヘルプっていうのは広告塔なのだね。■ダイアログのフォント指定は言語設定と同じように特別な配慮が必要な設定だろうか。つまり、表示言語をうっかりクリンゴン語に変更してしまうとスタートレックを見たこともない自分は元の設定に戻すことさえできなくて設定画面の迷宮で途方に暮れてしまうわけだけど、ダイアログのフォント設定を間違えたり壊したりすると同じように元に戻せなくなりそうなので。※iniファイルを直接編集するという解決法は、可能であるというだけであって、利用者に求めていいことではない(俺だってやりたくない)。■実はフォント設定にからめてセキュリティフォントをからかってやろうとしたのだけど、自分の想像が及ぶ程度の素朴な仕組み(※salt付きの換字暗号)ではなかったのでやめた>「自称完璧なマイナンバー保護技術『セキュリティフォント』 その1 - Windows 2000 Blog」
absent operatorの挙動だが、(?~) は何にもマッチしないのが期待値なんだろうか?」■空パターンはすべての文字列に含まれている(※空文字列を含め何にでもマッチする)というのが普通なので、そういう文字列以外にマッチするパターン(※非包含オペレータが表すもの)は何にもマッチしないのだろうかってことだよね。文字の集合に対する
[]
(どの文字にもマッチしない)と [^]
(どの文字にもマッチする) とは反対なのが面白い。■文字集合を使った初心者のよくやる間違い [^ここに文字の集合ではなく列を書いてしまう]
や、お手軽だが不完全な代替 .*?
を使ったパターンに対して、正しく、簡単で、理論を逸脱しない答えが用意されるのが待ち遠しい。■日本語部分だけ読んだ>「正規表現における 非包含オペレータの提案」。■いや待てよ。非包含オペレータが扱う典型的なパターンはどういうものだろう。foo
だろうか .*foo.*
だろうか。俺は (?~)
について書いてるつもりで (?~.*)
について書いていたんだろうか。二つが同じだとすると部分一致ではなく完全一致であることを明示するために (?~^foo$)
みたいにアンカーを付けたくなるだろうから両者は区別されるんだろう。じゃあやっぱり勘違いしてた? s=uvw
みたいな文字で構成された式を「文字列がパターンを含む? どういうこと?」と読んで疑問のままにしてるんだけど、その辺を含めて PDFを読み直したい。static const Range Null;;」)、高校生のときのノートを(捨てる前に)眺めてみたりするたび思う。あの頃俺は賢かった(今はもう理解できない……)。たぶん没入することが必要なんだな。振り返ってるときにはそれがない。■パッチを読んでいて……。「-で始まる行がいっぱい」<嬉しい!やってやったぜ! 「+で始まる行が凝集している」<ファイルを移動しただけか、正しい徴候。それかなんとなく気に入らなくてイチから書き直す悪い癖の発露。「あちこちに散らばる + の行」<やり方か仕組みのどちらかが間違ってる。「交互に現れる + の行と - の行」<普通っぽい。あと手前味噌だけどコメントが丁寧だと思った。「あ、そうなんだ。勉強になります(書かれていなければわかっていなかった)」って感じ。やっぱり時間差があっても自分は自分で、阿吽の呼吸で疑問と答えが噛み合うところがある。■アクセスログの一覧を下の方まで眺めてたら、こんな名前のファイルが3ヒットしていた>subpattern_highlight.rev2.patch。え、あれ? こんなんやってたっけ。「脳log[20120517p01] サブパターンハイライト。」つい反応してしまうくらいお気に入りのネタではあるんだな。■■■漢検の対策テキストから啐啄同時(※ATOKで一発変換できない)という四字熟語を仕入れた。ここ(「阿吽の呼吸で~」)が使い所だと思うのだけど、どういう形で文に組み込めるんだろうか。
最終更新: 2018-03-14T23:15+0900
行単位で加工するマクロのための定型。そのままで同時に標準入出力にもファイルドロップ(SendToを含む)にも対応している。Perl譲りなんだろうけど、Rubyの -p スイッチって便利だし実際のニーズに基づいてるよねって。
マクロに登録しても良し、ソートしたいテキストファイルをドロップしても良し。
よく知らないけどプラグインだとメインメニューにコマンドを登録できたりするんだろうか。こういうものを C++で書いてエディタ本体に内蔵したくはないよね。
掲示板に貼り付けるには長いし、Wikiのマクロ投稿ページはログインを要求してきて書き込みさせてくれないしで、返信できずにここに書いてるんですよ。>「[8316] ソートの挙動の切り替えはサクラエディタ内で可能になりませんでしょうか」
Meryのソートマクロを見たら実質ワンライナーだった。連打するたぐいのマクロではないとしても、自分のはゼロオーバーヘッドルールから離れすぎていた。
bSelLock
はたしかに else や default でパターンを網羅したいケース。■SetFocus
は、他はなくても必ず自分自身が対象として含まれるだろうという期待があるのだろうけど、それは予断だし油断があったのだと思う。同じファイルのすぐ上にある CViewCommander::Command_CASCADE
にも同じ型のコードがあるけどそれは?■クリア済みのWndProcを呼ぶことについて。呼べないから呼ばないでいいのか、呼べないから呼べるようにして呼ぶのか、判断がつかない。■パッチ部分は SendMessageToAllEditors
なのだけどそのすぐ上にある Send を Post に置き換えただけの PostMessageToAllEditors
については?■ここまでで触れずにとばした部分は全体に趣味的な印象を持った。delete 0
は安全らしいし、CloseHandle(0)
は無害らしいし、使わない領域、範囲外とインデックスでマークされてる領域を NULL で埋めなければいけない理由はないし、変数を2つ定義して、同時に初期化した片方を条件にもう一方を直後の if-else 文で初期化(※厳密には代入)するというとき、定義部分でも初期化が必須かといえばどーでもいい。それよりも C99 より前の C言語に倣った関数冒頭にまとめた変数宣言(&定義)のほうがつらい。長大な関数のあるブロックである変数が必要になったとき、使いたい値が代入されてからそこまでのすべてのコードパスでどんな値が代入され得るのかチェックしないといけないし、反対に不要になったときは、代入をやめたことで関数の以後で問題が起こらないことを確認しなければいけないし、それを forループの変数 i についても行わなければいけないのだから。行き当たりばったりで次々変数を増やすのもどうかと思うが、適切な粒度のスコープがあると思う。env/CAppNodeManager.cppのパッチで指摘された初期化はまとまっていて問題を見出せない。■env/CAppNodeManager.cppの別の部分については、IsSakuraMainWindow
でもやっていて実質的な意味を持たない NULLチェックを足して今以上にごたごたさせるより、2番目のループを取り除くぐらいの書き直しをしたらいい。「hWndLastが NULLのときに全くメッセージが送られていなかった」なんてときのコードはおそらく原型が残っていないし(そんなことを言うやつがよくわからないまま(同じ)轍を踏むのだ(自虐)。でも unicodeブランチでは遡れるログに限界が……)、その対応のせいで(たぶん昔はそうだったのだろうけど)双子のループではなくなっているのだから。こんな感じにしたい>CAppNodeGroupHandle__PostMessageToAllEditors.txt。もちろん SendMessageの方も。仕様の違いは、pWndArrに hWndLastが複数含まれていたときに複数回メッセージが送られないってことだけど、そんなこと起こらないし期待もしていないでしょう? ほぼコピペの双子関数をひとつにまとめるのは、PostMessageと SendMessageの戻り値の型が違うせいで失敗した。マクロを使うとデバッガで追いかけるのが難しくなるし、メンバ関数テンプレートはコンパイラの実装が遅かったような記憶があって積極的に使いたくないし、そもそもリンクエラーを取り除けなかった(<テンプレートの定義を.cppに書いていたから。明示的な実体化が必要だった。こんな感じ)。たぶんファイルローカルのモジュール関数テンプレートにしたら一挙両得だけど、アクセス許可を出さないとダメだよね? 代わりに staticメンバにする? そうするだけの、過剰なテクニックを駆使したりヘッダに手を入れたりするだけのメリットがないのでコピペのままでいいや。■macro/CWSH.cppについて。中断のためのスレッド関数とメインスレッドがパラメーターを通して hEventを共有していて、子スレッドの方で
OpenEvent
や DuplicateHandle
みたいなものは呼んでいないんだけど、子スレッドの終了を待たずに SetEvent(hEvent);
即 CloseHandle(hEvent);
して子スレッドはイベントを受け取れる?■読んだのはここまで。趣味的(あるいは潔癖・偏執的)とは書いたけどデバッグモードのコードだと思えばそういうものかなという気がしないでもない。が、C++が初期に遅いと言われたのってコンパイラが隠れてする仕事(コンストラクタの呼び出しとか)に対する無理解が理由にあると聞くので、無駄とわかってるところに 0 を埋めて歩くことに積極的にはなれない。staticでない未初期化変数の値をそのまま使用するのは結果が予測できないバグだけど、未初期化変数(遅延初期化変数)それ自体は問題にしないよ。■自分の不見識が明らかになるだけかもしれないけど……。「スタックのドカ食い対策」<スタックで間に合ってるならスタックの方が速いんじゃないの? 「
WINVERによる条件コンパイル」<ソース分裂バイナリ分裂はない方がいいし、俺プリプロセッサ嫌いなんだよね(<誰も聞いていない! 共感性・説得力皆無!)。さらに共感を得られそうにないことを書くと、namespaceが導入されたからグローバルな名前空間を明示するために
::
を付けましょう、これまでただ Func();
と呼んでいたものを ::Func();
と書きましょう、なんてのはなんの冗談かと思う。譲るのは当然後から来たほうだし、衝突しないような名前を選ぶ、衝突が避けられないときにしぶしぶ ::
を付けて区別する、くらいの態度でいるんだけど、みなさん積極的に ::
を付けますね。それって(知らないしやったことないけど)まさに MFCプログラミングで名前のバッティングが避けられなかったからみんなそうしてただけなんじゃないかとも思ってるんだけど、SDKプログラミングでもわりと積極的だよね。自分が無知で異端なのかと不安になる。■途切れていた古いログを見つけた。「Fix: Send/PostMessageToAllEditors() don't send message when last window parameter is NULL.」この修正が不可解で、現在のソースに残ったコメントから以前のコードを想像できなかった(だから原型が残っていないのだろうとコメントした)。単純に m_hWndLast の NULLチェックを省いてこう直せば良かったじゃない?>if( phWndArr[i] != m_hWndLast )
この頃はまだ IsEditWnd
(※後のIsSakuraMainWindow
?)が引数の NULLチェックをしていないことから、先取りして phWndArr[i](※m_hWndLastではない)の NULLチェックを追加してもいい>if( phWndArr[i] != m_hWndLast && phWndArr[i] )
。ま、済んだことはさておき、この時点ではまだ双子のループが存在していないことが興味深い。双子のループが誕生したのはこのコミット>「New: Grouping of the tab windows.」(←Firefoxだとアドレスバーで20回ぐらい Enterキーを押しているうちにページ内アンカー(#diff-24)が機能するけど、Operaだとリロードしてしまって永遠に機能しない。くそったれな遅延ロード。くそったれな S……)。グルーピング対応のためとはいえループは必要だったろうか(反語ではありません。結論保留)。最終更新: 2016-12-02T23:22+0900
♪ 目があった。鹿。このあとどんどん近づいていって見つめ合ったまますれ違った。体当たりされなくてよかった。 シシトビバシっていうのは名前だけではなかったのだ。
最終更新: 2017-11-01T20:40+0900
ただの表データを扱うのに Excelを起動したくはなくて、エディタの TSVモードを使った(※世の中には関連づけのままにフォトショップを使って画像をプレビューする人もいますがね<鷹揚な人だ見習おう)。タブ文字って、列の幅がタブの幅の倍数をまたぐたびに上下で列がずれるのが微妙で、タブを複数連続で使って揃えたとしても、列を編集して長さが変わったら限界まで圧縮されていたタブがぴょっこり復元して後ろの列を押し出したりするし、1タブでなんとかしようとタブの幅を想定最大列幅まで大きくするなら3つか4つの列しか画面に収まらないしで、どうやっても手間がかかる。タブ文字の拡張として TSVモードは良い。
TSVモードとは関係なく、いつもと違う使い方をしたのでこれまで気付かなかったことに気がついたり、新バージョンのバグに当たったりした。
文字の大きさや折り返し幅が関係してる。原因をつきとめてさあ報告しようかと既存のバグ報告を漁ろうとしたら、いきなり掲示板の3スレッド目がそれだった>開発掲示板(Unicode)[2370]。おまけ付きのパッチもある。脱力。
MRUに前回の適用ファイルタイプが記録されていたせいだった。けっこう昔からある機能で、Ver.2系の最初のリリースぐらいからある。要望も昔からあるみたいで「Request/111 手動で変更したタイプを記憶 - SakuraEditorWiki」の投稿者は request.txtとなっている。
いらない機能です。「一時適用」したファイルタイプを一時でなく覚えておいた結果、ユーザー(俺)を欺いてしまっているのだから。先にばらしてしまうと、次に挙げる問題もこの機能に起因して引き起こされていたし、せめて、拡張子というルールに基づくファイルタイプ判別に引っかからなかった場合に限り、アドホックな一時適用ファイルタイプを採用するなどしてほしかった。
どちらを優先するのか一概に決められないところはある。アドホックな選択を記憶・復元するのがユーザーの意思を尊重した結果なら、ルールを新設して適用したいというのもユーザーの意思なのだから。お天気屋の原理主義者の今日の言い分は「ルールはルール(なので絶対)、一時は一時」ですがね。
※お天気屋たる所以は、かっこ書きの中身が普段は「(所詮はルール。人の作ったもの。文言の枝葉末節や不備に盲従せずその精神を忖度した運用でカバーし必要なら変えるべし)」だから。どちらへ転んでも自分に都合のいい主張になるという。
タイプ別設定一覧から選んで一時適用ボタンを押したときと、ファイルを開くときに MRUから記憶していたファイルタイプを復元したときでは、状態が違う。ついでにいうとコマンドラインの -TYPEスイッチでファイルタイプを任意に設定したときは、MRUから復元したときと同じ挙動を示す。
どういう挙動か。ファイルタイプの選択結果がロックされていないので、設定を変更したときに、拡張子に基づくルールベースの選択に上書きされる。
この結果どういうイライラ状況が発生したか。
適用されているファイルタイプってタイプ別設定一覧を表示するまでわからないんだよね。ちょっと覚えがあってヘルプを調べたらタイトルバーには表示できるみたいだけど(「$B タイプ別設定の名前 (sakura:2.0.7.0以降)」)、初期設定ではない。
ファイルタイプが見えないしすり替わってるしルールを無視するしで、気がつくまで(つまりソースコードを読むまで) 1と 2のあいだをぐるぐるぐるぐるしていたのだった。
どうも W の幅をひとつの基準にしているらしい(※高さの基準に x が、ハイフンの長さの基準に n や m が使われるように(<果たしてそれを聞き分けて区別できるだろうか)、もっとも幅広な文字として W が挙がるのかもしれない)。そして列の幅計算にはフォントを使わず、全角半角単位で数えてるっぽい。
たとえば最近愛用してる HG正楷書体-PRO フォントの場合、W の文字は全角半角で字形にゆらぎ程度の違いしかなく、基準に使う W は半角文字ながら全角の幅を持っている。その結果、列幅の想定と実際におよそ2倍の開きが生じた結果、ほぼ列の内容と同じ幅の余白が隣の列との間に確保されることになった。
そういうアルゴリズムで(=列幅の2倍の)タブストップを計算してるのだと思ったから、よーし好きに書き直しちゃうぞー、と CTsvModeInfo::CalcTabLength を頭から書き下していって途中で首を傾げてしまった(あれ? これ、俺が書こうとしてるそのまんまやん)。実際、列の内容が W のみだった場合は想定とのあいだに誤差はなく、計算された余白は適正と思えるものだった。
実際どうなのだろう。閲覧を主に想定してるのだろうか。
ファイル名の通り……ではないな。細かいけど「記憶しない」ではなく復元しないだし、一定以上のタブ幅が4に切り詰められることの修正も入ってる。
雑なパッチとは「Viewが前の行にさかのぼって再描画してくれない? 全部書き換えたらいいじゃない」の精神で。「Viewが持ってるフォント情報は古い、しょうがないので自分で作る
」みたいなコメントがソースのどこかにはあって、フォントを利用した列幅計算はある状況では問題があるのかもしれないけど、「こまけぇこたぁ(略)」の精神で。
あと、TSVモードで現在無視されてるタブ幅の設定を、余白の量として扱った。タブ幅8なら隣の列とのあいだに最小の行で全角4個分の余白。
我慢して使うよ。
下に書いた悪魔合体を進めると、横スクロール対応を雑でなくできる
P.S. histという用語は MoveHistPrev/MoveHistNext という前例に基づいたものだったらしい。マクロを書いていて気がついた。だからどうということではないが。
そして、マクロを書いていてアンドゥ履歴をまとめたいなとか、カーソルをコマンド連打以外の方法で操作したいなとか思って調べたら、そういう機能は 2.0.4.0とか 2.1.0.0で入っていたらしい。マクロ強化の動きは見ていたけど、これはたしかに必要だわ。理想的にはコマンド列挙の VBスタイルではなく JScript式のオブジェクトモデルが欲しいという考えは変わらないけど。コマンド群が不足なく整備されさえすれば、マクロの先頭で JScriptで書いたラッパーライブラリを読み込んで evalするという方法もありそうだけど。『C++のためのAPIデザイン』を読んだところでは、関数群を整備するのに比べてオブジェクトライブラリを用意することには特有の問題(依存とか修正とかに関してだっけ?)があって難易度が上がるとかなんとか(つまり最初は関数列挙で正解)。
書いていたマクロっていうのがカーソル行をファイル末尾に飛ばすものなんだけど、Ruby風に書くと File.lines.partition{...}
というのをそのマクロを使ってやろうとしていたんだけど、どうしてもできないのがスクロール位置(縦と横)を動かさずにそれをすること。Jumpダメ。GoFileEndダメ。MoveHistPrevダメ。AddTailダメ。LineCutToStartダメ。DeleteLineは対象が折り返し行でダメ。使えるコマンドがなかった。「行削除って便利。(20100620p01)」のときから変わらない悩み。マクロ実行の前後でフォーカスを見失うのは我慢できない。
たしか秀丸にあったことで知った機能。今はソートの前に列を並び替えてるんだけど、ドロップをミスってデータを壊さないかはらはらしてる。気がつけばアンドゥできるけど、気がつかなかったときが怖い。
何度も[End]キーを押しては間違って行末へ飛んだ。どうやら TSVファイルの列を編集しているとき、無意識の[End]キーで飛んで行きたい末尾とは列の末尾だったらしい。
あと Tabキーで次の列へ移動するとか、Enterキーで下の行へ移動するとかしたい気がするけど、違和感なく適応できるかはわからない。試してみようにもマクロから CSV/TSVモードのオンオフを知る方法がないので。
できると思うんだけど。つまり、タブストップの随時再計算をそれなりの規模の CSVファイル(※ウチのPCだと富豪パッチバージョンで1MB・1万行ならもたつくけど現実的なレベルなので、それより大きいファイル)でやろうとして時間を空間で購った場合、横スクロールバーをドキュメントの最長行に対応させるためにやっていることっていうのはその一部になる。でもコストが整数2個から配列の配列と段違いに大きくなるので、CSVモードではない場合のコスト増を避けなければいけない。(折り返しモード)×(CSVモード)=4通りのコード分裂……。
レイアウトマネージャーの仕事の一部(※折り返さないときのための再計算を適宜実行すること)が外に漏れた結果あちこちにコピペコードが散らばってるなーとか、レイアウトはレイアウトマネージャーの持つパラメーターがないと幅計算できないしレイアウトマネージャーからは独立してる(参照を持っていない)んだから、レイアウトに計算結果を持たせるのは間違いだし値が意味を持たないよなーとか、レイアウトマネージャーからレイアウトを受けとってそのレイアウトにレイアウトマネージャーを引数として渡して幅計算をさせるっていうのは、直接レイアウトマネージャーに指定レイアウトの幅を聞けばいいし(※)、そうするならレイアウトマネージャーにはゲートウェイとして値をキャッシュして返す役割が期待できて、その値っていうのがつまり折り返さないときのために計算してレイアウトにこっそり(レイアウトの与り知らないところで)埋め込んだレイアウト幅のことなのだから、やっぱりレイアウトに値を埋め込むのは間違いだよなーとか、if (bFastMode) {...}
で囲まれた複数の部分が幅計算の適宜実行だけじゃなく、CLayoutMgr::_DoLayout
なんてアンダースコア付きで見るからにやばいメンバ関数を呼んでいて、レイアウトマネージャーの内臓に手を突っ込むがごとき癒着ぶりだなーとか、うーん、すでに悪魔の脳みそが必要な状態なんじゃないのこれ。
※こうなっていないのはレイアウトマネージャーが束ねるレイアウトっていうのがリンクリストになっていて、添え字で任意のレイアウトにランダムアクセスできないからだろうっていうのは想像できる。でも……。
落し所はレイアウトを必要なときに必要な分だけ作成して返すプロキシクラスに位置づけて、内部的にはレイアウトマネージャーの持つ情報に自由にアクセスすることだろうか。これだとレイアウトにレイアウトマネージャーへのポインタを持たせるオーバーヘッドを正当化できる、というか、それがレイアウトの持つ一番大事な情報ということになる。プロキシが自身が古くて無効だと知る方法はなんなのだろう。レイアウトマネージャーとレイアウトにバージョン番号を持たせて突き合わせるのだろうか。C++のイテレータはどうしてるかな……って考えると、俺だ! 俺が無効化されたイテレータを管理してた。デバッグモードでは違うけど。
でも……、レイアウトマネージャーの持つ情報のうち、レイアウト行ごとに分割できるものをまとめてレイアウトクラスとし、情報だけでなく行ごとに独立した機能もレイアウトのメンバーとしてレイアウトマネージャーからオフロードしたら、それって現状? プロキシクラスだなんだと言ってレイアウトマネージャーへのポインタを持たせる理屈をこねて、現状のレイアウトにポインタメンバを一個追加する言い訳を考えてただけ?
それもこれもレイアウトマネージャーを引数に取るレイアウトの一部のメンバ関数(CalcLayoutWidth, CalcLayoutOffset)と、レイアウトが自身で一切触れずにレイアウトマネージャーが操作するメンバ(m_nLayoutWidthとそのアクセサ)が気に入らないからだ。どちらもオフロード対象ではないということだから、レイアウトがレイアウトマネージャーへのポインタを持つか、レイアウトを通さず直接レイアウトマネージャーに尋ねて解決すべき問題。そもそも後者はメンバがメンバではないという一見してあり得ない状態。パブリックなメンバ変数しか持たない構造体ならそういう使われ方はあるが、じゃあお飾りでお為ごかしのアクセサを捨てよ。<こういうのって性格の反映なのかな。引きこもって外からの干渉を拒絶する姿勢、線を引いて私の仕事あなたの仕事と分ける姿勢って。人格のコアというか凝り固まってこじらせてるからこういう語調になるんだろうって。
……とまあこんな感じで脱線するから CSVモード(富豪パッチ版)の脱富豪化は進まないのだった。それにこういうのは実装前が一番楽しい段階だから。
<追記@2017-11-01>『[単行本(ソフトカバー)] 有野 和真【Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)】 技術評論社』で解説される Androidのコードに、自分で使うわけではないレイアウトのためのメンバーが出てくる。よくあるらしい。レイアウトは親が子のサイズを知りたがり子が親のサイズを知りたがるので、すぱっと割り切れないし決めきれない。それを解決する方法も入り組んでいて難しい。</追記>
当然の利用法として、特定の列を矩形選択で一括削除したくなったりするだろう。ダメ。削除し過ぎたり削除し足りなかったりする。なんだろう。削除の途中でタブストップの再計算が走るのだろうか。
すぐ上で
タブストップの随時再計算をそれなりの規模の CSVファイル(※ウチのPCだと富豪パッチバージョンで1MB・1万行ならもたつくけど現実的なレベルなので、それより大きいファイル)でやろうとして時間を空間で購った場合、横スクロールバーをドキュメントの最長行に対応させるためにやっていることっていうのはその一部になる。でもコストが整数2個から配列の配列と段違いに大きくなるので、CSVモードではない場合のコスト増を避けなければいけない。(折り返しモード)×(CSVモード)=4通りのコード分裂……
と書いたけど、別に配列1個でもよさそう。その場合「横スクロールバーをドキュメントの最長行に対応させるためにやっていること」とは独立したデータになるのでコード分裂もない。どういうデータを持つか。
スキャンの発生頻度はそこそこ低いのではないか。ネックは N番目の列の幅を網羅的にスキャンするときに、行の頭からスキャンして列番号をカウントしていくのでは後ろの方の列がつらいってこと。このへんはダブルクォーテーションの解釈と連携してさらなる補助データを用意することも考えられる。まあ、考えるだけで書かないんだけど……。