3つのHidemaru本体への関数追加要望No.10721
こみやんま さん 22/03/25 18:50
 
とくに差し迫って何かを実装してほしい、といったようなことではないのですが、
以下、「あったほうがいいんでないか?」くらいの提案です。


-----------------------------------------------------
その@
-----------------------------------------------------

C/C++/C#からマクロとやりとりする最の実装の敷居がぐんと
下がるのではないかと思うもの。

今でもできはしますが、
やはりC++と秀丸マクロ上の値のやりとりをC++だけで「1から実装する」のには相当
にトリッキーな実装を必要とするはずです。
(C#とCOMでも同じぐらいトリッキーで通常なら実装を断念しかねない)

(https://www.nuget.org/packages/HmCppInvoke-vs2022/2.1.0.1 みたいなものをト
リッキーな実装せず普通に実装しやすい
ようにしましょうという提案)



■現在実行中の秀丸マクロ空間のグローバル変数に指定の値を代入する.
 (★マクロ実行中のみ実行可能)

 ようするに「C++→秀丸マクロ」への伝達を簡潔に。
 後述する「評価値を得る」との対の関係で使えるのであると理想的

 現行のEvalでも文字列加工でなんとかなるので最悪はなくてもよいですが、実際や
ってみるとわかりますが、
 特に変数が文字列の場合にC++でRつかいつつ、その文字列の中で、秀丸マクロのR
も使うという実装になりやすい...


  union TDYNAMICVARIABLE {
    BYTE dynamic_byte[16];  // 128bit一応確保しておくだけ。ポインタ渡しでは
なくTDYNAMICVARIABLEの値渡しで実装したものがdllになっちゃってるみたいな状況
でも耐久力があるように。
    intptr_t nValue;        // 秀丸整数用 32bit/64bit
    wchar_t* pwszStr;       // 秀丸文字列用 本体関数はwchar*ベース
    double fValue;          // 秀丸浮動小数用
  };

  // TDYNAMICVARIABLE のいわばどれに値を格納してるのか、どのタイプなのかの伝達
  enum TDYNAMICVARIABLE_Type {
      TypeNativeInt = (1 << 0),
      TypeString    = (1 << 2),
      TypeDouble    = (1 << 3),
  }

  // pwszGlobalUserVariableName       : "#abc" や "$bbb"などといったユーザー
定義変数名。"##や$$は一時空間用なので使えない"
  // pNewValue                        : 設定する値。
  // ValueType                        : TDYNAMICVARIABLE型のどれに値を格納し
たのかの伝達(とともに型伝達でもある)
 BOOL WINAPI Hideamru_SetGlobalMacroVariable(const wchar_t *pwszGlobalUserV
ariableName, TDYNAMICVARIABLE *pNewValue, TDYNAMICVARIABLEType ValueType);

 使用例:

     TDYNAMICVARIABLE dynamicValue;
     dynamicValue.nValue = 3;
     BOOL Hideamru_SetGlobalMacroVariable( L"#abc", &dynamicValue, TypeNativ
eInt );

     wstring abc = L"あいうえお";
     TDYNAMICVARIABLE dynamicValue;
     dynamicValue.pwszStr = (wchar_t*)abc.data();
     BOOL Hideamru_SetGlobalMacroVariable( L"#abc", &dynamicValue, TypeStrin
g );

[ ]
RE:10721 3つのHidemaru本体への関数追加No.10722
こみやんま さん 22/03/25 18:52
 
最後の #abc は $abc です。

[ ]
RE:10722 3つのHidemaru本体への関数追加No.10723
こみやんま さん 22/03/25 18:54
 
------------------------------------------------
A
------------------------------------------------

対になる関数となります。
そしてこちらの方が要望としてはおそらく高いかと。

■マクロ空間上で「値としてのExpression」をしてC++側に持ってくる。
 ようするに「秀丸マクロ→C++」への伝達


  union TDYNAMICVARIABLE {
    BYTE dynamic_byte[16];  // 128bit一応確保しておくだけ。ポインタ渡しでは
なくTDYNAMICVARIABLEの値渡しで実装したものがdllになっちゃってるみたいな状況
でも耐久力があるように。
    intptr_t nValue;        // 秀丸整数用 32bit/64bit
    wchar_t* pwszStr;       // 秀丸文字列用 本体関数はwchar*ベース
    double fValue;          // 秀丸浮動小数用
  };

  flags:
      const int TypeAuto      = 0; // 指定するまでもない時使用。ほとんどの関
数は関数自体が返す型(数値型or文字列型)が決定しているため、指定するまでもない
      const int TypeNativeInt = (1 << 0);
      const int TypeString    = (1 << 2);
      const int TypeDouble    = (1 << 3);

 
  // pwszExpression       : 簡単に言えば、代入式( A = B; )の「B」に書ける評
価式文字列。
  //                        複数の式文は認められない。(ようするに「;」があっ
てはダメ)
  //                        "val(sprintf("%d", lineno))" などは大丈夫。
  // pExprResult          : pwszExpressionを実行した結果の値。(TDYNAMICVARIA
BLE ではなく TDYNAMICVARIABLE*経由にしておいてもいいかも)
  // pResultCastType      : 秀丸は「この型」だと(想定して)値を ExprResult へ
と格納しましたよ、解釈側はその型で解釈してね、という情報。
  // 返り値               : そもそも評価成功したか。FALSEとTRUE
 BOOL WINAPI Hideamru_ExpressionMacro(const wchar_t *pwszExpression, TDYNAM
ICVARIABLE *pExprResult, TType* pDstResultCastType );


 使用例:

      int dstResultCastType = 0;
    auto success = Hideamru_ExpressionMacro( L"lineno", &dstResultCastType);
      if ( dstResultCastType == TypeNativeInt ) {
          intptr_t lineno = pExprResult->nValue;
          //...
      } else if ( dstResultCastType == TypeDouble )
          double lineno = pExprResult->fValue;
          //...
      }


      auto success = Hideamru_ExpressionMacro( L"val(sprintf("%d", lineno))",
 &dstResultCastType);
      if ( dstResultCastType == TypeNativeInt ) {
          intptr_t lineno = pExprResult->nValue;
          //...
      } else if ( dstResultCastType == TypeDouble )
          double lineno = pExprResult->fValue;
          //...
      }

      auto success = Hideamru_ExpressionMacro( L"$uservar", &dstResultCastTy
pe);
      if ( dstResultCastType == TypeString ) {
          std::wstring date = pExprResult->pwszStr;
      }

      auto success = Hideamru_ExpressionMacro( L"$uservar[3]", &dstResultCas
tType);
      if ( dstResultCastType == TypeString ) {
          std::wstring date = pExprResult->pwszStr;
      }


  memberやgetconfigはEvalMacroで(衝突しない)ユーザー変数に一度入れたあと、Hi
deamru_ExpressionMacro で取り出せばいいかなと。


[ ]
RE:10723 3つのHidemaru本体への関数追加No.10724
こみやんま さん 22/03/25 18:57
 
dstResultCastType == TypeDouble

みたいに == で判定してるところは、& の間違いです。

[ ]
RE:10724 3つのHidemaru本体への関数追加No.10725
こみやんま さん 22/03/25 19:01
 
-------------------------------------------------------
B
-------------------------------------------------------

(この要望は一般的には少ないと思いますが、個人的には一番欲しい機能ですw)

■秀丸の定義済みのシンボルの種別を取得できるような秀丸本体関数
 (マクロ実行中でなくとも判定可能ならベスト)

  ・例
  "sprintf" → 関数
  "message" → 関数と文  両方
  "x"       → キーワード
  "result"  → キーワード
  "if"     → 制御文

 (秀丸本体の内部的にすでに種別が引き出しやすい形で管理されているようなら、
上のような情報が取得できる関数がほしいといったところです)
 (マクロは「実行前の文法チェックの際」に、キーワード/関数/式 がチェックさ
れているので、
  多分上記内容が引き出しやすい形で管理されているものと思っています)

  flags:
    const int TypeUnknown = 0;
    const int TypeFunction = (1 << 0);
    const int TypeStatement = (1 << 1);
    const int TypeKeyword = (1 << 2);
    const int TypeControlStatement = (1 << 3);

   // 関数も文もあるみたいなのがあるため、排他ではない

   TBymbolType st = Hidemaru_GetMacroSymbolType("message");
   if (st & TypeFunction > 0) {
      // すくなくともそのような関数があると判断
   }
   if (st & TypeStatement > 0) {
      // すくなくともそのような文があると判断
   }


  こんなことを知って判定で何ができるようになるかというと、
  明示せずとも暗黙な分岐ができるようになります。

  例えば、今は、
  Hm.Macro.Var.lineno
  Hm.Macro.Function.sprintf(...)
   Hm.Macro.Statement.moveto(...)

  などと「キーワード」「関数」「文」のどれなのか
  (シンボルだけではキーワードなのか文なのか自動判定できないため)
  明示的に記述する必要があるところを、
  

  Hm.Macro.lineno
   Hm.Macro.sprintf(...)
  Hm.Macro.moveto(...)

  といったようなことが出来るように吸収できます。
 
----------------------------------------------------------------------------
---------------

[ ]
RE:10724 3つのHidemaru本体への関数追加No.10726
こみやんま さん 22/03/25 22:39
 
※1 TDYNAMICVARIABLE * は 実際はvoid* の方がいいかもしれません。
(数値型とwchar_tの時にデリファレンスするしないで揺れてしまうのをとるか、
  void *という単純な型になっているのを取るか)

※2 話を単純化するため std::wstring date = pExprResult->pwszStr; などと記載
していますが、
    実際には、秀丸本体側で確保したメモリを、使用者側で解放する必要性がでるの
で、
    ほぼ確実に既存の文字列取得関数同様「GlobalLock, GlobalUnlock, GlobalFre
e」といった手順となることでしょう。

[ ]
RE:10726 3つのHidemaru本体への関数追加No.10727
秀丸担当 さん 22/03/28 15:54
 
いろいろご提案ありがとうございます。
確かにDLL側からは情報を取得したりするのは面倒だと思います。
Hidemaru_EvalMacroを使う場合では、変数の設定は手間なだけですが、情報の取得は
遠回りして得る方法を工夫しないといけないです。
なので、この中では2のHideamru_ExpressionMacroのようなことができたらいいとは
思います。
とはいえ、仕様がごっそり増えるのもそれ自体が難解という気がします。

あるいはHidemaru_GetStaticVariableのようなものがあれば、setstaticvariableし
たものを取得できて、仕様も文字列固定でシンプルでいいかもしれません。

[ ]
RE:10727 3つのHidemaru本体への関数追加No.10728
こみやんま さん 22/03/28 19:48
 
>あるいはHidemaru_GetStaticVariableのようなものがあれば、setstaticvariableし
>たものを取得できて、仕様も文字列固定でシンプルでいいかもしれません。

静的変数(内部実装としては共用メモリだとは思いますが)、秀丸のデフォルトだと
制限が大きいので
その上に乗せて汎用目的のAPIをラップして作っていくというのは敬遠してしまうの
ではないかと思います。

理由としては
・通常のマクロ変数なら実行の度に(たとえ実行中断などによる形になっても)確保
されたマクロ変数はクリアされるのに対して、
 静的変数はクリアされません(クリアされないことが存在意義でもありますが)。
 マクロが終わるとクリアするオプションはありますがクリアされないものと同じ部
屋の中という制限を受けることにはなります。

 他者マクロのクリアミス、あるいは静的変数への一時確保したものを実行中断など
が原因で未クリアなままにされているなど、
 どんどん蓄積ゴミがたまり、やがて上限に達して(原因があるとも思えないような
段階で)実行不可能になる可能性があります。
 (64のデフォルトだと未クリアだとけっこうあえなく上限になることでしょう)

・静的変数の上限は設定で大きくできますが、大きくしてる人はほとんど居ないと推
察します

・一方で静的変数取得の関数がいいところとしては、
 クリアしないという性質は、マクロ実行の間のみ取得という制限から解放され、dl
lを常駐タイプにした場合と親和性があることです。
 「マクロ実行中に限らずいつでも、どのプロセスからでも」値を引き出せるという
とても大きなメリットがあります。
 但し、この場合、staticvariableへのgetとset両方をネイティブ関数として提供す
るのが適切かと思います。
 (getだけ提供すると、getはマクロが走らないが、setはEVALMACROもしくはEXECMAC
RO_MEMORYなどでマクロを走らせないと設定できないという非対称になってしまうため)

・総合的には静的変数に制限するよりもAで説明したものの方が応用範囲がかなり広
いかと思います。
 (性質が違うため比べにくいですが)

(マクロ実行中のみ実行可能)
size_t nExprVariableByteSize = WINAPI Hideamru_ExpressionMacro(const wchar_t
 *pwszExpression, void *pExprVariableBuffer, int* pExprVariableTypeBuffer);

   pwszExpression          : 簡単に言えば、代入式( A = B; )の「B」に書ける評
価式文字列。
                             複数の式文は認められない。(ようするに「;」があ
ってはダメ)
                            "val(sprintf("%d", lineno))" などは大丈夫。
   pExprVariableBuffer     : 数値型なら、「int num; → &numで受け取り」, 「w
char_t* pwstr;→ pwstrで受け取り」
   pExprVariableTypeBuffer : 秀丸は「この型」だと(想定して)値を (*pExprVaria
bleBuffer) へと格納しましたよ、解釈側はその型で解釈してね、という情報
                             「int nType → &nType」などとして受け取り。int,
 double, wchar_t*, other, などを意味する値を受け取る。
   nExprVariableByteSize   : (*pExprVariableBuffer) は何バイトのデータなのか。
0ならそもそも実行に失敗している。
                            将来バイト列を渡したいといった要望が出た場合など
に備えて。
                            基本的には文字列と同じような取得方法となるが、サ
イズがわかっていれば、NULL終端以外のデータでも取れるようになる。


あるいは
(いつでも実行可能)
BOOL succcess = WINAPI Hidemaru_SetStaticVariable( const wchar_t *pwszVariav
leName, const wchar_t *pwszStringValue, int nCommonParam );
// successに失敗している
HGLOBAL memoryhandle = WINAPI Hidemaru_GetStaticVariable( const wchar_t *pws
zVariavleName );
// handleが0は取得自体に失敗しているか、対象のpwszVariavleName自体が無い (秀
丸の静的変数って、値が空文字だとどういう扱いなんですかね? マクロ変数は0や""
は変数未定義と同じ扱いっぽいですが)

---------------------------------------------------------------
いずれにしても、かなりニッチですし、
現行のWindowsにおける主要言語に対してはマクロと言語空間のやりとりには困らな
いようなものは、
(ロックしてないことによるアンセーフに目をつぶれた)
提供できてるんではないかとは思っていますので、
気が向いたらくらいでよいかとおもいます。



[ ]
RE:10728 3つのHidemaru本体への関数追加No.10730
秀丸担当 さん 22/03/29 09:13
 
setstaticvariableは、たまたまですが第3パラメータに-1を指定できるような追加
が最近ありました。
これはstaticというよりvolatileですが、サイズの制約が無く、そのマクロだけで有
効で、マクロが終わったら消えるので競合の心配もないです。
なので狙ったわけではなかったですが、今回の使い方に向いていると思います。

従来の0,1,2に相当する使い方も、それはそれで別の用途として使えると思います。
対にするためにHidemaru_SetStaticVariableもあったらいいかもしれないです。

その手法があったとして見つけられないかもしれないので、ヘルプの「DLL側から秀
丸エディタの関数呼び出し」のところに設定方法/取得方法のサンプルを書いておく
とよさそうです。

[ ]
RE:10730 3つのHidemaru本体への関数追加No.10732
こみやんま さん 22/03/29 10:24
 
>setstaticvariableは、たまたまですが第3パラメータに-1を指定できるような追加
>が最近ありました。
> ......
>その手法があったとして見つけられないかもしれないので、ヘルプの「DLL側から秀
>丸エディタの関数呼び出し」のところに設定方法/取得方法のサンプルを書いておく
>とよさそうです。


-1 の引数オプションがあるのはチラリズム程度には認識していましたが、
たしかによくヘルプを見ると、
・共有せず、現在の秀丸エディタだけで有効で、実行中のマクロ内だけで有効です。
・マクロが終了したら消えます。
・上限の設定は関係ありません。

と記載されてありました。


これ-1指定時は、事実上は通常のマクロ変数と同じようなスコープの挙動だから、
通常変数のメモリ制限を逃れるため用意された特殊なオプションなんでしょうか?

例えば、

// dllfuncstrw( #dll, "GetHugeText" ) で長大テキストなりデータなりが得られる
として

setstativariable("temp_huge_text", dllfuncstrw( #dll, "GetHugeText" ), -1 );

みたいに一旦変数「的」なものに格納しておきたいものの、
「通常のマクロ変数に入れるとマクロ変数の(総合メモリ)制限は超えるかもしれない、
うーん、どこかに制限のない箱はないか」
といった回避用途に使うんでしょうか。


[ ]
RE:10732 3つのHidemaru本体への関数追加No.10733
秀丸担当 さん 22/03/29 11:23
 
-1は、setactivehidemaru等で他の秀丸エディタに切り替えたときの共有も無いので、
変数よりもさらに狭いスコープになると思います。
当初の目的は、変数が多いと遅い問題の回避手段の1つになればと思っていたのです
が、V9.13時点では変数問題もある程度改善されてきたので、それに対しての効果は
あまりないです。
ですがサイズや個数の制約が無いことや、競合が無いことはメリットがあるので、何
らかの使い道はありそうなので、無くさずにそのままにしておきました。
それで、今回使い道がありそうと思ったところでした。

[ ]
RE:10733 3つのHidemaru本体への関数追加No.10734
こみやんま さん 22/03/29 11:53
 
>-1は、setactivehidemaru等で他の秀丸エディタに切り替えたときの共有も無いので、
>変数よりもさらに狭いスコープになると思います。
>当初の目的は、変数が多いと遅い問題の回避手段の1つになればと思っていたので
>すが、V9.13時点では変数問題もある程度改善されてきたので、それに対しての効果
>はあまりないです。
>ですがサイズや個数の制約が無いことや、競合が無いことはメリットがあるので、
>何らかの使い道はありそうなので、無くさずにそのままにしておきました。
>それで、今回使い道がありそうと思ったところでした。

あ、たしかに他のプロセスとも共有しないからマクロ変数より狭いですね。

-1オプション誕生の経緯を理解しました、ありがとうございます。

[ ]