秀丸エディタ×外部コマンド連携マクロ(選択テキストをPowerShell/Pythonに渡して戻す)

秀丸は単体でも十分強い。
でも「外部コマンド連携」を入れると、ガチで別物になる。

やりたいことは単純。

  1. 秀丸でテキストを 選択
  2. その選択を PowerShell / Python標準入力で渡す
  3. 外部コマンドが加工した結果(標準出力)を 秀丸へ戻して置換

これだけで、秀丸が「無限に拡張できるテキスト加工フロント」になる。


これで何が嬉しい?

例えば、こんなのが“一撃”になる。

  • JSON整形/minify
  • CSV/TSVの列加工
  • 文字コード変換(外部ツール任せ)
  • 大量の正規表現処理(Python任せ)
  • ログ抽出/整形
  • Base64 encode/decode
  • 連番付与、重複行削除、自然順ソート…etc

要するに「秀丸だけだと面倒」な処理を、外部に投げて戻すだけ。


まずは仕組み(超重要)

秀丸マクロには、外部コマンドを柔軟に叩ける runex がある。

この runex の肝がこれ:

  • 標準入力:選択範囲を渡せる
  • 標準出力:選択範囲を置換できる
  • エンコードも指定できる(UTF-8が使える)

つまり「フィルタ」みたいに使える。


準備(3分)

1) PowerShell か Python を用意

  • PowerShell:Windows標準でも動く(5.1)
    ただし、安定運用なら PowerShell 7(pwsh)おすすめ
  • Python:入ってるならそれでOK

2) マクロ置き場に「filters」フォルダ作る(おすすめ)

例:

C:\Users\あなた\Documents\HidemaruMacros\
  ext_filter.mac
  filters\
    hm_filter.ps1
    hm_filter.py

外部側:フィルタのサンプル(PowerShell / Python)

PowerShell(例:行末空白削除+空行削除)

ファイル名:filters\hm_filter.ps1

# stdin を全部読む
[Console]::InputEncoding  = [System.Text.UTF8Encoding]::new($false)
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)

$text = [Console]::In.ReadToEnd()

# 例:行末空白削除 + 空行を詰める
$lines = $text -split "`r?`n" |
  ForEach-Object { $_ -replace "[ \t]+$", "" } |
  Where-Object { $_ -ne "" }

# stdout へ返す(LFで返す。秀丸側で必要なら改行統一すりゃいい)
$lines -join "`n"

Python(例:同じ処理)

ファイル名:filters\hm_filter.py

from __future__ import annotations
import sys
import re

def main() -> None:
    data = sys.stdin.read()

    # 行末空白削除 + 空行削除
    out_lines: list[str] = []
    for line in re.split(r"\r?\n", data):
        line = re.sub(r"[ \t]+$", "", line)
        if line != "":
            out_lines.append(line)

    sys.stdout.write("\n".join(out_lines))

if __name__ == "__main__":
    main()

ここは“例”だから、用途に合わせて中身だけ差し替えていけばOK。


本丸:秀丸マクロ(選択→外部→戻す)

ファイル名:ext_filter.mac

ポイント:

  • 選択して実行が基本
  • 選択が無いなら 全文選択して実行(安全)
  • UTF-8で受け渡し
  • コマンド内で % を使う可能性があるから、拡張フラグ=1で事故防止(重要)
/*
  ext_filter.mac
  選択範囲(無ければ全文)を外部コマンドに渡して、stdoutで置換する。

  使い方:
    - 選択して実行(推奨)
    - 選択なしでも実行OK(全文を対象にする)

  事前準備:
    - filters\hm_filter.ps1 または hm_filter.py を用意
*/

#mode = val(input("外部フィルタ: 1=PowerShell / 2=Python", "1"));

if (!selecting) {
    // 選択が無いなら全文を対象にする
    selectall;
}

// 実行するコマンドライン(必要ならパスを直せ)
$cmd = "";

// PowerShell 7 (pwsh) 推奨。無ければ powershell.exe に変えてもいい
if (#mode == 1) {
    $cmd = "pwsh.exe -NoProfile -ExecutionPolicy Bypass -File \"" + macrodir + "\\filters\\hm_filter.ps1\"";
}

// Python のパスが通ってないなら python.exe のフルパスにする
if (#mode == 2) {
    $cmd = "python.exe \"" + macrodir + "\\filters\\hm_filter.py\"";
}

if ($cmd == "") {
    message "mode error";
    endmacro;
}

// runex:選択を stdin に流して、stdout で選択を置換
// 文字コードはUTF-8(6)にしておくのが一番揉めにくい
runex $cmd
, 1        // sync   0:async, 1:sync(終わるまで待つ)
, 5, ""    // stdin  5:selection
, 6, ""    // stdout 6:replace selection
, 7, ""    // stderr 7:output pane(エラーは出力枠に逃がす)
, 1, ""    // folder 1:current(必要なら2:specifyでmacrodir等)
, 0        // show   0:auto
, 1        // draw   1:no draw(リダイレクト中の描画抑制で高速)
, 6        // encode 6:utf-8
, 1        // ext    1=% の解釈を抑制(事故防止)
;

if (!result) {
    message "外部コマンド実行に失敗した。パスとコマンドを見直せ。";
    endmacro;
}

message "外部フィルタ完了";

使い方(最短)

  1. 加工したい範囲を選択
  2. マクロ実行
  3. 1=PowerShell か 2=Python を選ぶ
  4. 選択範囲が加工結果に置換される

ここが強い(運用のコツ)

コツ1:フィルタを増やすと世界が変わる

filters\ にスクリプトを増やして、マクロ側を「メニュー化」すると最強。

例:

  • json_pretty.py
  • sort_unique.py
  • extract_ips.ps1
  • base64_decode.py

コツ2:エラーは「出力枠」に逃がす

stdoutは置換に使ってるから、エラー(stderr)を混ぜると文章が壊れる。
だから stderr は出力枠へ(このマクロはそうしてる)。

コツ3:文字化けしたら「UTF-8固定」で殴る

runex側のエンコードをUTF-8にして、外部スクリプト側もUTF-8で入出力を固定。
これが一番揉めない。


よくある詰まりポイント

Q. pwsh.exe が見つからない

PowerShell 7が入ってないか、PATHが通ってない。
その場合は一旦 powershell.exe に変えて動作確認してもいい。

Q. python.exe が見つからない

PythonのPATHが無い。python.exe をフルパスにするか、pyランチャー使う。

Q. 何も置換されない / resultが失敗

  • コマンドラインの引用符(”)が崩れてる
  • スクリプトのパスが違う
  • 外部側が標準出力に何も出してない(print忘れ)

まとめ:秀丸を「最強のフロント」にする方法

外部コマンド連携は、要するに「秀丸を入力UIにして、処理は外に投げる」って発想だ。
一度作ると、もう戻れない。

コメント

タイトルとURLをコピーしました