最終更新日 2025-02-18

簡易サーバーを立てて、レンダリングペインのHTML側から「編集エリアの複数の情報」を取得

個別ブラウザ(もしくはレンダリングペイン)のHTML側から秀丸エディタの編集エリアの「複数の情報」を通信で取得し、
その情報を元に個別ブラウザ(もしくはレンダリングペイン)へと反映してみましょう

1秒に1度情報を取得し、リアルタイムに反映します。

前ページでは、秀丸マクロ側に setInterval を持たせましたが、
今回はレンダリングペイン側に持たせてみましょう。

HttpServerオブジェクトでレスポンスとしてJSONにして返しましょう。

HmTextUpdateServer.mac
jsmode "JScript\\" + currentmacrofilename;

js {
debuginfo(2);

if (typeof(server) != "undefined") {
    server.close();
}
  
var server = hidemaru.createHttpServer(function (req, res) {
  
    if (req.url == "/text") {
        res.writeHead(200); // OK
        // 現在の「秀丸エディタのテキスト」と「カーソル位置」を返すようにする
        var obj = {
            text: gettotaltext(),
            column: column(),
            lineno: lineno()
        };
        res.write(JSON.stringify(obj));
        res.end("");
    } else {
        res.writeHead(404); // Not found
        res.end("");
    }
});
  
server.listen(0); //ランダムなポート
var port = server.port;


function makeUrl(htmlFullPath, port) {
    var htmlFullPath = htmlFullPath.replace(/\\/g, "/");
    var absoluteUrl = sprintf("file://%s?port=%d", encodeURI(htmlFullPath), port);
    return absoluteUrl;
}


// メインの処理
function main() {

    var absoluteUrl = makeUrl(currentmacrodirectory() + "\\HmTextUpdateServer.html", port);

    // 指定のパラメータでレンダーペインを開く。browserpanecommand にして、targetを "_each" にしてもほぼ同じこと
    renderpanecommand ( 
    {
        target: "renderPaneTest",
        url : absoluteUrl,
        watch: 0,
        watchsave: 0,
        initialize: "async",
        show: 1,
        size : 800
    }
    );
}

if (port > 0 ) {
    main();
} else {
    console.log("サーバー構築失敗");
}

} // js

HTML 側

受信した内容をJSONとしてパースして、利用してみましょう。

HmTextUpdateServer.html
<html>
<head>
<title>HmTextUpdateServer</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
<div id='position'></div>
<div id='output'></div>
<script>
// ファイルURLからポート番号を取得
let urlParams = new URLSearchParams(window.location.search);
let port = Number(urlParams.get('port'));

let lastText = "";
async function updateText() {
    fetch(`http://localhost:${port}/text`)
        .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.json(); // テキストとして来るが、JSONもテキストなので、JSONオブジェクト解釈。
        })
        .then(obj => {

            // カーソルの位置
            const pos = `lineno: ${obj.lineno}, column: ${obj.column}`;
            position.innerText = pos;

            // テキスト
            const text = obj.text;
            if (lastText != text) {
                lastText = text;

                // 受信したテキストをマークダウンと解釈してHTMLに
                const html = marked.parse(text);
                output.innerHTML = html;
            }
        })
        .catch(error => {
            output.innerText = "エラーが発生しました: " + error.message + error.stack;
        }
    );
}

document.addEventListener('DOMContentLoaded', ()=>{
    if (port > 0) {
        // 最初に1回受信する。その後は1秒に1回受信
        updateText();
        setInterval(updateText, 1000);
    } else {
        output.innerText = "ポート番号が指定されていません。";
    }
})

</script>
</body>
</html>