PerlでEmEditorマクロを書こう B!

Songmuと申します。皆様初めまして。好きな言語はPerlと中国語だと公言しています。ただ、よく間違えられますが私も両親も日本人です。

よろしくお願いします。

さて、今年はやたらVimヴィム言われた年であったように感じます。また、Web開発者のMac移行がより進んだ年であったようにも思いますが、ここで空気を読まずEmEditorの話をします。

EmEditorとは?

Windows専用のテキストエディタであり、性能的には秀丸に比肩する能力を備えています。ただ、コミュニティの差なのか、秀丸に比べるとイマイチマイナーです。秀丸がWindowsテキストエディタ界におけるPerlだとしたら、EmEditorはRubyのような存在といえるでしょう(?)

EmEditorの特長

個人的に優れていると思う点をあげてみます。

  • Perl互換の正規表現での検索(秀丸に存在しない\b等も使える)
  • 中国語もGrepで引っ掛けられる
  • CSV, TSV表示機能がある(Ver.9以降)
  • Perlでマクロが書ける

今回は、Perlマクロに関して取り上げます。JScriptで書かれることが多いみたいなのですが、Perlで書けるという事はCPAN使い放題なので、複雑な事も簡単に実現可能なのです。

マクロで何が出来るのか?

百聞は一見にしかずということでまずは以下をご覧下さい。

TwitterTLを表示する
http://songmu.jp/riji/img/emtwit.jpg
選択範囲内の文字列をPerlコードとして実行・出力する
http://songmu.jp/riji/img/emcode.jpg

こんな感じのことができます。上記のように、個人的には

  • 選択範囲のテキストを加工したりどこかに送ったり
  • 何らかの出力をアウトプットバー(画面の下半分の箇所)に出す

といったことにマクロを活用しています。

作成方法

とりあえず簡単に。

  • メニューから[マクロ] -> [カスタマイズ] -> [マイマクロ]タブで[新規作成]を押してファイルを作成
  • ファイルの拡張子は.pleeにする

書き出し

以下の通りです。

#language="PerlScript"
our $Window;
 
use strict;
use warnings;
use utf8;

普通のPerlスクリプトとはshebang行の書き方が異なります。$Windowオブジェクトは既にEmEditorマクロ内で定義されているオブジェクトですが、use strictで書く場合は、ourで宣言しておかないと怒られます。

この$Windowオブジェクトを操作することがEmEditorマクロの肝となります。

$Windowオブジェクトについて

EmEditorを弄る上で必要な、多種多様なメソッド・プロパティがぶら下がっています。オブジェクトの仕様に関しては、EmEditorのヘルプに詳細に書かれているので、そちらを参照すると良いでしょう。

ちなみに、EmEditorマクロはもともとVBScriptやJScriptで書かれることを想定しているので、Perlでメソッドやプロパティアクセスをしようとすると多少戸惑う部分があります。

Perlマクロの場合、プロパティアクセスもメソッド呼び出しも、メソッド呼び出しとして記述することが出来ますが、プロパティに値をセットするときには、オブジェクトの実体であるハッシュリファレンスの中を覗かないといけません。

また、真理値をセットする場合には、真を1、偽を0としてセットします。

// JScriptの場合
// アウトプットバーの内容を消す
Window.OutputBar.Clear();
// アウトプットバー非表示の場合、表示する
if ( !Window.OutputBar.visible ){
    Window.OutputBar.visible = true;
}
// アウトプットバーに'hoge'と表示する
Window.OutputBar.writeln('hoge');
# Perlの場合
# アウトプットバーの表示を消す
$Window->OutputBar->Clear;
# アウトプットバー非表示の場合、表示する
$Window->OutputBar->{'visible'} = 1     # ハッシュの中を覗く
    unless $Window->OutputBar->visible; # getterとしては使用可能
# アウトプットバーに'hoge'と表示する
$Window->OutputBar->writeln('hoge');

多分AUTOLOADを使って、メソッドが存在しない場合は、ハッシュエントリーを見に行くようにしているのでしょう。getterとして使用可能なら、$Window->OutputBar->visible(1) とかして、setterとしても使用可能でも良さそうなもんですが、それは出来ないようです。

ちなみに、毎回$Window->...とか書くのがめんどくさかったりする場合は、オブジェクトにアクセスするメソッドはオブジェクト参照を返すので、以下のように書くことが出来ます。当たり前ですが。

my $out_bar = $Window->OutputBar; # $out_barにOutputBarオブジェクトが入る
$out_bar->Clear;
...

選択文字列(selectionオブジェクト)について

プロパティアクセスの説明とともにOutputBarオブジェクトの説明も済ませてしまったので、次はselectionオブジェクトの説明をします。

selectionオブジェクトには、編集中のテキスト内の選択文字列の情報が入ります。OutputBarがマクロにおける出力部分だとしたら、selectionは入力の部分を担います。

以下のようにして選択文字列を取得することが出来ます。

my $code = Encode::decode(
    'cp932',
    $Window->document->selection->Text
);

cp932でデコードしています。日本語Windowsを使っている場合、selection->Textには必ずcp932文字列が入ってしまいす。たとえ、UTF-8のファイルを編集中であっても、その選択文字列は自動的にcp932文字列に変換されてselection->Textに入ってしまうのです。同様に、OutputBarに出力するときもcp932にエンコードしてやらなくてはいけません。

ロケールの問題なのか理由は定かではありませんが、これは非常に困ります。中国語(cp932範囲外の文字)が使えません。

ちなみに、JScriptでマクロを記述する場合には、スクリプトをUTF-8で記述し、BOMをつける事によって、UTF-8をそのまま扱うことが出来ます。つまり、OutputBarに中国語表示が可能です。この点はJScriptの方が優れています。悔しいです。

// JScriptだとUTF-8(BOM付き)で保存すると中国語が表示できる!!!
Window.OutputBar.writeln('你好');

これに関して解決策をご存じの方は、y.songmu at gmail.comまでお知らせ下さい。非常に困っています。

マクロの実例(実践編)

気を取り直して、冒頭でも実行例を表示した、選択文字列をPerlコードとして実行するマクロを記載します。

これは簡単な計算をさせたり、正規表現のチェックをしたりとかなり重宝しています。

至極単純な話で、選択範囲をevalすれば良いだけの話なんですが、print, say文での出力をアウトプットバーに出したいため、IO::Captureモジュールを使って、捕捉した標準(エラー)?出力をアウトプットバーに出力しています。

IO::Captureモジュールはprint文が書かれてもその内容をすぐに出力せず、バッファしておくことができる、非常に便利なモジュールです。(一応モジュールの紹介もしておかないと)

#language="PerlScript"
our $Window;
use strict;
use warnings;
use utf8;
use Encode;
 
use Win32; # ダイアログ表示の為に使用
use IO::Capture::Stdout;
use IO::Capture::Stderr;
 
# 選択範囲のテキストを取得する
my $code = Encode::decode(
    'cp932',
    $Window->document->selection->Text
);
# 中身が空だったり、キャンセルされたら実行しない
exit unless $code;
# 実際はダイアログ表示させて無いんだけど、
# Win32モジュールを使う事も多いので合わせて紹介
exit if Win32::MsgBox('run?', 1) != 1;
 
# 標準(エラー)?出力の捕捉を開始する
my $capture = IO::Capture::Stdout->new;
my $stderr = IO::Capture::Stderr->new;
$capture->start;
$stderr->start;
 
# eval実行する
eval $code;
 
# 捕捉を終了する
$capture->stop;
$stderr->stop;
 
# 結果を出力する前にアウトプットバーの中身をクリアした後、表示
$Window->OutputBar->Clear;
$Window->OutputBar->{'visible'} = 1;

# 標準エラー出力を表示する
# readメソッドは捕捉した順番に出力内容をリストで返してくる
# 表示の際にはcp932でエンコードする
$Window->OutputBar->writeln(
    join "", map { Encode::encode('cp932', $_) } $stderr->read
);
 
$Window->OutputBar->writeln('---');
 
# 標準出力を表示する
$Window->OutputBar->writeln(
    join "", map { Encode::encode('cp932', $_) } $capture->read
);

マクロの実行について

マクロメニューやマクロツールバーからマウスクリックで実行することも出来ますが、よく使うマクロにはショートカットキーを割り当てておくと良いでしょう。私も先程のPerlコード実行マクロには Ctrl+P を割り当てています。

また、メニューを「メニューの変更」から拡張することができます。メニューには Alt+任意のキー でアクセス可能なので、そこからマクロを呼び出したり、階層構造で管理をしたりすることも可能です。Perlの話から逸れるのでここでは多くは書きません。

マクロの使い所

さて、ここまで読んできた方でEmEditor使いの方はもう、マクロをバリバリ書けるようになっていることでしょう。今後どう言ったマクロを書けば良いか、参考までに私が実際に作ったマクロの例を挙げます。

  • Twitterに投稿する(と同時にOutputzにも送信する)
  • 手元のメモをメールで携帯に送る
  • コード(SQL等)を整形する

等々です。外部プログラムとの連携も出来るので、頑張ればiTunesからプレイリストを拾ってきてコンテキストメニューに表示して選択したりなんかもできるようになるみたいです。

皆様も是非、Perlマクロを作ってみて下さい。便利だったら公開してみて下さい。

まとめ

EmEditorでのPerlマクロ開発について駆け足で説明しました。マクロだけじゃなく、正規表現での一括置換なんかも強力なので、WindowでPerlを書くならEmEditorを是非オススメします。

質問、感想、意見なんかは、y.songmu at gmail.com まで連絡くださると嬉しいです。TwitterID: songmu なのでそちら宛につぶやいてくださっても喜びます。

明日はoverlastさんです。お楽しみに!