V9.35β10No.11713
秀丸担当 さん 24/06/20 15:05
 
V9.35β10を公開しました。
そろそろ正式にしたいです。

以下のページの「先行開発バージョンはこちら」からダウンロードできます。
https://hide.maruo.co.jp/software/hidemaru.html

32bit版:
https://hide.maruo.co.jp/software/bin3/hm935b10_signed.exe

64bit版:
https://hide.maruo.co.jp/software/bin3/hm935b10_x64_signed.exe

[ ]
RE:11713 V9.35β10No.11716
こみやんま さん 24/06/25 01:15
 
>V9.35β10を公開しました。

う〜ん、とりあえず報告だけしておくと、
「hidemaru.setTimeout」はまだ恐らくはβ10でもまだかなり深刻な問題を抱えてい
るように思います。

ディレイに200くらいが設定されていたとしても、何かの条件が重なると
「全く実行されない。対象関数の実行は完全にスルー」といった状況になるようです。

そしてその状況になると、もはや「該当の名前空間」に関しては、
・setTimeout自体を全く受け付けなくなってるかも
・一方、同状況になっても、setIntervalの方は受け付けるように思われる。

「それだけの情報では調べるのしんどい」という可能性が高いですが、
とりあえず、かなり高確率で状況を発生させることが出来るファイルは
下記、HmGoogleGeminiの1.1.2.4です。(1.1.2.5では強制的に直したと思われるので
発生しないと思われます)
 (多分HmOpenAiGptも同じ。理由はマクロ部分が限りなく同一だから)

https://github.com/komiyamma/hm_google_gemini/releases

マクロで関係しそうなところは、
「hideamru.setInterval」「hidemaru.setTimeout」を使っているところでしょうから、
そこだけを拾って簡易的なものを構築していけば絞り込めるかも。
(AIサービスへの接続の有無は多分無関係です)

@ pushPostExecMacroMemory(ここでsetTimeoutとsetInterval)
A setTimeout 1箇所。setTimeout(()=> ... , 200); のところ。このAの方が全く
実行されなくなる。同期部分にdebuginfo(2)、該当のsetTimeoutの関数内にconsole.
logを差しはさんでも実行されない。 該当の状況になったとしても、「この1つ上の
行」までは全く問題なく毎回実行されることも何度も確認済み。

1.1.2.4のHmGoogleGemini.macのみ (これだけでは実行できません)
https://github.com/komiyamma/hm_google_gemini/blob/b59fb5bd65b33fbdfbdd4cbc91aed6402550e096/HmGoogleGeminiLaunch/HmGoogleGemini.mac


時間があったら、私の方でも簡易なconsoleとsetTimeout,setIntervalのバージョン
を作ってみます。

「プロセスでの初めての実行」でいきなり該当のAが無視される、なんてことはない
ので、
「同一の名前空間」で「何度もsetInterval, setTimeout」が入り乱れて何かが「蓄
積」するのか?
的な印象を受けます。

比較的すぐに発生することもあれば、数時間経過してから発生なんてこともあって、
なかなかですが、通常使用ではなく、デバッグに集中すれば多分比較的すぐ見つかる
かも。


[ ]
RE:11716 V9.35β10No.11717
こみやんま さん 24/06/25 10:18
 
setTimeoutやsetIntervalの骨格は以下。
実行には「HmSimpleHttpServer.exe と php.exe」 は必要。
(上のリリースのHmGoogleGemini.zipから拾うか、もしくは別のexeの実行に対する応
答で置き換えても良いかと思います)


ただ、以下までまとめると、バグらしき状況(setTimeoutを全く受け付けなくなる状
況)は発生しないんですよねぇ。
キー登録して「ポポポポポ」と適当に連続実行しても問題はなさそうでした。


hidemaruversion "9.25.99";

jsmode @"WebView2\MySetTimeoutBug";
js {

debuginfo(2);
let hidemaruExeDir = hidemarudir();
let currentMacroDirectory = currentmacrodirectory();
// 宣言のみ。この空間マクロで時間を超えて共有するので初期化してはならない。
var avilablePort;

if (!Boolean(avilablePort)) {
    openHttpServer();
    console.log("ポートなし");
}


// 簡易Httpサーバーを立てる。ポート自体付きでサーバーを立てることが出来ない
限定的なマシンだと失敗するだろう。
function openHttpServer() {
    function getExtractPort(text) {
        const match = text.match(/PORT:(\d+)/);
        return match ? Number(match[1]) : null;
    }

    try {
        // このウィンドウハンドルの値を私ながら簡易サーバーを立ち上げる。
        let currentWindowHandle = hidemaru.getCurrentWindowHandle();

        // このウィンドウハンドルがなくなったら、2秒後に「該当の簡易サー
バー」は自動終了する
        // 簡易サーバーがどんどん増えるといったことはなくなる。
        let processInfo = hidemaru.runProcess('"' + currentMacroDirectory +
"\\HmSimpleHttpServer.exe" + '"' + " " + currentWindowHandle, currentMacroDi
rectory, "stdioAlive", "sjis");

        // 簡易サーバープログラムの出力を非同期で読み取る。
        // 簡易サーバープログラムはサーバーを起動するとともに、確保したポー
ト番号を標準出力に出す。
        let stdOut = processInfo.stdOut;
        stdOut.onReadLine(readLineAsync);

        // この関数は非同期で呼ばれる
        function readLineAsync(serverOutputText) {
            try {
                let port = getExtractPort(serverOutputText);
                if (port == 0) {
                    throw "HTTPサーバーのためのポートが確保できませんでした";
                }
                if (port != null) {
                    avilablePort = port;
                    pushPostExecMacroMemory("js { doMain() }");
                }
            } catch(err) {
                outputAlert(err);
            }
        }

    } catch (err) {
        outputAlert(err);
    }
}

// hidemaru.postExecMacroMemoryの実行を確かなものとする関数
function pushPostExecMacroMemory(command) {
    let isScheduled = 0;
    // まずは0ディレイで実行を試みる。setTimeoutに乗せる。
    hidemaru.setTimeout(()=>{
        if (!isScheduled) {
            console.log("ファーストトライ");
            isScheduled = hidemaru.postExecMacroMemory(command) ?? 1;
        }
    }, 0);

    // この下の処理が必要な理由は秀丸エディタv9.22〜v9.34のバグのため。setTi
meoutが同じフレーム(1秒60フレーム)内に
    // 2回実行されると、一方が実行されないバグのため。このため、上の処理が
本当に成功したのか? の確認が必要になる。
    let peRetry = hidemaru.setInterval(()=>{
        if (!isScheduled) {
            console.log("チックトライ");
            isScheduled = hidemaru.postExecMacroMemory(command) ?? 1;
        }
        if (isScheduled) {
            console.log("クリア");
            hidemaru.clearInterval(peRetry); }
    }, 100);
}

function outputAlert(msg) {
    let dll = loaddll(hidemaruExeDir + "\\HmOutputPane.dll");
    dll.dllfunc.Output(hidemaru.getCurrentWindowHandle(), msg + "\r\n");
}


// 選択テキストを質問内容としてファイルに保存し、AIを指定のパラメータやモ
デルで起動
function doSendQuestionContent() {
    console.log("doSendQuestionContent");
    hidemaru.setTimeout(()=>{console.log("★これが動作しないことがあるのか?
"); }, 200);
}

// メイン処理
function doMain() {
    try {
        doSendQuestionContent();
    } catch (err) {
        outputAlert(err);
    }
}


if (avilablePort > 0) {
    doMain();
}




} // js


[ ]
RE:11716 V9.35β10No.11718
秀丸担当 さん 24/06/25 10:19
 
バグ情報ありがとうございます。
setTimeoutがうまくいかないかもしれないということで、ちょっと現時点ではわから
ないですが、とりあえずHmGoogleGeminiの1.1.2.4を入れて試してみます。

[ ]
RE:11718 V9.35β10No.11719
こみやんま さん 24/06/25 10:42
 
>バグ情報ありがとうございます。
>setTimeoutがうまくいかないかもしれないということで、ちょっと現時点ではわか
>らないですが、とりあえずHmGoogleGeminiの1.1.2.4を入れて試してみます。

β7の修正で、renderpanecommand と hidemaru.setInterval 関連修正が入っている
ように、
renderpanecommand でパネル開いてることももしかすると関係しているのかもしれな
いです。
(console.logだけだとバグが発生しそうにはありませんでした)

[ ]
RE:11719 V9.35β10No.11720
秀丸担当 さん 24/06/25 17:36
 
HmGoogleGeminiで時間がかかって再現しました。
いったんその状態になると、その名前空間のインスタンスはsetTimeoutだけでなく、
setIntervalやrunProcessのonReadAllなども動きませんでした。

おそらく元の原因は同じかもしれない別の再現方法がわかりました。
WebView2のマクロを実行し、その後個別ブラウザ枠で何か表示させ、その次にまたWe
bView2のマクロを実行すると、コールバック的なものが動かないです。
直接的にはWebView2のPromiseが動かないです。
個別ブラウザ枠は作業フォルダを分離することで回避できることがわかりました。
(少し試してみた限りでは)
レンダリング枠はもともと作業フォルダも含めて分離されているので、それで起きる
場合があるということは、おそらく個別ブラウザ枠でもタイミング次第では起きるの
かもしれません。
秀丸エディタの問題だとしたらいいのですが、WebView2にそういう問題があるとする
と、jsmodeでWebView2を使うよりJScriptのほうが無難ということになってしまいそ
うです。

[ ]
RE:11720 V9.35β10No.11721
こみやんま さん 24/06/25 21:31
 
ぉぉ! 再現してよかったです。
(運が悪いと数日再現しないかなぁ、とかも思っていたので)


> WebView2のマクロを実行し、その後個別ブラウザ枠で何か表示させ、その次にまた
>WebView2のマクロを実行すると、
> コールバック的なものが動かないです。
> 直接的にはWebView2のPromiseが動かないです。


う〜む、マクロライブラリにも上がっている「HmMarkdownSimpleServer」などは、
この形になってるような気がしますが、普通に動作してるような気がします。

└ https://xn--pckzexbx21r8q9b.net/?page=nobu_tool_hm_markdown_simple_server_use
)

拡張子「.md」だと自動起動にしてるので「同じファイルに対してマニュアルで複数
回実行」することはないですが、
仮にマニュアルで同じファイルに対して複数回実行したとしても、
ただちに実行が破綻するといったようなことは無いように思えました。
(これも何かタイミングが悪いと壊れるのかな?)



>> 直接的にはWebView2のPromiseが動かない

JavaScriptは

@ メイン処理たる同期
A 優先非同期:Promise系の「優先キュー・優先コールスタック」
B 通常非同期:一般的なsetTimeout/setIntervalなどの「通常キュー・通常コール
スタック」

で「全体でシングルスレッド」の中を「1つのコールスタック枠」を出入りして疑似
的に非同期(であるかのように)見せているだけですが、
「Promiseが実行されない」となると、「メイン処理・同期処理の部分」が「終わっ
ていない」と「JSエンジンが見なしている」んでしょうか。

Promiseが実行されなければ、Aより優先度が落ちる Bはもちろん実行されないので、
該当の状況に陥ると、window.setTimeout/window.setIntervalなども実行されないの
はほぼ確実でしょうねぇ...

[ ]
RE:11721 V9.35β10No.11722
秀丸担当 さん 24/06/26 09:39
 
個別ブラウザ枠のときで確実に再現できるので、それで条件を絞り込んでWebView2の
問題を特定できました。
PreferredColorSchemeを設定すると、それだけでだめでした。
一見関係無さそうな、PreferredColorSchemeの1行をコメントアウトするだけで問題
無くなりました。
V9.35β9より前ではダークモード時のみ問題、V9.35β9からは常に問題が起きていた
ということになるようです。

個別ブラウザ枠(たぶんレンダリング枠も)でPreferredColorSchemeを設定すると、
たぶん同一プロセスにある別のWebView2インスタンスにも影響を与え、Promiseが動
かなくなってしまうようです。

V9.35β9の修正だけボツにできたらいいのですが、ダークモード時は効果ないので、
以前からのダークモード適用のPreferredColorSchemeをボツにしたほうがよさそうで
す。

[ ]
RE:11722 V9.35β10No.11723
こみやんま さん 24/06/26 10:58
 
>PreferredColorSchemeを設定すると、それだけでだめでした。

うーむ、まさかのPreferredColorScheme とはw

となると、HTMLまわりで以下みたいな(ある種、正規のカラースキーマ取得)機能は
秀丸としてはちょっと提供できなそう、といった形でしょうか。


<!DOCTYPE html>
<html>

<head>
    <title>ダークモードはブラウザ枠やレンダリング枠でも有効</title>
    <style>
        @media (prefers-color-scheme: light) {
            body {
                background-color: #fff;
                color: #222;
            }
        }

        @media (prefers-color-scheme: dark) {
            body {
                background-color: #222;
                color: #eee;
            }
        }
    </style>
</head>
<body>
    <h1 id="kami">色...</h1>
    <script>
        let kamiEle = document.getElementById("kami");
        // 今レンダリングしてるブラウザコンポーネントはダークモードなの?
        if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
            kamiEle.innerText = "ダークモード";
        } else {
            kamiEle.innerText = "ライトモード";
        }
    </script>
</body>

</html>


本体のWebView2から「darkmode()の値」を伝搬すれば色々と手段はありますが、
以下みたいにして、URLに  ***.html?darkmode=1 みたいに伝えますかねぇ。

<!DOCTYPE html>
<html>

<head>
    <title>ダークモードはブラウザ枠やレンダリング枠でも有効</title>
    <style>
        [theme-color-scheme="light"] {
            body {
                background-color: #fff;
                color: #222;
            }
        }

        [theme-color-scheme="dark"] {
            body {
                background-color: #222;
                color: #eee;
            }
        }
    </style>
    <script>

        // URL パラメータから prefers-theme-color-scheme の値を取得
        const urlParams = new URLSearchParams(window.location.search);
        const isDarkMode = urlParams.get('darkmode');
        document.documentElement.setAttribute("theme-color-scheme", isDarkMo
de ? "dark" : "light");
    </script>
</head>
<body>
    <h1 id="kami">色...</h1>
    <script>
        let kamiEle = document.getElementById("kami");
        // 今レンダリングしてるブラウザコンポーネントはダークモードなの?
        if ( document.documentElement.getAttribute("theme-color-scheme") ==
"dark" ) {
            kamiEle.innerText = "ダークモード";
        } else {
            kamiEle.innerText = "ライトモード";
        }
    </script>
</body>

</html>


しかし、可能ならいちいちパラメータとして伝搬することなく、
HTML側で閉じて処理する方法があった方がいいかなーとは思います。

[ ]
RE:11723 V9.35β10No.11724
こみやんま さん 24/06/26 13:07
 
>>PreferredColorSchemeを設定すると、それだけでだめでした。

PreferredColorScheme を設定すると、不具合が出るということであれば、

とりあえず、カラースキーマをHTML側で得られれば良いでしょうから、

以下みたいなのもアリだと思います。
(検索するとすれれば「テーマカラー」か「prefers-color-scheme」かどちらかでし
ょうから、その辺でヘルプでひっかかりやすい構成がよいかなぁと)


@ネイティブ側から「NavigationCompleted」のタイミングで、
「document」の「prefers-color-scheme」に値を設定しておいてやる。

private void WebView2_NavigationCompleted(object sender, NavigationCompleted
EventArgs e)
{
    bool darkmode = hidemaru.isDarkMode(); // ネイティブで秀丸本体のダーク
モードを得て...

    if (darkmode) {
        webView2.CoreWebView2.ExecuteScriptAsync(
            @"
            window.addEventListener('DOMContentLoaded', function() {
                if (document) document.documentElement.setAttribute('prefers
-color-scheme', 'dark');
            });
            ";
    } else {
        // ほとんどの人は、lightだろうから、lightの時にわざわざ値をlightとい
う設定しない方がよいかもしれない。余計な実行もなくなるし...
        webView2.CoreWebView2.ExecuteScriptAsync(
            @"
            window.addEventListener('DOMContentLoaded', function() {
                if (document) document.documentElement.setAttribute('prefers
-color-scheme', 'light');
            });
            ";
    }
}



A @media という書き方は出来ないものの、比較的近い書き方でテーマをスイッチン
グできる。
//------------------------------ HTML 側でカラースキーマ適応

<html>
<head>
<style>
    body {
        background-color: #fff;
        color: #222;
    }

[prefers-color-scheme="dark"] {
    body {
        background-color: #222;
        color: #eee;
    }
}
</style>
</head>
<body>
<script>
/* 要するに以下JSと同じことをネイティブ側から登録しておく感じ
document.addEventListener("DOMContentLoaded", ()=> {
let darkmode = 1;
if (document) { document.documentElement.setAttribute('prefers-color-scheme',
 darkmode ? 'dark' : 'light'); }
});
*/
</script>
</body>

</html>

[ ]
RE:11724 V9.35β10No.11725
秀丸担当 さん 24/06/26 16:09
 
いずれWebView2が直るかもしれないですが、秀丸エディタとしては当面PreferredCol
orSchemeの指定はしないようにします。
後からprefers-color-schemeをいじる方法もあるのですね。情報ありがとうございま
す。
何かしら競合が起きないか気になるのと、将来WebView2が直るかもしれないので、そ
こまでするのはやめておこうと思います。

[ ]
RE:11725 V9.35β10No.11726
こみやんま さん 24/06/27 11:29
 
>後からprefers-color-schemeをいじる方法もあるのですね。情報ありがとうござい
>ます。

あ、そうではなく、(prefers-color-scheme という名前で勘違いさせてしまったかも)

「秀丸用にカラーテーマの属性を新設」し、そこに値を設定すればよいのでは?
ということです。


秀丸のブラウザ枠やレンダリング枠で、HTMLコンテンツ内部で
カラーテーマをコントロールするやり方をまとめました。
(@media {***}は使えなくなるという前提で)

https://xn--pckzexbx21r8q9b.net/?page=nobu_tool_hm_webview2_pane_dark


そうすると行き着く先は、2つになるかと思っています。

@その先のページのように、カラー情報を伝達して、HTML側で受け取る。
(HTMLが100行などある場合、重複で持ちたくない場合に有効)

AHTML自体をライトモードとダークモードで分けてしまう。
(HTMLが30行未満だと、こちらの方が手っ取り早いと判断する人も多そう)


@の場合は、行き着く先は概ね 先のURLの一番下、もしくは下から2番目のような形
になっていきます。

--- test.mac ----
jsmode "WebView2";
 
js {
    // 対象のHTML
    let targetfile = `${currentmacrodirectory()}\\test.html`;
 
    // URLオブジェクトに直す
    let absoluteUrl = new URL(targetfile);
 
    // GETパラメターとして darkmode=1 という形で追加
    let params = new URLSearchParams();
    params.set('darkmode', darkmode());
    absoluteUrl.search = params.toString();
 
    // 個別ブラウザ枠として開く
    browserpanecommand(
    {
        target: "_each",
        url : absoluteUrl,
        initialize: "async",
        show: 1
    }
    );
}


-------- test.html -----------
<html>
<head>
<style>
[hm-theme-color="dark"] {
    color-scheme: dark;
}
[hm-theme-color="light"] {
    color-scheme: light;
}
</style>
</head>
<body>
あああ
<a href="aaa">bbbb</a>
<script>
let targetColor ;
const urlSearchParams = new URLSearchParams(window.location.search);
const isDarkModeEnabled = urlSearchParams.get('darkmode');
 
if (isDarkModeEnabled == 1) {
    document.documentElement.setAttribute('hm-theme-color', "dark");
} else {
    document.documentElement.setAttribute('hm-theme-color', "light");
}
</script>
</body>
</html>


これってめんどくさいのでは?
という話です。
(@media で拾えなくなるということは、お手軽な手法が結構一気に崩壊するので...)

ネイティブ側で
private void WebView2_NavigationCompleted(object sender, NavigationCompleted
EventArgs e)
{
    bool darkmode = hidemaru.isDarkMode(); // ネイティブで秀丸本体のダーク
モードを得て...

    if (darkmode) {
        webView2.CoreWebView2.ExecuteScriptAsync(
            @"
            window.addEventListener('DOMContentLoaded', function() {
                if (document) document.documentElement.setAttribute('hm-them
e-color', 'dark');
            });
            ";
    } else {
        // ほとんどの人は、lightだろうから、lightの時にわざわざ値をlightとい
う設定しない方がよいかもしれない。余計な実行もなくなるし...
        webView2.CoreWebView2.ExecuteScriptAsync(
            @"
            window.addEventListener('DOMContentLoaded', function() {
                if (document) document.documentElement.setAttribute('hm-them
e-color', 'light');
            });
            ";
    }
}


HTMLのルート属性として「hm-theme-color」に値が設定されますよ、という決め事を
しておけば、
「マクロからの伝達も不要」になり、
「HTMLのJSも不要」になり、

各ユーザーは以下みたいなHTMLで切り替えられるようになりますよ、
といった話です。


<html>
<head>
<style>
[hm-theme-color="dark"] {
    color-scheme: dark;
}
[hm-theme-color="light"] {
    color-scheme: light;
}
</style>
</head>
<body>
あああ
<a href="aaa">bbbb</a>
</body>
</html>


これにこだわる必要はないですが、
何かブラウザ枠やレンダリング枠のテーマカラーを
本体のテーマカラーを合わせる「パターン」や「イディオム」
みたいなものは提示しておいたほうが良いかなとは思います。
(@media が使えなくなるなら、一気に書き方が揺れるし難度も上がると思いますので)


[ ]
RE:11726 V9.35β10No.11727
秀丸担当 さん 24/06/27 14:56
 
そういう意味だったのですね。
それだったら無くは無いと思います。
独自すぎる気もするので、現時点ではやめておこうと思います。
ありがとうございます。

[ ]