last updated:2024/04/20
Ver.9.19以降、マクロファイル内にある js{ } 記述内は JavaScript で記述することが可能になりました。 execjs文で別ファイルの JavaScript も実行できます。
JavaScript 実行時には、HidemaruGlobal オブジェクト、Hidemaru オブジェクト が常にグローバルに存在します。秀丸マクロ命令の実行や秀丸エディタの機能を使うには、この2つのオブジェクトを利用します。
他にも使用できるオブジェクトがあるのでマクロヘルプの JavaScript対応 -オブジェクト を参照してください。
その他 に注意点などが書いてあるので、よく読みましょう。
JavaScript は汎用プログラム言語です。各種ライブラリも利用できます。
JavaScriptの使い方としては以下の方法があります。どちらの方法がいいかはマクロによるのでいろいろ試してみましょう。
JavaScriptの実行環境としては以下の3つを指定可能です。
jsmode文のパラメータ1で文字列として指定します。
JScript(デフォルト)
WSHベースのエンジンで秀丸エディタを実行できる環境なら標準搭載されています。
対応規格は古い(ECMA-262 3rd edition(December 1999))。
JScriptの資料はJScript and VBScript Microsoft Learnを参照。
Chakra
IEベースのエンジン。
対応規格は古い(ECMA-262 5.1 edition(December 2009))。
WebView2
Chromium版 Microsoft Edge相当。 Windows10、11以外の場合は、MicrosoftのサイトからWebView2ランタイムをインストールする必要があります。 (Windows 7、8、8.1 をサポートしているのは、WebView2ランタイム バージョン 109 が最終になります)
JavaScriptの資料はJavaScript MDNを参照。
新しい JavaScript を使いたい場合は「WebView2」を使うしかありませんが、実行環境としては Windows 10、11 が主なターゲットになります。どの Windows 環境でも動かそうとする場合、現状では「JScript」を使うことになります。
秀丸マクロの文/キーワード/関数は、HidemaruGlobalオブジェクトのメソッドとして呼び出すことができます。
//filename2キーワードとmessage文の呼び出し
js {
//HidemaruGlobalオブジェクト の名前は「hidemaruGlobal」
a = hidemaruGlobal.filename2();
hidemaruGlobal.message(a);
}
「hidemaruGlobal」のメソッドとして呼び出す為、hidemaruGlobal.filename2();
としていますが、「hidemaruGlobal.」は省略できます。
(通常はHidemaruGlobalのメソッドがグローバルに展開されている)
//filename2キーワードとmessage文の呼び出し
js {
//HidemaruGlobalオブジェクトを省略
a = filename2();
message(a);
}
jsmode文を使うことで、明示的にグローバル展開を無効にしたり有効にしたりできます。
js{ }の実行中は、他の秀丸エディタへの切り替えができません。
従来のマクロでは、アクティブな秀丸ディタが切り替われば、マクロ実行する秀丸ディタも切り替わっていましたが、 js{ }内では切り替わりません。
従来のマクロ
debuginfo 1;
openfile "a.txt";
debuginfo sprintf("basename=%s\n",basename);
openfile "b.txt";
debuginfo sprintf("basename=%s\n",basename);
endmacro;
実行結果
basename=a.txt
basename=b.txt
ファイルを開くと、アクティブな秀丸ディタも切り替わるので、マクロの実行も切り替わっている。 (basename が切り替わっている)
jsの場合
debuginfo 1;
openfile "a.txt";
debuginfo sprintf("js:basename=%s\n",basename);
js{
openfile("b.txt");
debuginfo(sprintf("js:basename=%s\n", basename()));
}
endmacro;
実行結果
js:basename=a.txt
js:basename=a.txt
ファイルを開くと、アクティブな秀丸ディタは切り替わるが、マクロの実行は切り替わっていない。 (basename が変わっていない)
数値を JavaScript と 秀丸マクロ 間でやり取りする場合は、64bit版でも、32bitまでという制限あり。
(hidemaruオブジェクトの)getVar/setVarによる JavaScript - 秀丸マクロ間の数値型変数とのやりとりは、32bitの数値として扱われる。
32bitの数値の上限は 2147483647、下限は -2147483648
サンプルマクロ
debuginfo 2;
#a = 0x123456789;
debuginfo(sprintf("macro:#a=0x%llx\n", #a));
js{
var jsval1 = hidemaru.getVar("#a");
hidemaruGlobal.debuginfo(hidemaruGlobal.sprintf("js{} :#a=0x%llx\n", jsval1));
var jsval2 = 0x123456789;
hidemaruGlobal.debuginfo(hidemaruGlobal.sprintf("js{} :#b=0x%llx\n", jsval2));
hidemaru.setVar("#b", jsval2);
}
debuginfo(sprintf("macro:#b=0x%llx\n", #b));
endmacro;
実行結果
macro:#a=0x123456789
js{} :#a=0x23456789
js{} :#b=0x123456789
macro:#b=0x0
現時点では秀丸マクロが実行中かどうかという意味合い。
非同期の状態では、秀丸マクロ実行中ではないので使用できるオブジェクトに制限があります。
秀丸マクロを制限なく使いたい場合は、hidemaru.postExecMacroFile や hidemaru.postExecMacroMemory でマクロを実行する方法もあります。
マクロ本体
//ファイル名:test_js.mac
hidemaruversion "9.22.14";
//アウトプット枠に出力
debuginfo 2;
debuginfo sprintf("%d:%s start\n", tickcount, currentmacrobasename);
js{
//非同期で呼ばれる関数(秀丸マクロ実行中には呼び出されない)
function checkInterval(){
console.log(tickcount() + ":[非同期] Call checkInterval() idInterval=" + idInterval + "\n");
hidemaru.clearInterval(idInterval);
}
//秀丸マクロ実行中に実行される内容
var idInterval;
idInterval = hidemaru.setInterval(checkInterval,1000);
console.log(tickcount() + ":[同期] idInterval=" + idInterval + "\n");
}
debuginfo sprintf("%d:%s end\n", tickcount, currentmacrobasename);
endmacro;
実行結果
22375343:test_js.mac start ←マクロ開始
22375406:[同期] idInterval=23414 遅延時間と呼び出される関数を指定
22375406:test_js.mac end ←マクロ終了
22376406:[非同期] Call checkInterval() idInterval=23414 ← setIntervalで指定した時間後に checkInterval関数が実行されている。
実行結果を見ればわかりますが、checkInterval 関数はマクロ実行時には呼び出されず、マクロが終了してから setInterval で指定した時間経過後に呼び出されています。
JavaScript は明示的にリセットしなければ、同じスクリプトエンジン・同じ名前空間のオブジェクトはウィンドウを閉じるまで保持されます。この性質を利用しローバルスコープで変数を宣言すれば、どのタイミングでも変数にアクセス可能です。
なので、マクロを終了しても
idInterval = hidemaru.setInterval(checkInterval,1000);
idInterval の内容は保持されていので、checkInterval 関数内の
hidemaru.clearInterval(idInterval);
で、タイマーを止めることができます。