Skip to content

Instantly share code, notes, and snippets.

@densya203
Last active May 12, 2023 06:08
Show Gist options
  • Save densya203/886a908406c9dfc853592f5e8fd59531 to your computer and use it in GitHub Desktop.
Save densya203/886a908406c9dfc853592f5e8fd59531 to your computer and use it in GitHub Desktop.
秀丸マクロ。WSL2のext4ファイルシステム(すなわち /mnt/ 以外)に配置してある大量のファイル群へのグレップを、純正の4倍(当社比)早く実行します。
// 最新バージョンは
// https://gist.github.com/densya203/886a908406c9dfc853592f5e8fd59531 で入手ください。
// gist から解凍した後、このファイルを秀丸で開いて Shift-JIS CR+LF にしてください。
//
//-----------------------------------------------------------------------------
// 初期設定 各自の環境に合わせて設定してください。
//-----------------------------------------------------------------------------
// 検索対象ファイルの拡張子
// 最後はカンマで終わってOK
// html と js → "html,js,"
$DEFAULT_FILE = "rb,erb";
// WindowsからデフォルトのWSLへアクセスするときのパス
// 「//wsl.localhost/」にパワーシェルで wsl -l -q を実行したときに最初にヒット
// する文字列を足してもらえばOKだと思います。
// / 区切りで設定
$DEFAULT_LINUX_PATH_PREFIX = "//wsl.localhost/Ubuntu";
// グレップ結果からタグジャンプや おーなーしぇふさんの z_grep.mac の
// 「Grep検索結果から置換(行単位で置換)」を使いたい人用の設定
// http://hidemacro.gtx.jp/doc/kensaku.htm
$DEFAULT_REPLACE_PATH_FROM = "/home/";
$DEFAULT_REPLACE_PATH_TO = "\\\\wsl.localhost\\Ubuntu\\home\\";
// ↑にはネットワークドライブを当てて、↓のようにするとパスが短くなり、かつトリ
// プルクリックでのタグジャンプが効いてなにかといいです。
// $DEFAULT_REPLACE_PATH_TO = "U:\\home\\";
//-----------------------------------------------------------------------------
// 定数定義
//-----------------------------------------------------------------------------
// 履歴保存位置
$REGISTRY_PATH = "Software\\Hidemaruo\\Hidemaru\\" + currentmacrobasename;
// 履歴保存数
#HISTORY_SIZE_KEYWORD = 30;
#HISTORY_SIZE_FILE = 5;
#HISTORY_SIZE_DIRECTORY = 30;
//-----------------------------------------------------------------------------
// メイン処理
//-----------------------------------------------------------------------------
Main:
debuginfo 2; // 2 → アプトプット枠にも出力
disabledraw;
call InitDengakuDLL;
call ReadDataFromRegistry;
call CreateDialog;
call LoadHistoryToCtrls;
call MainLoop;
goto EndProcess;
return;
//-----------------------------------------------------------------------------
// 田楽DLLの利用準備
//-----------------------------------------------------------------------------
InitDengakuDLL:
if (version < 311) {
message "このマクロには秀丸の Ver.3.11 以降が必要です。";
endmacro;
}
$$dllFileName = hidemarudir + "\\dengakudll.dll";
// 田楽DLLのロード
loaddll($$dllFileName);
if (!result) {
message "田楽DLL をロードできませんでした。\nネットで検索してゲットした「dengakudll.dll」を\n" + hidemarudir + " に配置してください。";
endmacro;
}
return;
//-----------------------------------------------------------------------------
// レジストリから履歴を読み取り、グローバル変数の配列にセットします。
//-----------------------------------------------------------------------------
ReadDataFromRegistry:
openreg "CURRENTUSER", $REGISTRY_PATH;
// 存在しない場合、レジストリキーを生成して初期化する
if (result == 0) {
createreg "CURRENTUSER", $REGISTRY_PATH;
##i = 0;
while (##i < #HISTORY_SIZE_FILE){
$$reg_key = "file" + str(##i);
if (##i == 0) {
writeregstr $$reg_key, $DEFAULT_FILE;
} else {
writeregstr $$reg_key, "";
}
##i = ##i + 1;
}
##i = 0;
while (##i < #HISTORY_SIZE_DIRECTORY){
$$reg_key = "directory" + str(##i);
writeregstr $$reg_key, "";
##i = ##i + 1;
}
writeregstr "from", $DEFAULT_REPLACE_PATH_FROM;
writeregstr "to" , $DEFAULT_REPLACE_PATH_TO;
writeregstr "reg_on", "0";
}
// レジストリに保持されている内容を読み込む
##i = 0;
while (##i < #HISTORY_SIZE_FILE){
$$reg_key = "file" + str(##i);
$file_history[##i] = getregstr($$reg_key);
##i = ##i + 1;
}
##i = 0;
while (##i < #HISTORY_SIZE_DIRECTORY){
$$reg_key = "directory" + str(##i);
$directory_history[##i] = getregstr($$reg_key);
##i = ##i + 1;
}
$path_replace_from = getregstr("from");
$path_replace_to = getregstr("to");
$reg_on = getregstr("reg_on");
closereg;
return;
//-----------------------------------------------------------------------------
// ダイアログを作成して表示します。
//-----------------------------------------------------------------------------
CreateDialog:
// 既に開いていればダイアログを閉じる
if (#isOpen){
#n = dllfunc("ENDDIALOG");
}
// ダイアログの作成
#n = dllfunc("NEWDIALOG", "grepの実行(WSL2ネイティブ)", 100, "0 0 window MeiryoKe_UIGothic 11 px");
#n = dllfunc("NEWPAGE", 99);
// 検索する文字列
#n = dllfunc("NEWCONTROL", "text", "", "検索する文字列(&S)");
#n = dllfunc("SETCTRLWIDTH", "", 26);
#n = dllfunc("NEWCONTROL", "combo", "target_keyword", "");
#n = dllfunc("SETCTRLWIDTH", "", 63);
#n = dllfunc("NEWCONTROL", "check", "reg_on", "正規表現");
#n = dllfunc("SETCTRLSTATE", "reg_on", $reg_on);
#n = dllfunc("NEWPAGE", 99);
// 検索するファイル
#n = dllfunc("NEWCONTROL", "text", "", "検索するファイル(&N)");
#n = dllfunc("SETCTRLWIDTH", "", 26);
#n = dllfunc("NEWCONTROL", "combo", "target_file", "");
#n = dllfunc("SETCTRLWIDTH", "", 73);
#n = dllfunc("NEWPAGE", 99);
// 検索するディレクトリ
#n = dllfunc("NEWCONTROL", "text", "", "WSL上の検索するディレクトリ(&D)");
#n = dllfunc("SETCTRLWIDTH", "", 26);
#n = dllfunc("NEWCONTROL", "combo", "target_directory", "");
#n = dllfunc("SETCTRLWIDTH", "", 63);
// カレント
#n = dllfunc("NEWCONTROL", "button", "choose_current_button", "カレント");
#n = dllfunc("SETCTRLWIDTH", "", 10);
#n = dllfunc("SETCTRLNOTIFY", "", "10");
#n = dllfunc("NEWPAGE", 99);
// 結果のパス変更
#n = dllfunc("NEWCONTROL", "text", "", "結果一覧におけるパスの変更(&C)");
#n = dllfunc("SETCTRLWIDTH", "", 26);
#n = dllfunc("NEWCONTROL", "edit", "path_replace_from", $path_replace_from);
#n = dllfunc("SETCTRLWIDTH", "", 33);
#n = dllfunc("NEWCONTROL", "text", "", "→");
#n = dllfunc("SETCTRLWIDTH", "", 3);
#n = dllfunc("NEWCONTROL", "edit", "path_replace_to", $path_replace_to);
#n = dllfunc("SETCTRLWIDTH", "", 37);
#n = dllfunc("NEWPAGE", 99);
// OK キャンセルボタン
#n = dllfunc("NEWCONTROL", "okcancel");
#n = dllfunc("SETCTRLWIDTH", "", 50);
#n = dllfunc("SETCTRLHEIGHT", "", 1);
// ダイアログオープン
#n = dllfunc("SHOWDIALOG", hidemaruhandle(0), 0);
#isOpen = true;
return;
//-----------------------------------------------------------------------------
// 各コントロールオブジェクトに履歴をロードします。
//-----------------------------------------------------------------------------
LoadHistoryToCtrls:
// 「検索する文字列」
##i = 0;
while(##i < #HISTORY_SIZE_KEYWORD){
if (##i == 0) {
// 範囲選択している場合
if (selecting == 1) {
#n = dllfunc("SETCTRLSTRING", "target_keyword", gettext(seltopx, seltopy, selendx, selendy, 1));
} else {
#n = dllfunc("SETCTRLSTRING", "target_keyword", getsearchhist(##i));
}
}
#n = dllfunc("SETCTRLITEM", "target_keyword", getsearchhist(##i));
##i = ##i + 1;
}
// 「検索するファイル」
##i = 0;
while (##i < #HISTORY_SIZE_FILE){
if ($file_history[##i] != "") {
if (##i == 0) {
#n = dllfunc("SETCTRLSTRING", "target_file", $file_history[##i]);
}
#n = dllfunc("SETCTRLITEM", "target_file", $file_history[##i]);
}
##i = ##i + 1;
}
// 「検索するディレクトリ」
##i = 0;
while (##i < #HISTORY_SIZE_DIRECTORY){
if ($directory_history[##i] != "") {
if (##i == 0) {
#n = dllfunc("SETCTRLSTRING", "target_directory", $directory_history[##i]);
}
#n = dllfunc("SETCTRLITEM", "target_directory", $directory_history[##i]);
}
##i = ##i + 1;
}
return;
//-----------------------------------------------------------------------------
// メインループ。コントロールからの入力を受け付けます。
//-----------------------------------------------------------------------------
MainLoop:
while (true) {
$$mode = "";
while (strlen($$mode) == 0) {
$$mode = dllfuncstr("WAITCTRLNOTIFY", 10);
}
// キャンセルボタン押下
if ($$mode == "0") {
// ダイアログを閉じて終了
#n = dllfunc("ENDDIALOG");
$target_keyword = "";
$target_file = "";
$target_directory = "";
break;
// OKボタン押下
} else if ($$mode == "1") {
$target_keyword = dllfuncstr("GETCTRLSTRING", "target_keyword");
$target_file = dllfuncstr("GETCTRLSTRING", "target_file");
$target_directory = dllfuncstr("GETCTRLSTRING", "target_directory");
$path_replace_from = dllfuncstr("GETCTRLSTRING", "path_replace_from");
$path_replace_to = dllfuncstr("GETCTRLSTRING", "path_replace_to");
$reg_on = dllfuncstr("GETCTRLSTATE" , "reg_on");
$$error_message = "";
if ($target_keyword == "") {
$$error_message = $$error_message + "検索する文字列を入力してください。\n";
}
if ($target_file == "") {
$$error_message = $$error_message + "検索するファイルを入力してください。\n";
}
if ($target_directory == "") {
$$error_message = $$error_message + "検索するディレクトリを入力してください。\n";
}
if ($$error_message != "") {
message $$error_message;
} else {
// ダイアログを閉じて戻る
#n = dllfunc("ENDDIALOG");
// グレップを実行
call ExecuteGrepInWsl;
break;
}
// 「カレント」ボタン押下
} else if ($$mode == "10") {
$$current_dir = directory;
$$current_dir = dllfuncstr("GSUB", $$current_dir, "\\", "/", -1);
if (leftstr($$current_dir, 1) != "/") {
$$current_dir = midstr($$current_dir, 2);
}
$$current_dir = dllfuncstr("GSUB", $$current_dir, tolower($DEFAULT_LINUX_PATH_PREFIX), "", 1);
#n = dllfunc("SETCTRLSTRING", "target_directory", $$current_dir);
}
}
return;
//-----------------------------------------------------------------------------
// WSL でのグレップを実行します。
//-----------------------------------------------------------------------------
ExecuteGrepInWsl:
$$command = "";
// 正規表現を使う場合、E オプション
if (val($reg_on)) {
$$command = $$command + "wsl grep -rnE '" + $target_keyword + "'";
} else {
$$command = $$command + "wsl grep -rnF '" + $target_keyword + "'";
}
// 検索するファイルの末尾がカンマでない場合
if (strlen($target_file) && rightstr($target_file, 1) != ",") {
$target_file = $target_file + ",";
}
$$command = $$command + " --include=*.{" + $target_file + "}";
$$command = $$command + " " + dllfuncstr("GSUB", $target_directory, "\\", "/", -1);
if ($path_replace_from != "") {
$$command = $$command + " | sed 's/" + dllfuncstr("GSUB", $path_replace_from, "/", "\\/", -1) + "/" + dllfuncstr("GSUB", $path_replace_to, "\\", "\\\\", -1) + "/'";
}
// :N で表示される行番号を秀丸のグレップ結果と同じ (N) に
$$command = $$command + " | sed 's/\\:\\([0-9]\\+\\)\\:/\\(\\1\\)\\: /g'";
// スラッシュを¥に
$$command = $$command + " | sed 's/\\//\\\\/g;s/\\(.*:\\)/\\1/'";
if ($target_keyword != "" && $target_file != "" && $target_directory != "") {
runex $$command, 1, 0, "", 4, "", 4, "", 0, "", 0, 1, 6;
if (result == 0) {
message "コマンド実行に失敗しました。";
debuginfo $$command;
} else {
// 履歴を保存
call SaveDataToRegistry;
};
}
return;
//-----------------------------------------------------------------------------
// 履歴をレジストリに保存します。
//-----------------------------------------------------------------------------
SaveDataToRegistry:
setsearchhist 0, $target_keyword;
setpathhist 0, $target_directory;
openreg "CURRENTUSER", $REGISTRY_PATH;
// ---------------------------------------------
// 「検索するファイル」
// ---------------------------------------------
$$new_history[0] = $target_file;
##new_history_count = 1;
##i = 0;
while (##i < #HISTORY_SIZE_FILE) {
##unq = yes;
##j = ##i + 1;
while (##j < #HISTORY_SIZE_FILE) {
if ($file_history[##i] == $file_history[##j] || $file_history[##i] == $target_file) {
##unq = no;
break;
}
##j = ##j + 1;
}
if (##unq) {
$$new_history[##new_history_count] = $file_history[##i];
##new_history_count = ##new_history_count + 1;
}
##i = ##i + 1;
}
##i = 0;
while (##i < ##new_history_count) {
$$reg_key = "file" + str(##i);
writeregstr $$reg_key, $$new_history[##i];
##i = ##i + 1;
}
// ---------------------------------------------
// 「検索するディレクトリ」
// ---------------------------------------------
$$new_history[0] = $target_directory;
##new_history_count = 1;
##i = 0;
while (##i < #HISTORY_SIZE_DIRECTORY) {
##unq = yes;
##j = ##i + 1;
while (##j < #HISTORY_SIZE_DIRECTORY) {
if ($directory_history[##i] == $directory_history[##j] || $directory_history[##i] == $target_directory) {
##unq = no;
break;
}
##j = ##j + 1;
}
if (##unq) {
$$new_history[##new_history_count] = $directory_history[##i];
##new_history_count = ##new_history_count + 1;
}
##i = ##i + 1;
}
##i = 0;
while (##i < ##new_history_count) {
$$reg_key = "directory" + str(##i);
writeregstr $$reg_key, $$new_history[##i];
##i = ##i + 1;
}
// ---------------------------------------------
// 結果のパス変更
// ---------------------------------------------
writeregstr "from" , $path_replace_from;
writeregstr "to" , $path_replace_to;
// 正規表現
writeregstr "reg_on", $reg_on;
closereg;
return;
//-----------------------------------------------------------------------------
// マクロ終了処理
//-----------------------------------------------------------------------------
EndProcess:
freedll;
enabledraw;
endmacro;
//-----------------------------------------------------------------------------
// メイン処理実行
//-----------------------------------------------------------------------------
call Main;
@densya203
Copy link
Author

densya203 commented May 10, 2023

おすすめの人

Ruby on Railsの開発をWSL2上のLinuxで行い、かつ秀丸エディタから離れれず、そしてグレップをよく使う中年のおっさん(=私)。

実装の経緯

WSL2上のUbuntuで、ネイティブに配置されたディレクトリ(/mnt/c などではなく、\\wsl.localhost\Ubuntu 配下のext4ファイルシステム)が大きい(60GB程度)場合、そこでのグレップの実行速度が遅くなることがあります。私の環境では、800件のヒットで体感4倍ほど遅くなりました。
サポートフォーラムで聞いてみたものの、実装するよ、というお返事は残念ながらいただけませんでした。

そこで、秀まるおさんの「自分で使うものは、なければ作れ」精神を胸に、このマクロを作ってみました。寿命は短そうですが・・・。

このマクロは、WSL2上でLinuxのgrepコマンドを実行し、その結果を秀丸で(秀丸純正のgrep結果風に)受け取ることができます。

快適にするために

\\\\wsl.localhost\\Ubuntu\\U: などネットワークドライブを当てておくとパスが短くなって何かと捗ります。

実行方法

まず、田楽DLL をダウンロードし、秀丸のexeがあるフォルダに配置してください。
次に、当gistからダウンロードしたzipの中にある GrepInWSL2.mac を、あなたの秀丸マクロフォルダに配置してください。
配置した GrepInWSL2.mac を秀丸で開いて Shift-JIS CR+LF にしてください。
あとは秀丸からマクロの実行をするだけです。

アンインストール方法

設定内容をレジストリに書き込んでいますので、
コンピューター\HKEY_CURRENT_USER\SOFTWARE\Hidemaruo\Hidemaru\densya203-grepinwsl2.mac
を削除してください。

問題点

たまに、WSL (4374) ERROR: CreateProcessParseCommon:789: Failed to translateというエラーが出ることがありますが、未調査です。
検索結果は正しいようです。

謝辞

秀まるおさん
秀丸サポート担当の方
すぎうら まさき さん(田楽DLL開発者の方)
Yusuke Komoriさん(LF-Numberer.mac を勝手に参考にさせていただきました)。
おーなーしぇふさん(z_grep.mac の「Grep検索結果から置換(行単位で置換)」20年ぐらい使ってます。)

スクリーンショット1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment