~秀丸マクロを「関数」を文字列で実行~

概要

この機能を利用する場合、秀丸エディタ v8.98 (正式版 or β9以上)を強く推奨します。
そうでない場合、数値と文字列の型を間違えて実行すると秀丸が不正な状態となります。

Hm.Macro.doEval(...)を「関数向けに特化」したものとして、「Hm.Macro.doFunction」が用意されています。

秀丸マクロにおいて「関数」とは

$ret = sprintf(....);

のように呼び出しに「( )」を利用し、返り値を受け取る形になっているものです。

一方、類似ですが関数のようでいて「返り値」がなく、「( )」もないものは秀丸マクロでは「文」もしくは「命令文」としています。

秀丸マクロの関数を実行可能です。

マクロ実行中のみ実行可能

Hm.Macro.doFunction(wstring func_name, ...関数の引数);
  • C++側のソース

    dllmain.cpp
    #include "HmCppInvoke.h"
    
    using namespace Hidemaru;
    using namespace std;
    
    extern "C" __declspec(dllexport) THmNumber test() {
        Hm.funcDllExport();
    
        try {
            auto ret = Hm.Macro.doFunction(L"sprintf", L"%03d%s", 555, L"あいうえお"); // 秀丸マクロ関数の「sprintf」を呼び出してみる例。
            if (! ret.getException() )
            {
                wstring retValue = ret.getResult<wstring>(); // getResult() には「関数(今回の場合sprintf)の返り値」が入っている。
                auto updatedArgs = ret.getArgs(); // getArgsには引数("%03d", 555)の関数実行後の値がvector<THmMacroVariable>の形で格納されている。
                                            // この機能は秀丸マクロの「getlinecount」など引数の値自体を書き換える関数のためにある。
                Hm.OutputPane.output(L"関数の返り値:" + retValue + L"\r\n");
                for (auto arg : updatedArgs) {
                    // 対象が数値タイプなら
                    if (std::holds_alternative<THmNumber>(arg)) {
                        THmNumber v = std::get<THmNumber>(arg);
                        Hm.OutputPane.output(L"arg:" + to_wstring(v) + L"\r\n");
                    }
                    // 対象が文字列タイプなら
                    else if (std::holds_alternative<wstring>(arg)) {
                        wstring v = std::get<wstring>(arg);
                        Hm.OutputPane.output(L"arg:" + v + L"\r\n");
                    }
    
                }
            }
            else
            {
                Hm.OutputPane.output(L"実行失敗\r\n");
            }
        }
        catch (exception e) {
            Hm.OutputPane.output(Text::Encoding::utf8_to_utf16(e.what()));
        }
    
        return 1;
    }
    

引数が書き換わる関数

C++の型に対する支援を期待するのなら、そのままHm.Macro.doFunction...と利用するよりも、
ラップするのがおすすめです。
また、秀丸マクロの関数にはごく一部、返り値のみならず、引数に渡している変数自体に値が入ってくるものもあります。
例えばgetlinecount (秀丸v8.94以降)enumregvalue (秀丸v9.00以降)などが該当します。
こういったものも取得できるようになっています。

今回は「秀丸マクロ関数のgetlinecount」をラップしてみましょう。

  • C++側のソース

    dllmain.cpp
    #include "HmCppInvoke.h"
    
    using namespace Hidemaru;
    using namespace std;
    
    std::tuple<THmNumber, THmNumber> getlinecount(wstring text, THmNumber index) {
        try {
            THmNumber dummycolumn = 0;
            auto ret = Hm.Macro.doFunction(L"getlinecount", text, index, dummycolumn); // 秀丸マクロ関数の「getlinecount」を呼び出してみる例。
            if (!ret.getException())
            {
                THmNumber lineno = ret.getResult<THmNumber>();
    
                auto upArgs = ret.getArgs(); // getArgs()で引数(text, index, dummycolumn)の関数実行後の値がvector<THmMacroVariable>の形で取得できる。
                THmNumber column = get<THmNumber>(upArgs[2]); // 関数に渡した3番めの引数(0オリジンでindex2のdummycolumn)が、関数の実行後どうなったのか取得。
                return { lineno, column };
            }
        }
        catch (exception e) {
        }
        return { 0,0 };
    }
    
    extern "C" __declspec(dllexport) THmNumber test() {
        Hm.funcDllExport();
    
        auto [lineno, column] = getlinecount(L"ABCD\nXYZ", 7);
        Hm.OutputPane.output(to_wstring(lineno) + L", " + to_wstring(column) + L"\r\n");
    
    
        return 1;
    }
    

Hm.Macro.doFunction(...) の返り値

    • getResult()メソッド

      実行した秀丸マク関数の返り値がTHmMacroVariable型で入っています。
      取得するにはテンプレートでの型指定、もしくは、std::get<T>での取得が必要です。

    • getArgs()メソッド

      秀丸マク関数を実行した後、秀丸マクロ関数に渡した引数が最終的にどういった値になったかを取得できます。
      vector<THmMacroVariable>型で、関数に渡した最初の引数が[0], 次の引数が[1], ... といった形で格納されています。 各種リスト要素は、std::get<T>での取得が必要です。

    • getException()メソッド

      何か明確な例外が発生した場合はexception型の例外インスタンスが入っています。
      例外が入っていない場合は、std::nullopt が入っっている。

    • getMessage()メソッド

      基本的には特になにもはいっておらず、空文字が入っています。

返り値が不明な関数はうまくいかない

秀丸マクロの関数にはCOMなどで利用する「member関数」など、
ごく一部「関数だけではその返り値が数値なのか文字列なのか区別が付かないものがあります。
こういった関数は、うまくいきません。
これらは、Hm.Macro.doEval(...)、getVar、setVar、などを利用してラップしましょう。