最終更新日 2024-09-25

自動起動マクロとhmJavaVMによるイベントハンドラ

秀丸マクロで一番困る現象が、
「マクロは実行した短時間に変数を構築し、終わったら全て破棄される」
という「変数や処理の情報が揮発する」作りになっていることです。

このためマクロ間の「時間間隔を置いた」情報の共有は、
不可能でこそないものの、
自然な記述では実現しにくい、という大きな問題がありました。

しかし、hmJavaVMではそのようなことに困ることはありません。
なぜなら、

1つのプロセス内であれば、マクロ実行中だろうと、そうでなかろうと、「情報が継続している」

からです。

イベントハンドラ的な記述をJavaで組んでみることにより、
如実に秀丸マクロとは異なる感触を実感出来ることでしょう。

Java側

Java側では全く普通のプログラムを書くことができます。

下の「各々のメソッド」は、呼び出されるタイミングは異なりますが、
「クラス内の変数」は「該当の秀丸プロセス」が生き続けている限り、継続しているため、
クラス全体としてイベントハンドラを彷彿とさせる自然で常識的な記述になっています。

HidemaruEvent.java
package myhmpac;

import java.util.ArrayList;
import java.util.List;

import hidemaru.Hm;

class FileInfo {
    public FileInfo() {}
    public String filename;
    public int codepage;
};

public class HidemaruEvent {

    static List<FileInfo> info = new ArrayList<>();

    private static void AddFileInfo() {
        if (info == null) {
            info = new ArrayList<FileInfo>();
        }

        FileInfo i = new FileInfo();
        i.filename = (String)Hm.Macro.getVar("filename2");
        i.codepage = (int)Hm.Macro.getVar("codepage");
        info.add(i);
    }

    // アウトプットパネルに文字列出力
    private static void PrintOutputPanel(Object message) {
        Hm.Macro.setVar("$__out_message",  message + "\r\n");

        Hm.Macro.doEval(
                String.join("\n",
                        "#OP=loaddll(\"HmOutputPane.dll\");",
                        "#ret=dllfunc(#OP,\"Output\",hidemaruhandle(0),$__out_message);",
                        "freedll(#OP);"
                    )
                );

        Hm.Macro.setVar("$__out_message",  "");
    }

    // ファイルの新規作成直後
    public static long OnPost_NewDocumentMake() {
        AddFileInfo();
        PrintOutputPanel("OnPost_NewDocumentMake");

        return 1;
    }

    // ファイルが開いた直後
    public static long OnPost_FileOpen() {
        AddFileInfo();
        PrintOutputPanel("OnPost_FileOpen");

        return 1;
    }

    // ファイルが閉じる直前
    public static long OnPrev_FileClose() {
        PrintOutputPanel("OnPrev_FileClose");
        PrintOutputPanel("このファイルのセーブの変遷");

        Integer cnt=0;
        for(FileInfo i : info) {
            if (cnt==0) {
                PrintOutputPanel( cnt.toString() + "最初");
            } else {
                PrintOutputPanel( cnt.toString() + "番目のセーブ");
            }
            PrintOutputPanel(i.filename);
            PrintOutputPanel("コードページ:" +i.codepage);
            cnt++;
        }

        info.clear();
        info = null;

         return 1;
    }

    // ファイルをセーブした直後
    public static long OnPost_FileSave() {
        PrintOutputPanel("OnPost_FileSave");
        AddFileInfo();

        return 1;
    }

    // マクロを手動で実行している
    public static void OnCall_Macro() {
        String currentmacrofilename = (String)Hm.Macro.getVar("currentmacrofilename");
        PrintOutputPanel(currentmacrofilename + "を手動で実行した");

        return 1;
    }
}

秀丸の自動起動マクロをイベントハンドラの契機とする

以下のように、秀丸マクロの自動起動マクロをイベントハンドラの替わりとしてみましょう

HidemaruAutoLaunch.mac
//===========================================================
// イベント番号に対応するラベルへと飛ぶ。
//-----------------------------------------------------------
disablebreak;
$event_label = "OnEvent_" + sprintf("%02d", event);
call $event_label;
enablebreak;
endmacro;
//===========================================================



//===========================================================
// 自動起動マクロではない
//-----------------------------------------------------------
OnEvent_00:
    return;

//===========================================================
// ファイルを開いた直後
//-----------------------------------------------------------
OnEvent_01:
    call OnPost_FileOpen;
    return;

//===========================================================
// 新規作成直後
//-----------------------------------------------------------
OnEvent_02:
    call OnPost_NewDocumentMake;
    return;

OnEvent_03:
    ##is_after_save = geteventparam(0);
    if (##is_after_save) {
        call OnPost_FileSave;
    }
    return;

OnEvent_04:
    return;
OnEvent_05:
    return;
OnEvent_06:
    return;

//===========================================================
// ファイルを閉じる直前
//-----------------------------------------------------------
OnEvent_07:
    call OnPrev_FileClose;
    
    return;
//===========================================================

OnEvent_08:
    return;
OnEvent_09:
    return;
OnEvent_10:
    return;


//-----------------------------------------------------------
// 各実装
//-----------------------------------------------------------

OnPost_NewDocumentMake:
    #JVM = loaddll(hidemarudir + @"\hmJavaVM.dll");
    #_ = dllfuncw(#JVM, "CallMethod", "myhmpac.HidemaruEvent", "OnPost_NewDocumentMake");
    freedll(#JVM);
    return;

OnPost_FileOpen:
    #JVM = loaddll(hidemarudir + @"\hmJavaVM.dll");
    #_ = dllfuncw(#JVM, "CallMethod", "myhmpac.HidemaruEvent", "OnPost_FileOpen");
    freedll(#JVM);
    return;

OnPost_FileSave:
    #JVM = loaddll(hidemarudir + @"\hmJavaVM.dll");
    #_ = dllfuncw(#JVM, "CallMethod", "myhmpac.HidemaruEvent", "OnPost_FileSave");
    freedll(#JVM);
    return;

OnPrev_FileClose:
    #JVM = loaddll(hidemarudir + @"\hmJavaVM.dll");
    #_ = dllfuncw(#JVM, "CallMethod", "myhmpac.HidemaruEvent", "OnPrev_FileClose");
    freedll(#JVM);
    return;

自動マクロとして.macを登録する

下図のように自動マクロとして

で、
HidemaruAutoLaunch.macを呼び出すようにしてみましょう。

動作確認

何か適当にファイルを開き、
そのファイルを次々に「異なるファイル名」や「異なる文字コード」で セーブし続けてください。
一番最後にそのファイルを閉じた時、「これまでにどのようなファイル名」や「文字コード番号」で保存してきたのか、
すべての情報がアウトプット枠に出ることでしょう。

まとめ

このように、本来のマクロでは、「実行して終了」したら情報が揮発してしまいますが、
hmJavaVMでは、プロセス単位で情報が継続しているため、
Javaの「必ず全てがクラスになっている」という特性との相性の良さも働き、
非常に自然な形でイベントハンドラ的に記述出来ます。