マクロ用の変数の要望

  1. あけましておめでとうございます
    ちょっと大きめの要望をさせてください。

    マクロを作成していると、時々状態を保存しておきたい機会が出てきます。
    マクロの仕様上、実行ごとに終了するので、マクロ上の変数には状態を保存しておくことができません。
    独自にファイルに保存したり、Mery.iniに書き加えたりする手法もありますが、タブごとに変数保存したい場合などには何らかの工夫が必要ですし、破棄の問題も出てきます。
    Document、Editorインターフェイス(もしかしたらWindowも?)に、ユーザーが保存できる変数があると、マクロのできることがもっと広がるのではないかと思います。

    オブジェクトを保存するのは、なかなか難しいと思いますので、文字列型でも充分と思いますが、複数のマクロから使用されるとなると、文字列変数のディクショナリ型にしてバッティングを回避するのがいいかと思います。

    Editor.ActiveDocument.Tag["MyMacroData"] = "tempdata";
    のように変数保存して、次回実行時に取り出せると便利かな..と
    (Tagプロパティは.Netのコントロールにあるユーザー変数の名前です)
    もちろん、タブが閉じられたときには破棄される前提で構いません。

    私としては、ksさんの「Eclipse風コメントアウト」を改造して使用しているのですが、独自のコメントアウト文字を指定して使いたいのですが、それを記憶させる用途に使用したいと思っています。

    ご検討をお願いします。

     |  pizz  |  返信
  2. 明けましておめでとうございます。

    ご意見ありがとうございます。ユーザが自由に使える変数置き場ですか。Delphi でも Tag プロパティは存在しますし、あれば便利でしょうね。

    Editor や Document ごととなると、仕様上、マクロを実行するたびにこれらは生成・破棄されますので、厳密にそういう実装はできませんが、それっぽく見えるように、であれば出来なくはないかと思います。

    > 文字列変数のディクショナリ型にしてバッティングを回避するのがいいかと思います。

    数値型か文字列型の Tag プロパティを設けるぐらいなら何とかなりそうですが、ディクショナリ型で JavaScript とやり取りするのは情報がまったく見つからず…。私の技術では厳しいかもしれません ^^;

    ご意見は今後の開発の参考にさせていただきたいと思います。

     |  Kuro  |  返信
  3. 追伸:ディクショナリ型より、オブジェクトを保存するほうが簡単でした ^^;

    document.tag = {};
    document.tag["foo"] = "bar";

    みたいな書き方で良ければ実装できる気がします。

     |  Kuro  |  返信
  4. ご検討ありがとうございます。

    > 追伸:ディクショナリ型より、オブジェクトを保存するほうが簡単でした ^^;
    > document.tag = {};
    > document.tag["foo"] = "bar";
    > みたいな書き方で良ければ実装できる気がします。

    初期化を誰がするのか、というところですかねー
    マクロにやらせると、他のマクロのデータを消してしまうので、Mery側で初期化できると嬉しいのですが...
    まぁ、すぐに無ければ困るというものではないので、ゆっくりご検討いただければと思います。

     |  pizz  |  返信
  5. ご返信ありがとうございます。
    そうですね。型なしの tag 変数で初期値は NULL。文字列としてでも数値型としてでも連想配列としてでも自由に使っていただける感じです。(JavaScript の変数と同じ)

    > マクロにやらせると、他のマクロのデータを消してしまうので、Mery側で初期化できると嬉しいのですが...

    それはありますね。マクロ側で if 文で変数が使用中かどうかをチェックしていただく必要が出てきますが、それはディクショナリ型の場合でも同様かと。

    > まぁ、すぐに無ければ困るというものではないので、ゆっくりご検討いただければと思います。

    了解いたしました、現状のところは保留とさせていただきますね。

     |  Kuro  |  返信
  6. すみません、完全に蛇足ですので、そのつもりで読んで下さい。
    仕様については、Kuroさんにおまかせするつもりですが、参考になればと思い。

    わたしとしては、Tagプロパティはreadonlyの(setできない)プロパティにするといいかなと思っていました。(そういう意味ではTagListプロパティのほうが合ってますね)
    目の前にタイプフリーな変数があると、普通の人は自分のことだけ考えてsetしてしまうので、ディクショナリの使用を強制したいのです。
    たとえ、ディクショナリの使用を推奨していても、誰かが上書きしてしまうと、影響を受けた方では解決できない問題になってしまうもので。

    ただし、そうするためにはMery側で初期化するしかないのですが...
    ちなみに、ディクショナリオブジェクトは、COMオブジェクト("Scripting.Dictionary")なので、C系だとCLSIDFromProgID()と、CoCreateInstance()でインスタンス化できると思うのですが、Delphiはわかりません(;_;)

    以上すみません、蛇足でした。

     |  pizz  |  返信
  7. ご返信ありがとうございます。

    > たとえ、ディクショナリの使用を推奨していても、誰かが上書きしてしまうと、影響を受けた方では解決できない問題になってしまうもので。

    なるほど、おっしゃる通りです。tag プロパティが用意されていれば普通は自由に使っちゃいそうなものですね ^^;

    マクロ (のファイル名) ごとにグローバルにする、とか……でも複数のマクロで共通で使いたい場合がダメですか。

    > ちなみに、ディクショナリオブジェクトは、COMオブジェクト("Scripting.Dictionary")なので、C系だとCLSIDFromProgID()と、CoCreateInstance()でインスタンス化できると思うのですが、Delphiはわかりません(;_;)

    アドバイスありがとうございます。
    ヒントをもとに調べてみましたが全然見つかりませんでした… (ノД`)・゜・。
    Delphi は情報が少ないのが欠点ですね。

    サク〇エディタさんのグローバル変数みたいに、SetCookie("スコープ", "名前", "変数") みたいにメソッドとして呼び出す方式であればできるかも……

     |  Kuro  |  返信
  8. テキストエディター「Mery」ベータ版 Ver 3.0.0 を公開...
    https://www.haijin-boys.com/software/mery/mery-3-0-0#14
    > マクロの Window、Editor、Document オブジェクトに Tag プロパティを追加
     
     
    マクロ開発上ものすごく強力かつ便利そうな機能がついに実現されたんですね! XD
    (とかいいつつ、このトピックの立った当時はまだ意味が私自身の理解が追いついておらず、何についてのやりとりなのかすら分かっていませんでしたが)。 LOL
    拙作マクロのいくつかに【include版】と称してマクロの機能をカスタマイズし設定用変数の値をまとめて外部ファイルで読み書きさせていますが、こういったことが Mery 内部で完結する機能としても搭載されたということですよね?

    しかしながら『Microsoft Docs』の「Dictionary オブジェクト」の記事にはスクリプトの例文がほとんどないようなので、私の場合は VBS/VBA がらみの初心者向けリファレンスからサンプルコードをさがしてきて JavaScript の記法に翻訳しないといけないみたいですね。 …ちょっと難しそう。
    https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/dictionary-object

    -----
    現在マクロライブラリに投稿済みの拙作【include版】マクロのばあいはエディタプロセスを再起動しても設定内容を保持しておきたいものがほとんどなので、もしかすると拙作マクロで Tag プロパティを活用できそうなのは「折り返しトグル切り替え」と「すべて選択/選択解除」「位置を復帰/保存」マクロぐらいでしょうか?
    …マルチカーソル範囲選択に対応できる目星がつかない現状では選択範囲の位置情報マクロをいじるのも空しいような。:(

    いずれ pizz さんの「Eclipse風コメントアウト(改) 」マクロや masme さんの「テキスト整形」「行並べ替え」「連番を挿入」マクロがいち早く Tag プロパティを採用するであろうとおもっていまして、それをサンプルコードにさせていただこうかな? などとおもってます(あわよくばマルチカーソル選択範囲への文字列操作の対応方法も)。 :P
    不勉強な上に独創性?もなくて申しわけないですが。

     |  sukemaru  |  返信
  9. Kuroさん
    対応ありがとうございます!
    2年越しで実現していただけるとは!!
    早速、拙作マクロに取り入れてみました。
    従前は苦肉の策でファイル保存していましたが、それらのコードを取り除いてシンプルになりました。

    sukemaruさん
    早速対応してみましたが、Kuroさんのサンプルと大した違いもなく...
    参考にはならないような気がします

     |  pizz  |  返信
  10. >> sukemaru さん

    > マクロ開発上ものすごく強力かつ便利そうな機能がついに実現されたんですね! XD

    何気にこの機能追加はかなり時間 (2 年?) かかりましたね ^^;

    > 設定用変数の値をまとめて外部ファイルで読み書きさせていますが、こういったことが Mery 内部で完結する機能としても搭載されたということですよね?

    そういうことになりますね。先日の、ステータスバーを一時変数置き場にするようなことも不要になるはずです (w

    Dictionary 型は難しそうに思えますが、普通に

    tag("任意の文字列") = 9999;
    

    みたいに使えます。

    これだけだとマクロを実行するたびに上書きされるので意味ないですが、すでにその変数 (キー) が存在していたら上書きしないような処理を加えれば OK です。

    他のマクロと共有される変数なので "任意の文字列" をなるべくユニークなものにしていただくのが良いですね。

    Java のパッケージ名みたいに完全にユニークにするため FQDN みたいな規約を使ったりすると安全かもしれませんが、どういった運用が良いのかまだわかりません。

    >> pizz さん

    ご無沙汰しております。

    > 2年越しで実現していただけるとは!!

    うわ、ほんとだ。2 年も経過してますね…。お待たせしました!

    Delphi 関連の情報がなくて困っていたのですが、たまたま 1 件だけロシア語のサイトに情報を見つけまして何とか実装できました。

    早速、マクロの修正お疲れ様です。tag プロパティ、うまく動いているようで安心しました。

    しかし、Ver 3.0.0 未満のことを考えるとマクロを 2 パターン用意するか Version で分岐するなどで対応しないといけないところが大変そうですね ^^;

    私も、emmet マクロの一部の機能がグローバル変数が使えなくて実装できていなかったのですが、これでようやく対応できそうな気がします。

     |  Kuro  |  返信
  11. すごい、仕事速い! 8)
    ソースコード見ました。 現実のマクロのコードの中で使用されているのを見て、おかげさまで納得できました。
    ありがとうございます。 :D

    キーに変数が使用されていましたので、あの部分で文字列、数値、真偽値、オブジェクトなどを代入すればよいみたいですね。
    Window, Editor, Document オブジェクトで使い分けられるという利点も理解できた気がします。
    ひとつ前のコメントに揚げさせていただいた pizz さんや masme さんのマクロが向いているのだろうなというボンヤリしたイメージしかありませんでしたけど、勘はまちがってなかったと。 :)
    やはり拙作の「検索ジャンプ」「ブックマークジャンプ」「読みなおし」マクロなどは設定内容を半永続的に保持させたいので向いていなさそうですが、「折り返しトグル切り替え」「すべて選択/選択解除」「位置を復帰/保存」マクロあたりでは外部ファイルの読み書きをなくせるメリットがいかせるかもしれませんね。

    なによりも、Prompt() メソッドとの親和性が高そうという感じがヒシヒシと! :o
    「引用の追加」や「カッコで囲う」マクロ内の「任意の文字列...」系コマンドでの Prompt() の初期値で Tag に保存した値を利用すれば、前回指定した文字列を毎回繰り返して入力しなおす手間をナシにできそうですね。
    … 改造・自作をはじめたばかりの頃に作ったマクロなので当時は外部ファイルの読み書きなんて考えもつかなかったですし、Prompt() メソッドの練習用にあとからコマンドを追加しただけみたいなもので自分でもあまり活用していませんでした(たまに使うときは入力する文字列をコピぺしてましたが、置換ダイアログで正規表現を使うほうが履歴に残せるから便利だったという)。 X(

    GetKeyState.exe と連携させるかたちにすれば「インデント/逆インデント」系や「”引用符” の追加/削除」マクロなどにも Prompt() を導入できそうですし、pizz さんに倣ってsukemaru版の「行コメント」マクロも?
    でもこのへんのマクロはパチパチ連打することが多いから、なるべく動作速度を優先したいところ…。

     |  sukemaru  |  返信
  12. ありがとうございます。
    「Dictionary 型」というのをきちんと勉強しないといけないのかとおもってましたが、杞憂だったみたいですね。 :)

    キー名をマクロごとに macroName.keyName で「オブジェクト.プロパティ = 値」形式にするとか、スネークケースで macroName_keyName みたいにしちゃえばひとつのマクロに複数の Tag ? キー? を持たせても大丈夫そうですし、pizz さんのマクロのようにさらに変数に代入しちゃえばコードの記述が間延びしないようにもできますね。
    既存の公開マクロに組み込むとなるとバージョンチェックで処理を分岐させる必用があったりしますが、旧バージョン/正式版の Mery でも IO.js を include している場合には外部ファイルを使っての代替処理もできそうだな、ともイメージできました。

    … あとは、はたして拙作マクロでそこまでやる必要のあるやつがアルのか? という根源的な疑問が。 rofl

    どうせマルチカーソル/矩形選択に対応できるだけのスキルはないのだから、せめて Tag を活用してみせるぐらいはやれよ と言われてしまいそうなので… とりあえず練習がてら「折り返しトグルD」に導入してみました。
    https://www.haijin-boys.com/wiki/折り返しトグル切り替え
    外部ファイルの I/O 処理がなくなりますから、これで高速で連打しても大丈夫になるかもしれません。 LOL

    > 先日の、ステータスバーを一時変数置き場にするようなことも不要になるはずです (w
    これが今バージョンでの実装の直接的なきっかけだったのでは? なんて。 :D

     |  sukemaru  |  返信
  13. 実はこっそり期待してました
    早速、ツールバーのアイコンのサイズを切り替えるマクロを作ってみましたが、問題なく動作します。

    const Is_S = (1<<0);	// 小
    const Is_M = (1<<1);	// 中
    const Is_L = (1<<2);	// 大
    const Is_X = (1<<3);	// 特大
    const Msk = Is_S | Is_M | Is_L | Is_X;	// マスク用
    // 設定
    var df = Is_M;	// デフォルト値 小・中・大・特大から1つ設定
    var chk = Is_S | Is_M | Is_L | Is_X;	// 小・中・大・特大で切替
    // var chk = Is_M | Is_L;	// 中・大で切替
    
    var is = df;	// アイコンサイズ
    if(window.tag.exists("iconSize")){
    	is = window.tag("iconSize");
    }
    var i = 0;
    while(i < 4){
    	is <<= 1;
    	if((is & Msk) == 0)	is = Is_S;
    	if((is & chk) != 0)	break;
    	i++;
    }
    switch(is){
    	case Is_S:	editor.ExecuteCommandByID(2228); break;
    	case Is_M:	editor.ExecuteCommandByID(2229); break;
    	case Is_L:	editor.ExecuteCommandByID(2230); break;
    	case Is_X:	editor.ExecuteCommandByID(2231); break;
    	default:	is = Is_M;	break;
    }
    window.tag("iconSize") = is;
    

    でもこのマクロは需要無いかな……もし良かったら使ってみて下さい

     |  シリル  |  返信
  14. >> sukemaru さん

    > 外部ファイルの I/O 処理がなくなりますから、これで高速で連打しても大丈夫になるかもしれません。 LOL

    これはイイですね。確か以前に、ファイル経由だから連打したら遅延が、とかの話題もあった気がしますが、そういった問題は改善されそうですね。

    > > 先日の、ステータスバーを一時変数置き場にするようなことも不要になるはずです (w
    > これが今バージョンでの実装の直接的なきっかけだったのでは? なんて。 :D

    そうなんですよね…

    っていうのは冗談で、実はその時点ですでに Tag プロパティ実装済みだったので非常に悔しい思いをしました (w

    >> シリル さん

    > 実はこっそり期待してました

    さすがです…。

    > でもこのマクロは需要無いかな……もし良かったら使ってみて下さい

    何に使うのだろうと思いつつも使わせていただきました。

    ワーイ、たーのしー!

    特大アイコンなんて 1 度も使ったことがなかったのですが、なんだか Windows 95 時代のソフトみたいでアリですね。

     |  Kuro  |  返信
  15. (いまさらですが)た~のし~。 XD
    おもしろいので『小マクロ集』に加えさせていただこうかなとおもっていたのですが、アイコン化したばあい実行ごとにアイコンの位置(デスクトップ上の座標)も変化してしまうため、トグル系マクロならではの「連打」の醍醐味を味わえなくなってしまうようですね... (アイコンを高速連打できるだけの反射神経や動体視力がありませんので)。
    いや、むしろシューティングゲーム感覚ですばやくターゲットのアイコンをエイムしてクリックできる人ならもっと楽しいのかしら? :)

    … いまのところアイコンのデザインもおもいつかないので、4 in 1 トグル専用の「アイコンサイズのトグル切り替え」簡易版をここにこっそりと置かせていただきます。
    ツールバーアイコンのサイズは各エディタウインドウ別の設定のようですので Tag の親オブジェクトを Editor にしました(折り返しのほうこそ全エディタウインドウ共通の設定のようで、Window.Tag にするべきでした)。

    /*
      #title="アイコンサイズのトグル切り替え"
      #tooltip="アイコンサイズ切り替え 4 in 1 トグル: 小/中/大/特大"
      ※ 動作要件:Mery 3.0.0 以上
      ※ Mery.exe 再起動後の初回実行時はつねに「中アイコン」になります
     */
    
    var id = (editor.tag.Exists("iconSize")) ? editor.tag("iconSize") : 2228;
    editor.ExecuteCommandByID(id += (id == 2231) ? -3 : 1);
    editor.tag("iconSize") = id;
    
    // Status = ( (id == 2228) ? "小"  : (id == 2229) ? "中"
    //          : (id == 2230) ? "大"  :/*id == 2231*/ "特大" ) + "アイコン";
    

    私の場合、既存のテスト用マクロ「TEST.js」ファイル上で、ふだんは3行まとめてコメントアウト、各サイズのアイコンの見映えの確認をしたいときだけアンコメントしてショートカットキーでポチポチ実行するのが合っているみたいです。

     |  sukemaru  |  返信
スポンサーリンク