秀丸エディタ・HmCustomLivePreviewのカスタム 中級編

  • 概要

    ここでは、前節「秀丸エディタ・HmCustomLivePreviewのカスタム 初級編」の続きです。

  • HmCustomLivePreviewVar.macの作成

    それでは、HmCustomLivePreviewDefault.macをコピーして、HmCustomLivePreviewVar.macとしましょう。

    今回の話題は、hmJSのhmJS専用の関数群の中でも、
    hm.Macro.Var(...)やhm.Macro.Eval(...)が使えるのか、使えないのかの問題と解説となります。

  • HmCustomLivePreviewの「フォームの表示」と「マクロ中か否か」の問題

    HmCustomLivePreviewの動作を確認してみましょう。
    この理解は、JScriptで使える変数、使えない変数の理解する上で欠かせないものとなります。

    • マクロの実行開始~フォームを閉じる(もしくは秀丸を閉じる)までを時間軸とすると、下図のようになります。

    この中で、「秀丸マクロの変数やシンボル」へとアクセス可能なのは、「マクロ実行開始」~「マクロ終了」までです。
    「HmCustomLivePreview」のフォームビューワーが表示された瞬間には、すでに「マクロは終了」しています。

    マクロが実行しっぱなしだと、他のマクロが実行できず、不便ですのでこのようになっています。
    (秀丸マクロはマクロを複数同時に実行できないため、他のマクロ実行のさまたげとならないように、
    このような苦肉の策が必要なのです
    )

    このことは、下記のプログラムを実行してみればわかります。

    #dll = loaddll( currentmacrodirectory + @"\HmCustomLivePreview.dll" );
    if (!#dll) {
      message("NO");
      endmacro;
    }
    
    #_ = dllfuncw( #dll, "DoString", R"JSCRIPT(
    
    function OnCustomTranslateHTML(filename, rawtext) {
    
        return hm.Macro.Var("column").toString();
    }
    
    )JSCRIPT"
    );
    
    #_ = dllfuncw( #dll, "Show", hidemaruhandle(0) );
    

    これをHmCustomLivePreviewで見てみると、下図のようになります。
    「一瞬だけcolumnに相当する数値」が出た後、次のTick以降は、秀丸のテキストまんまへと戻ってしまったハズです。

    秀丸デバッグモニターのエラーなどで確認すると

    のようになっているのが確認できます。
    先述したように、「HmCustomLivePreview」を表示した直後に「秀丸マクロ」としては終了してしまったので、
    フォーム表示以降は、マクロ変数にはアクセスできないのです。

  • 秀丸の編集テキストのフォントを、そのままHmCustomLivePreviewへと伝達

    それでは、hm.Macro.Var(...)の使い手は全くないのでしょうか?
    そんなことはないと思われます、

    確かにライブ情報としては使えないものの、「HmCustomLivePreview」の起動時に収集できる情報でも
    十分に価値があるものも、中にはあることでしょう。

    例えば、プレビュー画面で利用されるフォントが、
    現在秀丸で編集中の画面で利用しているフォントと同じもので描画する、
    といったこともそのひとつでしょう。

  • HmCustomLivePreviewFont.macの作成

    それでは、HmCustomLivePreviewFont.macをコピーして、HmCustomLivePreviewFont.macを作成してみましょう。

    #dll = loaddll( currentmacrodirectory + @"\HmCustomLivePreview.dll" );
    if (!#dll) {
        message("NO");
        endmacro;
    }
    
    #_ = dllfuncw( #dll, "DoString", R"JSCRIPT(
    
    // 秀丸でマクロ開始時点で使用されているフォント名の取得
    // (OnCustomTranslateHTML関数の中では取得できないので、最初の1回ここで取得しておく)
    var fontname = hm.Macro.Var("fontname");
    
    function OnCustomTranslateHTML(filename, rawtext) {
    
        var htmltext = rawtext;
        htmltext = htmltext.replace( /</g, "&lt;");
        htmltext = htmltext.replace( />/g, "&gt;");
        htmltext = htmltext.replace( /\n/g, "<br>");
    
        // 該当フォントのタグで、HTMLを囲む
        htmltext = "<font face='"+fontname+"'>" + htmltext + "</font>";
        return htmltext;
    }
    
    
    )JSCRIPT"
    );
    
    #_ = dllfuncw( #dll, "Show", hidemaruhandle(0) );
        

    これをHmCustomLivePreviewで見てみると、下図のようになります。

    秀丸上のフォント名がきっちりと反映されていることがわかるでしょう。

  • 選択中のテキストだけレンダリングする

    次は、秀丸で編集しているテキスト全体ではなく、
    「秀丸上で選択しているテキスト」だけを対象にレンダリングするようにします。
    ライブビューですので「テキストの選択範囲を変更すれば」、描画内容が更新されるわけです。

    HmCustomLivePreviewSelectImg.macの作成

    HmCustomLivePreviewImg.macをコピーして、HmCustomLivePreviewSelectImg.macとしましょう。
    そして、下図のハイライトの行だけを書き換えます。

    #dll = loaddll( currentmacrodirectory + @"\HmCustomLivePreview.dll" );
    if (!#dll) {
      message("HmCustomLive");
      endmacro;
    }
    
    #_ = dllfuncw( #dll, "DoString", R"JSCRIPT(
    
    function OnCustomTranslateHTML(filename, rawtext) {
    
        var htmltext = hm.Edit.SelectedText;
        htmltext = htmltext.replace( /</g, "&lt;");
        htmltext = htmltext.replace( />/g, "&gt;");
        htmltext = htmltext.replace( /\n/g, "<br>");
    
        htmltext = htmltext.replace(/---/g, "<hr>" );
        // ここまでは前回までの話
    
        // 画像と思われる正規表現をあなた独自に定義する。
        // ここでは「a-zA-Z0-9_\/」のいずれの文字列が連続しており、
        // その後に「.png」「.jpg」「.jpeg」「.bmp」.gif」のいずれかの文字が続いていれば、
        // 画像とみなしている。
        // 厳密性は全くないが、「あなただけが利用する置換法則」なので、
        // あなたが要求する範囲を満たす正規表現ならなんでもよいのである。
        var re = /[a-zA-Z0-9_\\\/]+\.(png|jpe?g|bmp|gif)/g;
    
        // htmltext内に対象の「re」に当てはまる箇所を発見する度に、
        // 正規表現キャプチャーを引数として、image_regex_replacerを呼び出す。
        // 正規表現キャプチャーとは「(...)」に当てはまった中身のこと。
        htmltext = htmltext.replace(re, image_regex_replacer );
        return htmltext;
    }
    
    // $0はマッチした全体、$1は1つめの(...)、よって上の正規表現だと、「拡張子」に相当するのが1つめ
    // $2は今回は利用していない。
    function image_regex_replacer($0,$1,$2) {
    
        // マッチしてれば
        if ($0) {
            // 現在のカレントディレクトリはどこ?(=原則ファイルを開いている場所)
            // より正確には、filnameをグローバル変数にコピーし、clr.System.IO.Path.GetDirectoryName(...)などを利用する。
            var currentdir = clr.System.IO.Directory.GetCurrentDirectory();
    
            // イメージファイルのフルパスを求める。
            var imgfilefullpath = currentdir + "/" + $0;
    
            // そのファイルが実際にあれば…
            if ( clr.System.IO.File.Exists(imgfilefullpath) ) {
                // HTMLとして画像を描画できるように、イメージタグに変換する。
                var ret = $0;
                ret += "<br><img src='" + currentdir + "/" + $0 + "'><br>";
                ret += "拡張子" + $1 + "<br>"
    
                return ret;
    
            // 無ければ、(not found)という文字列でもくっ付けておく。
            } else {
                return $0 + "(not found)";
            }
        }
    
        return "";
    }
    
    )JSCRIPT"
    );
    
    #_ = dllfuncw( #dll, "Show", hidemaruhandle(0) );
    

    このようにすることで、アルゴリズムはそのままに、「編集テキスト全体」ではなく、
    「選択しているテキスト」に対して同様の処理をするようになりました。

    ライブプレビューですので、選択範囲をどんどん変えていくと、
    描画の中身も変わっていくことを確認してみましょう。