複数行コメントの強調表示が上手く使えなNo.39727
fzok4234 さん 22/05/17 07:27
 
いつもお世話になっております。fzok4234 です。


さて、ユーザー定義の「複数行コメント」の強調表示の応用方法で、どうしても上手
く強調表示ができない
ことがあって困ることがいくつかございます。

長くなるので以下 3 項目に分割して載せますが、いずれの内容も「複数行コメン
ト」だけで実現できず、現状では
強調表示の対象のファイルの書式ごとに自分で「構文解析器」をマクロや外部 DLL
の形で開発しないと
いけない状況となっています。一々ファイル形式ごとに構文解析器を 1 から作るの
は大変で、作った後も
動作の高速化のためのチューニングに相当時間と労力を奪われているのが実情です。

もちろん、Language Server Protocol のクライアント機能の外部 DLL を自作する、
という手もありますが、
これはあくまで Language Server という「既製」の構文解析器を呼び出すためのも
ので、処理したいファイル形式に
合った Language Server を誰かが提供してくれないと意味がありません。実際に
  https://microsoft.github.io/language-server-protocol/implementors/servers/
を見てみても対応言語はそれ程多くなく、当方でよくお世話になる
  ・コマンドプロンプトのバッチファイル。
  ・VBScript ( WSH ) 。
  ・ini ファイル。
  ・レジストリの *.reg ファイル。
や、何よりも秀丸エディタ自身で使う
  ・秀丸マクロ。
  ・強調表示の *.hilight ファイルや HmJreSelect.dll 用の .HmJreSelect ファイ
ル内の長大な
    正規表現パターンのリスト。
  ・デスクトップ保存の *.hmdesk やプロジェクトの .hmbook などのその他の設定
ファイル。
などは見当たりません。

こういったことから、行を跨いで文脈から正確に強調表示を行うことを「複数行コメ
ント」から手っ取り早く
行いたいのですが、実際に手を付けるとどうやっても上手くできないことがいくつも
発生して大変困っています。

どうか最適な解決方法の提案よろしくお願い申し上げます。



[ ]
RE:39727 1.開始文字列と終了文字列で囲わNo.39728
fzok4234 さん 22/05/17 07:29
 
1.  種類を「複数行」にした際に、「開始文字列」と「終了文字列」で囲われた「中
身の文字列」の書式を
    正規表現などを用いて厳格に指定する方法です。具体的には、
      1.1 複数の種類のエスケープ文字を Unicode で指定する。
      1.2 中身の文字列で特定の文字を使えないようにする。
      1.3 中身の文字列に改行コードを含む / 含まないの選択をする。
    といったところです。
   
    1.1 に関しては、現状ではダイアログの「エスケープ文字」欄には平文での 1
文字指定しかできず、
    複数種類の文字を正規表現で指定できません。このため、例えば PowerShell の
展開可能文字列
      "aaaa""bbbb`"cccc"
    のように、終了文字列 「"」( U+0022 、U+201C 、U+201D 、U+201E ) をエス
ケープする文字が
    「"」自身と汎用のエスケープシーケンス「`」( U+0060 ) との 2 種類、文字
コード上は 5 種類
    あるような場合では、どうやっても上手くエスケープ文字を指定できません。
   
    1.2 については、上記の PowerShell の展開可能文字列の場合、「"」と「`」は
エスケープシーケンスの
    ため、例えば
      "aaa"bbbb`"
    とかは不正な文字列リテラルとなるため「中身の文字列」を
      ・「"」と「`」を除外した任意の 1 文字。
      ・「""」。
      ・「`」と任意の 1 文字の組み合わせ。
    に限定しないといけません。しかし、ダイアログに「中身の文字列」を正規表現
で指定する欄が無いため
    このような制限が上手くできません。
   
    1.3 に関しては、例えばコマンドプロンプトのバッチファイルで
      hidemaru.exe "%USERPROFILE%\Documents\foo.txt"
    とあるときに、引数のファイルパスの部分は「開始文字列」と「終了文字列」の
両方を「"」として
    「表示方法」を「文字定数」とする「複数行」と定義し、パスの中の環境変数の
部分は「開始文字列」と
    「終了文字列」の両方を「%」として「表示方法」を「普通の文字」とする「複
数行」と定義したとします。
    この場合、改行コードが混入した
      "%USERP
      ROFILE%\Docum
      ents\foo.txt"
    といった不正な書式にもマッチしてしまうため、パスと環境変数共に「中身の文
字列」で改行コードの使用を
    禁止したいのですが、どうしても上手くできません。その理由として、
      ・「通常の強調表示」の機能では環境変数の部分に適用したい「表示方法」の
「普通の文字」が使用できない。
      ・複数行コメントの種類「単一の文字列」では「入れ子」ができないため、パ
スの「文字定数」よりも
        優先度の低い環境変数の「普通の文字」を重ねて強調表示できない。
    となっているため、必ず種類「複数行」でなければならないのですが、このとき
にどうやっても改行コードの
    排除ができません。



[ ]
RE:39727 2.特定の区間を除外しての複数行No.39729
fzok4234 さん 22/05/17 07:31
 
2.  種類を「複数行」にした際に、特定のパターンで囲われた区間だけ本来の強調表
示を中断させる方法です。
    C# や PowerShell など最近の言語で、文字列リテラル中に任意の式を埋め込ん
で自動的に展開する
    「補完文字列」というものが実装されるようになりました。例えば C# では
      str = $@"aaaaaaaaa{ ( val == null ? @"null" : val.ToString() ) , 3 }bb
bbbbb
               ccccccccc{    0
                           + 1
                           + 2
                           + 3
                           + 4
                         , 2 : X2
               }dddddddddddddd
               eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeee" ;
    で、PowerShell では
      $str = "aaaaaaaaa$(
                           if ( $null -eq $val ) {
                             "null"
                           } else {
                             $val.ToString()
             )bbbbbbbbbbbbb`nccccccccc$(  ( 0 + 1 + 2 + 3 + 4 ).ToString()
 )dddddd
             eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeee"
    という感じのものです。この場合、C# では「{」と「}」で、PowerShell では
「$(」と「)」で囲まれた
    部分が「補完式」となって任意の式や文を記述することが可能です。補完式の範
囲外の「aaaaa ... 」とか
    「bbbbb ... 」といった部分は通常の「静的な文字列リテラル」と同じ扱いとな
ります。
   
    ここで問題となるのが、この「静的リテラル」だけを狙って「表示方法」を「文
字定数」にして「複数行」の
    強調表示を行うための方法です。上記の C# の例の場合、「開始文字列」を「$@
"」に、「終了文字列」を
    「"」にして「表示方法」を「文字定数」とする「複数行」で定義すると、「{」
と「}」で囲われた「補完式」の
    部分まで全て「文字定数」で色付けされてしまいます。このため、この「補完
式」の部分だけを除外して
    それ以外の「静的リテラル」だけを「文字定数」で色付けして、「補完式」の範
囲内では
      ・ローカル変数 val は「普通の文字」のまま。
      ・演算子 == 、 ? 、 : などは「強調表示 1」。
      ・数字 0 、1 、... は「数値」。
      ・入れ子になった文字列 @"null" は改めて「文字定数」。
    という本来の色付けを行う、といったことがどうしても上手くできません。
   
    「静的リテラル」だけを狙うつもりで { 開始文字列 , 終了文字列 } の組を
      a.  { \$@" , \{ }
      b.  { \}   , \{ }
      c.  { \}   , "  }
    の 3 つ用意して「文字定数」とするような方法では、b. の項目が例えば
      if ( condition )
      {
        System.Console.WriteLine( @"a" ) ;
      }
      else
      {
        System.Console.WriteLine( @"b" ) ;
      }
    というコードの 3 〜 5 行目の「} else {」の部分まで「文字定数」とするよう
な誤爆が起きてしまいます。
    今までの経験から、このような誤爆の回避は大変困難であることが分かっていま
す。



[ ]
RE:39727 3.中身抜きでの開始文字列と終了No.39730
fzok4234 さん 22/05/17 07:33
 
3.  「開始文字列」と「終了文字列」のみ色付けして「中身の文字列」への色付けを
行わない方法です。
    上記 2. の応用とも言えますが、主な目的は入れ子の階層の深い括弧に別々の色
を付けて、入れ子関係を
    明確にすることです。
   
    当方では例えば、
      [ReplaceRegExp]
      (?#psnumeric)=(?>(?:)|(?:@\A(?>(?<decimalDigits>\d++)|(?<hexDigits>\h+
+)|(?<numericTypeSuffix>(?>(?<longTypeSuffix>(?i:[l]))|(?<decimalTypeSuffix>
(?i:[dl]))))|(?<numericMultiplier>(?i:[kmgtp][b]))|(?<decimalSeparatorChar>
(?<!(?<![\.])[\.])[\.])|(?<exponentPart>(?i:[e])(?>[\+]|\g<dashChar>)?+\g<de
cimalDigits>)|(?<numeric>\g<noEscapeL>(?>(?<realLiteral>(?>(?:\g<decimalDigi
ts>?+\g<decimalSeparatorChar>\g<decimalDigits>\g<exponentPart>?+)|(?:(?<!\g<
decimalSeparatorChar>)\g<decimalDigits>\g<exponentPart>))\g<decimalTypeSuffi
x>?+\g<numericMultiplier>?+)|(?<integerLiteral>(?>(?<hexIntegerLiteral>[0](?
i:[x])\g<hexDigits>\g<longTypeSuffix>?+\g<numericMultiplier>?+)|(?<decimalIn
tegerLiteral>\g<decimalDigits>\g<numericTypeSuffix>?+\g<numericMultiplier>?
+))))))))
    というような長い正規表現パターンを *.hilight とか HmJreSelect.dll の .Hm
JreSelect とかのテキストファイルに
    記述する機会が多いのですが、正規表現パターンの丸括弧「(」、[)]の入れ子階
層が深くなって正しい
    入れ子関係を把握することが困難になることがよくあります。
   
    そこで、{ 開始文字列 , 終了文字列 } を丸括弧の { \( , \) } にして「複数
行」にしつつも、括弧の部分だけ
    色付けして括弧の中身はそのままにしたいのですが、どのような手順でこれを行
えばよいのか全く分かりません。
   
    さらに、もし仮にこれができたとしても、ダイアログの「入れ子」の 3 つのオ
プションは 8 階層までしか
    サポートされず、際限なく入れ子階層が深くなるようなケースではどのように対
処すればよいのか全く
    分かりません。



[ ]
RE:39727 複数行コメントの強調表示が上手No.39731
秀丸担当 さん 22/05/17 10:51
 
それぞれについて、手っ取り早くする方法は無いので、やるとしたらマクロなどでカ
ラーマーカーで色付けするのが一番早いと思います。

こういった複雑な定義はLSPというより、TextMateから始まるtmLanguageという定義
方法がvscodeやVisualStudioなどでも使われているようで、その方法は正規表現を大
量に書いてするもののようです。
一応ちょっと前に話題があったとき、対応できないかと思ってそれなりに手元では動
いたりしていますが、公開できるものになるかどうかは不透明です。
どこかにあるtmLanguageの資産を使うことを考えると、鬼車の方言がもはやデファク
トスタンダードのようで、鬼車を含んだ別DLLを作るしかないかなと思っています。
あとCPUをけっこう使ったり、どうしても非同期になるので複数行コメント定義のよ
うに即時性は無くなったりします。

もしtmLanguageができたとして、新規に自分が定義するのは、手っ取り早い解決手段
になるとは言い難いかもしれないです。
即時性は無く、文法解析を正規表現縛りで大量に定義することになると思うので、そ
れであれば、マクロや外部のプログラムでやったほうが早いということになるかもし
れません。

[ ]