検索ヒット件数が数万件に渡る場合の「すべて検索」動作速度について

  1. Kuroさん

    お疲れさまです。
    最近、職場でMery布教活動に勤しみまして、サクラエディタユーザーを一人引き込みましたw
    痒いところに手が届く感じでいいね、と気に入ってくれたようです👌

    さて、日頃優しく使えば起こることでもないのですが、マルチカーソルを酷使したときの動作時間について気になったので一応ご報告です。

    「すべて検索」を使ったとき、ヒットする件数に応じてマルチカーソル化の処理時間が指数関数的に増えるようです。

    環境:
    ・CPU: AMD Ryzen 5 3600
    ・メモリ: 32 GB
    ・Windows 11 22H2
    ・Mery 3.5.5

    「すべて検索」実行結果 (左:ヒット件数、右:処理完了時間):
    1000個: 0.148秒
    3000個: 0.65秒
    6000個: 1.923秒
    10000個: 4.777秒
    20000個: 17.939秒
    30000個: 38.595秒
    40000個: 67.612秒
    50000個: 106.315秒
    60000個: 154.237秒

    グラフ化:
    https://imgur.com/a/uxGuup1

    以下のマクロで検証しました:

    outputBar.Writeln("---");
    
    var before = new Date();
    outputBar.Writeln(before);
    
    var sel = document.selection;
    sel.Find(sel.Text, meFindAll);
    
    var after = new Date();
    outputBar.Writeln(after);
    
    outputBar.Writeln((after - before) / 1000);
    

    マルチカーソル機能が大好きゆえに Ctrl+Shift+A での「すべて検索」を多用しがちで… つい、容量大きめのCSVなんかでヒットする件数を意識せずに使ったりして、そのまま応答なしになってしまうことがあるんです。 (ガバガバな検索条件で使うせいなんですけれど😅)

    上記のマシン以外にWindows 10のもうちょっとスペック控えめなマシンでも確認しましたが、傾向としては同様で、1万件あたりを堺に処理時間の増加が顕著でした。

    せめて1万件を超えるあたりから遅くなるのを見越して、カーソルを増やす処理中 (1万件あたり) に「検索にヒットする箇所が多いため、処理に時間がかかる可能性があります。続行しますか?」のような確認が入れば、いつ処理が戻ってくるのか分からないまま待ちぼうけ…という事態は避けられそうではあるので、そういった形でもかなり助かります。(お茶濁し的ですが、、、)

    また、ヒット件数が多いと時間がかかるのはある程度仕方ないのだろうと思うので、「すべて検索」実行中にマウスカーソルを処理中を示すグルグルアイコン (スピナー、と言うんでしょうか?) にしてはいかがでしょうか?

    私のようにMeryにマルチカーソルで過酷な労働を強いているために起きていることではあるので要望しづらいのですが、もしなにか対策が思いつくようであれば、ご検討いただけると嬉しいです。

     |  yuko  |  返信
  2. ご報告ありがとうございます。

    > 痒いところに手が届く感じでいいね、と気に入ってくれたようです👌

    そう言っていただけると嬉しいです。でも、サクラエディタさんのほうが圧倒的に多機能ですし、職場では定番ですから安心感もあるかと思いますよー。

    > せめて1万件を超えるあたりから遅くなるのを見越して、カーソルを増やす処理中 (1万件あたり) に「検索にヒットする箇所が多いため、処理に時間がかかる可能性があります。続行しますか?」のような確認が入れば、いつ処理が戻ってくるのか分からないまま待ちぼうけ…という事態は避けられそうではあるので、そういった形でもかなり助かります。(お茶濁し的ですが、、、)

    マルチカーソルの数は 1 万件に制限をかけていたつもりでしたが、どうやらリミッターが動作してないっぽいです。VS Code も 1 万件だったので、それに合わせたつもりでした。

    > また、ヒット件数が多いと時間がかかるのはある程度仕方ないのだろうと思うので、「すべて検索」実行中にマウスカーソルを処理中を示すグルグルアイコン (スピナー、と言うんでしょうか?) にしてはいかがでしょうか?

    そうですね。しかし、カーソルを追加するだけなのにちょっと時間がかかりすぎな気もするので、まずは高速化の方向で調べてみようと思います。

    とはいえ、1 万件にカーソルを制限したとしても、編集の速度だけはどうしようもありませんが…😅

     |  Kuro  |  返信
  3. > サクラエディタさんのほうが圧倒的に多機能ですし、職場では定番ですから安心感もあるかと思いますよー。

    そもそもMeryの初期状態が忘却の彼方な私のコテコテカスタマイズ環境のせいで、サクラエディタの方が多機能というのを失念していました…😳

    私としては、マクロで拡張がしやすい点、言語別設定とカラーテーマはシンプルさ重視で分離している点、などなど…こう、色々とちょうど良い感じ (語彙力低) が気に入っているわけですが、同じようなポイントで刺さる人は少なくないと思います。少なくとも私の周りでは、それなりにエンジニアとして活躍している知人方にMeryが愛用されていますので!

    > マルチカーソルの数は 1 万件に制限をかけていたつもりでしたが、どうやらリミッターが動作してないっぽいです。VS Code も 1 万件だったので、それに合わせたつもりでした。

    そうだったのですね。
    たしかに1万件あたりまでであればちょっと待てばいい具合でしたし、そのあたりの制限がやはりちょうどいいのでしょうね。

    > とはいえ、1 万件にカーソルを制限したとしても、編集の速度だけはどうしようもありませんが…😅

    まぁ、1万箇所に同等の編集を加えられる形式となると、ほとんどの場合で正規表現でサクッと編集できそうではありますので、よほどの編集箇所量で速度も求めるということであれば、普通に置換を使ってくださいという話ですよね。マルチカーソルが無い時代はそうやってきたわけですし…😅
    Ctrl-Shift-A が便利すぎて、惰性で置換でなくマルチカーソル編集してしまうのが手癖になってしまい、、、

    ところで最近は折返しインデントで心が折られているようですが、あれが実現したらと、見ていてとてもワクワクしました。
    メモ書きってMarkdownでなくともインデントを付けつつ構造化しながら書くことが多いですから、折返しインデントがされてくれるとすごく人に優しい見た目になりますね。
    それに、同時に作っているインデントガイドとの相性もこれまた感動的で… 過去に挫折した機能とのことで、察することさえできないくらい大変そうではありますが、完成を心より期待しています!

     |  yuko  |  返信
  4. マルチカーソルにおける処理速度、という括りでこちらで報告します。 (ややトピック混同になってしまってすみません)

    [文字コードの切り替え] をマルチカーソルで行うと、カーソル毎に処理できますが、こちらも指数関数的に処理時間が増加するようです。

    100件: 0.06秒
    1000件: 1.236秒
    2000件: 5.965秒
    3000件: 17.328秒
    4000件: 38.613秒
    5000件: 71.123秒

    ※全件「通常文字 → Unicode への変換」の処理で計測

     |  yuko  |  返信
  5. > 少なくとも私の周りでは、それなりにエンジニアとして活躍している知人方にMeryが愛用されていますので!

    ありがとうございます。私の周りには Mery ユーザーがいないもので、そう言っていただけるとうれしいです!

    > よほどの編集箇所量で速度も求めるということであれば、普通に置換を使ってくださいという話ですよね。

    そうですね。VS Code でも 1 万件を超えようとすると「置換を使いなさい」ってアラートがでますから、そういうものなのでしょう😅

    Visual Studio 2022 だとカーソルの数に上限はないようですが、数万件のカーソルで文字列操作 (たとえば、[編集] > [詳細] > [行インデント]) などするとフリーズしちゃいますね。

    マルチカーソルって内部的に置換しているわけではなく、手動でやるのと同じ操作を自動でやってるだけなので、速度は期待できませんし、[元に戻す] のバッファもカーソルの数だけ消費してしまうので、ぜひ、[置換] と使い分けていただければと思います。

    > メモ書きってMarkdownでなくともインデントを付けつつ構造化しながら書くことが多いですから、折返しインデントがされてくれるとすごく人に優しい見た目になりますね。

    Markdown なんかで使用されるとヤだなーと思っていました (w

    というのも、箇条書きなんかで「-」や「*」のぶんもインデントとして扱えるように、といったご要望が出てくる気がしたものですから。

    VS Code や Sublime Text はできないですからね!(秀丸エディタさんとサクラエディタさんはできちゃいますが…)

    > それに、同時に作っているインデントガイドとの相性もこれまた感動的で… 過去に挫折した機能とのことで、察することさえできないくらい大変そうではありますが、完成を心より期待しています!

    そうなんですよね。実はこれ、折り返しインデントを実装するにあたって、すべての行のインデントを計算するので、どうせならその値を何か他にも使えないかしら、と思いついた機能でした。

    > [文字コードの切り替え] をマルチカーソルで行うと、カーソル毎に処理できますが、こちらも指数関数的に処理時間が増加するようです。

    ご報告ありがとうございます。

    これは上記で書いた内容とかぶってしまいますが、仕様上、動作速度が遅いのはどうしようもなさそうなので、やるとしたら、途中で中断できるような仕組みを用意するぐらいですね。

    とはいえ、すべての処理に割り込みをかけられるわけではないので、ある程度はフリーズを回避できるかな、ぐらいの対策になってしまうと思いますが…😅

     |  Kuro  |  返信
  6. > Markdown なんかで使用されるとヤだなーと思っていました (w
    >
    > というのも、箇条書きなんかで「-」や「*」のぶんもインデントとして扱えるように、といったご要望が出てくる気がしたものですから。

    まぁさすがにそこまで考慮しなくていいんじゃないかなーと思いますけどね

    > VS Code や Sublime Text はできないですからね!(秀丸エディタさんとサクラエディタさんはできちゃいますが…)

    …と思ったら、秀丸、サクラはできちゃうんですね。なんとなくそちらの2つは、設定の方式といい、方向性が似てる感じがありますねー。

    > そうなんですよね。実はこれ、折り返しインデントを実装するにあたって、すべての行のインデントを計算するので、どうせならその値を何か他にも使えないかしら、と思いついた機能でした。

    なるほど、副産物だったんですね。
    全行のインデント幅計算ともなると、チューニングが難しそうです。

    > これは上記で書いた内容とかぶってしまいますが、仕様上、動作速度が遅いのはどうしようもなさそうなので、やるとしたら、途中で中断できるような仕組みを用意するぐらいですね。

    ありがとうございます。
    この量の文字コード変換をする人なんてそうそういないでしょうし、簡易的な方法でも対策いただけるだけで大変ありがたいです🙇‍♂️

     |  yuko  |  返信
  7. 自分はマルチカーソルを1個ずつ順番に処理するマクロを作って使っています。

    こちらの投稿を拝見してこのマクロの処理速度が気になり [文字コードの切り替え] で試したところ、単に [文字コードの切り替え] を実行するよりマクロのほうが速かったので何か参考になればと投稿してみます。

    比較のため toggleCharacterCode メソッドのみ実行した場合も計測しました。
    スペックが低いためか yuko さんの計測結果よりかなり処理時間が長くなりました。

    【単に [文字コードの切り替え] を実行】

    ・コード

    var numberOfSelections = document.selection.count || 1;
    var startTime, endTime;
    startTime = new Date();
    
    document.selection.toggleCharacterCode();
    
    endTime = new Date();
    outputBar.writeln(numberOfSelections + '個: ' + (endTime - startTime) / 1000 + '秒');
    

    ・結果

    100個: 0.087秒
    1000個: 2.758秒
    2000個: 15.468秒
    3000個: 47.548秒
    4000個: 108.82秒
    5000個: 205.077秒

    順番に処理するマクロは、
    (1) 選択範囲の情報を記録
    (2) すべての選択範囲を解除
    (3) ずれを調整して選択範囲の情報を更新
    (4) 選択
    (5) toggleCharacterCode メソッドを実行
    (6) 処理後のずれを計算して記録
    (7) (3)から(6)を記録した選択範囲分繰り返す
    (8) 選択範囲を復元
    みたいな流れになってます。

    最初はこちらのほうが遅いかと予想してましたが、10000個でも21秒くらいと処理時間が短かったです。

    【1個ずつ順番に処理するマクロ】

    ・コード

    var numberOfSelections = document.selection.count || 1;
    var startTime, endTime;
    startTime = new Date();
    
    var docSel = document.selection;
    
    function Sel(index) {
      this._activePos = docSel.getActivePos(index);
      this._anchorPos = docSel.getAnchorPos(index);
    }
    
    Sel._offset = 0;
    Sel.selections = [];
    
    Sel.prototype.adjustPos = function() {
      this._activePos += this.constructor._offset;
      this._anchorPos += this.constructor._offset;
    };
    
    Sel.prototype.select = function() {
      docSel.setActivePos(this._activePos);
      docSel.setAnchorPos(this._anchorPos);
    };
    
    Sel.prototype.updateOffset = function() {
      var endPos = Math.max(docSel.getActivePos(), docSel.getAnchorPos());
      if (this._activePos > this._anchorPos) {
        this.constructor._offset += endPos - this._activePos;
        this._activePos = endPos;
      } else if (this._activePos < this._anchorPos) {
        this.constructor._offset += endPos - this._anchorPos;
        this._anchorPos = endPos;
      } else {
        this.constructor._offset += endPos - this._activePos;
        this._activePos = this._anchorPos = endPos;
      }
    };
    
    Sel.storeSelections = function() {
      var count = docSel.count || 1;
      for (var index = 0; index < count; index++) {
        this.selections.push(new Sel(index));
      }
    };
    
    Sel.restoreSelections = function() {
      docSel.setActivePos(this.selections[this.selections.length - 1]._activePos);
      docSel.setAnchorPos(this.selections[this.selections.length - 1]._anchorPos);
      for (var i = 0; i < this.selections.length; i++) {
        docSel.addPos(this.selections[i]._anchorPos, this.selections[i]._activePos);
      }
    };
    
    Sel.storeSelections();
    
    redraw = false;
    beginUndoGroup();
    addUndo();
    
    docSel.clear();
    
    for (var i = 0; i < Sel.selections.length; i++) {
      Sel.selections[i].adjustPos();
      Sel.selections[i].select();
    
      docSel.toggleCharacterCode();
    
      Sel.selections[i].updateOffset();
    }
    
    Sel.restoreSelections();
    
    endUndoGroup();
    redraw = true;
    
    endTime = new Date();
    outputBar.writeln(numberOfSelections + '個: ' + (endTime - startTime) / 1000 + '秒');
    

    ・結果

    100個: 0.077秒
    1000個: 0.833秒
    2000個: 1.924秒
    3000個: 3.293秒
    4000個: 4.968秒
    5000個: 6.91秒
    10000個: 21.309秒

     |  ucky  |  返信
  8. ご報告ありがとうございます。

    その後、私のほうでもマルチ カーソルの動作速度の改善に取り組んでおり、次のバージョンでは、爆速とまではいきませんが、それなりに実用レベルかなといった感じには最適化できそうです。

    いただいたマクロですと、【単に [文字コードの切り替え] を実行】の場合、たぶん 3 秒ぐらいにはなるかと思うので、次のバージョンのリリースまで今しばらくお待ちくださいませ。(プログラムはできているのですが、今、新機能とかの記事を書いてる途中です)

     |  Kuro  |  返信
  9. リリースに向けた作業にお忙しい中、返信ありがとうございます。

    新バージョンのリリース楽しみにしています!

     |  ucky  |  返信
  10. uckyさん

    > 自分はマルチカーソルを1個ずつ順番に処理するマクロを作って使っています。

    ありがとうございます。なるほど、その手がありましたか!
    標準機能があったがゆえ、自前で変換とは認識からすっぽ抜けていました…。

    Kuroさんの方で機能をだいぶ改善してくださったとのことではありますが、情報提供ありがとうございました。
    本題からずれますが、マルチカーソルの扱いについての処理がシンプルにまとまっていて、だいぶ勉強になりました。

    Kuroさん

    おおっ、いよいよ新バージョンも間近ですか。
    そして最後の大仕事、記事執筆…。筆が重量級かと思いますが、応援しております🤤

     |  yuko  |  返信
  11. >> ucky さん

    応援ありがとうございます!新バージョン、なんとかリリースできました。

    マルチ カーソルの動作速度はそこそこ改善できたものの、1 万を超えてくるとやっぱり遅いですね。

    いただいた、【1個ずつ順番に処理するマクロ】より、ちょっと速いかな、と言った感じですが、エディターコンポーネントの仕様上、大きなファイルだと 1 つ 1 つの操作が遅くなってしまうものですから、恐らくこの速度が限界っぽいです…。

    >> yuko さん

    新バージョン、ようやくリリースできました。

    [すべて検索] コマンドは爆速になってると思います。

    …が、[文字コードの切り替え] など [選択範囲の変換] の操作はある程度、高速化できたものの、1 万を超えてくると快適とは言えない程度には遅いですね。

    進捗ダイアログの表示と、[キャンセル] で処理を中断できるようにしてみたので、これでフリーズは回避できるかと思います。([キャンセル] と言っても、途中まで処理したものがロールバックされるわけではないですが、そこはご了承くださいませ)

    > そして最後の大仕事、記事執筆…。筆が重量級かと思いますが、応援しております🤤

    応援ありがとうございます!ほんと…😅 このご時世、ブログ記事なんてリスクしかないものですから、できれば 1 ミリもやりたくない苦行でございます。

    そしてリリースした直後にバグを見つけてしまう現象、キマシタワー。ヤダモー😭

     |  Kuro  |  返信
  12. Kuroさん

    リリース (と記事執筆) 大変お疲れさまでした。

    > マルチ カーソルの動作速度はそこそこ改善できたものの、1 万を超えてくるとやっぱり遅いですね。

    十分すぎるほどの改善具合でした👏
    よく合成フォントの調査や確認にカスタムフォント機能と合わせて文字変換は使うので、めちゃくちゃ助かります。ありがとうございます!

    > 進捗ダイアログの表示と、[キャンセル] で処理を中断できるようにしてみたので、これでフリーズは回避できるかと思います。([キャンセル] と言っても、途中まで処理したものがロールバックされるわけではないですが、そこはご了承くださいませ)

    入力時だけでなく、戻るにも進捗ダイアログが出るようになったんですね。
    進んでいるのか止まっているのか分からない感じがなくなったので、それも相まって体感速くなったように感じました。
    いや実際に処理を改善して速くもなっているのだと思いますが、よく聞く「ゴールが見えると耐えられる心理」を感じましたw

    > そしてリリースした直後にバグを見つけてしまう現象、キマシタワー。ヤダモー😭

    なんなんでしょうね、あの現象は… リリースの神様はバグ検出がお上手なんでしょうかね…🤔
    そして私も折り返しインデント周りで発見してしまいましたので、ご報告を。。。
    https://imgur.com/a/XzoZyxl

    動画にキャプションを挟んでいますが、以下の2点です。

    (1) インデント付きの行で、まずカーソルを論理行頭のインデント内に移動させる。直後に下にカーソル移動させて折り返しインデント先頭にカーソル移動する。すると右矢印キーを2回押さないとカーソルが右に移動しない。
    (2) 折り返しインデントされた行で、上方向にカーソル移動をする際に直上ではなく左上方向にカーソルがずれる。一応、フォントがプロポーショナル (UDEV Gothic 35JPDOC) なのがいけないのかと思い、モノスペース (UDEV Gothic JPDOC や MS ゴシック) なフォントにしてみたりしましたが、同様でした。

    このへんの位置計算は大変そうですよね…😅

     |  yuko  |  返信
  13. > (2) 折り返しインデントされた行で、上方向にカーソル移動をする際に直上ではなく左上方向にカーソルがずれる

    「上方向に」としていましたが、下方向でも発生することはあるようです。
    どうやらカーソル移動前のカーソル位置が、折り返しインデント後の行になっていると発生するように見えます。

    https://imgur.com/a/tTbNR6X

     |  yuko  |  返信
  14. 早速お試しいただきありがとうございます。

    > 十分すぎるほどの改善具合でした👏

    そう言っていただけると私の土日が報われます😂

    > 入力時だけでなく、戻るにも進捗ダイアログが出るようになったんですね。

    そうなんです。[元に戻す] の場合は [キャンセル] しても、もう一度 [元に戻す] を実行すれば、続きから元に戻せるようになっています。

    あと、マルチ カーソル関連のほとんどの処理はキャンセルできるようにしたので、カーソルの上限、1 万は廃止しました。

    > なんなんでしょうね、あの現象は… リリースの神様はバグ検出がお上手なんでしょうかね…🤔

    ほんと、出鼻をくじかれてしょんぼり…、と思っていたのですが、勘違いでした (w

    > そして私も折り返しインデント周りで発見してしまいましたので、ご報告を。。。

    ご報告ありがとうございます。

    やはり折り返しインデントはバグ出ますよね。出たとこ勝負な感じですが、お付き合いいただけるとありがたいです。

    > (1) インデント付きの行で、まずカーソルを論理行頭のインデント内に移動させる。直後に下にカーソル移動させて折り返しインデント先頭にカーソル移動する。すると右矢印キーを2回押さないとカーソルが右に移動しない。

    現象、確認しました。カーソルが変なところに入っちゃってますね。これは修正できそうです。

    > (2) 折り返しインデントされた行で、上方向にカーソル移動をする際に直上ではなく左上方向にカーソルがずれる。

    現象、確認しました。

    これは上下移動時、カーソルの X 座標を維持する仕組みに、折り返しインデントが干渉しちゃってますね。

    > このへんの位置計算は大変そうですよね…😅

    そうなんですよね。もともとそういった機能のないエディターコンポーネントに無理やり実装しているものですから、影響範囲は計り知れず…😱

     |  Kuro  |  返信
  15. 追伸、ご報告いただいた 2 点、修正できました。

    UDEV Gothic 35JPDOC でも確認しておいたので、たぶん大丈夫かなと思います😌

    検証にご協力いただいたとき、どこからどこまでがこのバグの影響なのか判断が難しいと思うので、この 2 点は早めに修正版をリリースしたいところです。

    別件で恐縮ですが、インデント ガイドが表示されないという件も現象が再現できれば修正版に追加したいところですが…

     |  Kuro  |  返信
  16. Kuroさん

    > そうなんです。[元に戻す] の場合は [キャンセル] しても、もう一度 [元に戻す] を実行すれば、続きから元に戻せるようになっています。

    たしかに、そのように動きました。
    元から快速なのでそうそう出くわすこともないとは思いますが、実際起こったときに「フリーズでなく処理に時間かかってるだけ」というのがひと目見て分かるのはやはり安心できますね。

    > やはり折り返しインデントはバグ出ますよね。出たとこ勝負な感じですが、お付き合いいただけるとありがたいです。

    もちろんです。
    こういった新機能や機能改善を試すのが好きな人間としては、こうやって改善されていくのを見るのもまた楽しいですしね。 (直す方は大変だと思いますけど😅)
    気づいたところがあれば随時報告させていただきますね。

    > 検証にご協力いただいたとき、どこからどこまでがこのバグの影響なのか判断が難しいと思うので、この 2 点は早めに修正版をリリースしたいところです。

    そうですね。試してすぐに目についたということは使っていてかなりの頻度で出くわしそうではあるので、こまめなリリースになってしまうのは恐縮ですがそうしてもらえると私としても嬉しいです。

    > 別件で恐縮ですが、インデント ガイドが表示されないという件も現象が再現できれば修正版に追加したいところですが…

    うーん、私の方でもいくつか適当に見てはいるものの、再現しないんですよね。
    ただ、該当スレッドの方でKuroさんがおっしゃっているように、タブ文字に背景色を付けているとまったく描画されないですね。

    あとは検索でタブ文字がヒットしているときにも同様の理由か、ハイライト色が優先されて表示されなくなるようです。ただ、こちらについては「検索にタブ文字をヒットさせながらインデントガイドを表示させたい」ってケースがあまり思い浮かばないので、修正が難しい内容なら放置でもいい気はします。

     |  yuko  |  返信
  17. > こういった新機能や機能改善を試すのが好きな人間としては、こうやって改善されていくのを見るのもまた楽しいですしね。 (直す方は大変だと思いますけど😅)

    ありがとうございます。
    特に今回は折り返しインデントの実装が、私の技術ではかなり厳しかったものですから、そう言っていただけると心強いです。

    > 試してすぐに目についたということは使っていてかなりの頻度で出くわしそう

    お恥ずかしい限りです。自分が作ったプログラムって、テストするとなぜか体が勝手にバグを避けて動いてしまうんです…😅 なので、検証にご協力いただけてとても助かります。

    > ただ、該当スレッドの方でKuroさんがおっしゃっているように、タブ文字に背景色を付けているとまったく描画されないですね。

    先ほどご返信をいただけて、タブの背景色だったようです。

    > あとは検索でタブ文字がヒットしているときにも同様の理由か、ハイライト色が優先されて表示されなくなるようです。

    なるほど、そのパターンもありましたか。あとはマーカーでの色付けなんかもありそうですね。

    > 「検索にタブ文字をヒットさせながらインデントガイドを表示させたい」ってケースがあまり思い浮かばないので、修正が難しい内容なら放置でもいい気はします。

    インデント ガイドを描画する順番が文字より先か後か、だけの問題なので、どちらでも変更は簡単です。

    今回、参考にさせていただいた Sublime Text ではインデント ガイドが文字より先に描画されていたもので、それに合わせてみましたが、秀〇エディタさんや E〇Editor さんは文字より後のようですね。(VSCode は微妙な感じ)

    この件も含めて、今夜あたりにリリースします!

     |  Kuro  |  返信
  18. >> yuko さん

    お役に立てたなら幸いです。
    しかし、Ver 3.5.6 でかなり速くなったので標準機能に関してはこのマクロの出番はなさそうですね。

    >> Kuro さん

    リリースお疲れ様です。

    こちらの環境では、10000個で 1.097秒と標準機能のほうがかなり速くなりました。普段は標準機能で足りることは標準機能で済ませているので助かります。

    それと、自分もインデント ガイドが表示されないケースに出くわしたので向こうのほうに投稿します。

     |  ucky  |  返信
  19. Kuroさん

    Ver 3.5.7 リリース、ありがとうございます。

    おかげさまで折り返しインデント時のカーソル移動、スムーズになりました。やはりインデントで揃ってくれると、階層的なメモでの見た目が良いですね。しばらくONのままで使ってみようと思います。

    ところでアンインデントの操作ですが、おそらく前回?今回?のアップデートによって、複数行選択かつアクティブカーソルが1列目 (行頭) のときの動きが以前と変わってしまったようです。

    上記の選択状態の場合、アクティブカーソルが1列目になっている行だけはアンインデント対象外となるように動いていたと思いますが、現状はその行もアンインデント対象となります。

     |  yuko  |  返信
  20. ご返信ありがとうございます。

    こちらこそ。おかげさまで、修正版、なんとかリリースできました。

    > おかげさまで折り返しインデント時のカーソル移動、スムーズになりました。

    そうですね。折り返しインデント時のカーソルの X 座標維持は VSCode を参考に実装してみました。Sublime Text と VSCode を行ったり来たり、最近は Sublime Text に傾いておりますが😅

    > 複数行選択かつアクティブカーソルが1列目 (行頭) のときの動きが以前と変わってしまったようです。

    これは、ツイッターのほうで Ver 3.5.6 で不具合の報告をいただきまして、Ver 3.5.7 で修正しましたが、問題がありましたでしょうか?

    > 上記の選択状態の場合、アクティブカーソルが1列目になっている行だけはアンインデント対象外となるように動いていたと思いますが、現状はその行もアンインデント対象となります。

    変更以前 (Ver 3.5.5) で試してみましたが、複数行選択の場合、動作に違いはなさそうに見えます。

    お手数をおかけしますが、具体的な再現方法など教えていただけると助かります。

     |  Kuro  |  返信
  21. Kuroさん

    > そうですね。折り返しインデント時のカーソルの X 座標維持は VSCode を参考に実装してみました。Sublime Text と VSCode を行ったり来たり、最近は Sublime Text に傾いておりますが😅

    VSCodeの座標位置といえば、Meryだとプロポーショナル扱いな 3:5 幅のフォントでもちゃんと上下でのカーソル移動で、元の行位置と近い位置に移動してくれて助かります。VSCodeだと 1:2 幅以外のフォントで全角文字と半角文字が混在していると、上下移動の際にカーソル位置が大きくずれるんですよね…

    > 変更以前 (Ver 3.5.5) で試してみましたが、複数行選択の場合、動作に違いはなさそうに見えます。
    >
    > お手数をおかけしますが、具体的な再現方法など教えていただけると助かります。

    すみません。怠けてキャプチャを撮るのを端折ってしまいました…😅
    https://imgur.com/a/4QNWqnf

    上記で、1枚目が Ver 3.5.5、2枚目が Ver 3.5.7 です。
    1行目/1列目 から選択を開始し、3行目/1列目 で止めています。その状態でShift+Tabを押しています。
    すると、3行目「ccccc」の行が Ver 3.5.7 だとアンインデント対象になってしまっているのが見て取れるかと思います。

     |  yuko  |  返信
  22. ご返信ありがとうございます。

    > VSCodeの座標位置といえば、Meryだとプロポーショナル扱いな 3:5 幅のフォントでもちゃんと上下でのカーソル移動で、元の行位置と近い位置に移動してくれて助かります。

    なるほどー。Mery の場合、上下の移動を開始した時点での列 (X 座標) をピクセル単位で記憶、カーソル上下移動時は逆にピクセル単位から列に復元してるので、画面上での位置がズレにくいのだと思います。(私が作ったわけではありませんが😅)

    > すみません。怠けてキャプチャを撮るのを端折ってしまいました…😅

    お手数をおかけします。あ、なるほど…。1 列目にカーソル、私は下から適当にマウスで選択して 1 列目にカーソルを持ってきてたもので再現できなかったようです。

    確かに、他のエディターで試してみたらすべて、1 列目にカーソルはアンインデント対象外のようですね。

    小さな親切と思って追加した機能でしたが、大きなお世話だったようで、次のバージョンではロールバック (廃止) したほうが良さそうですね。

     |  Kuro  |  返信
  23. > 確かに、他のエディターで試してみたらすべて、1 列目にカーソルはアンインデント対象外のようですね。

    そうなんです。なのでアンインデントの操作が1列目で止めるかたちで使っている方には結構違和感出るかなと…

    > 小さな親切と思って追加した機能でしたが、大きなお世話だったようで、次のバージョンではロールバック (廃止) したほうが良さそうですね。

    未選択状態でアンインデント自体はけっこう嬉しいと思いますが、メンテが難しい(そして面倒くさい)のであれば、勿体ないですがロールバックもやむなしでしょうかね。
    個人的にはわざわざ「未選択状態でもアンインデントできるマクロ」を使っているくらいなので、それなりに需要のある仕様ではないかなぁと思っているんですけどねー

     |  yuko  |  返信
  24. > 個人的にはわざわざ「未選択状態でもアンインデントできるマクロ」を使っているくらいなので、それなりに需要のある仕様ではないかなぁと思っているんですけどねー

    おぉ、スゴイ!マクロで実現できるとは…。
    VSCode で便利だと思って実装した未選択アンインデントでしたが、Sublime Text ではデフォルトで無効になっているし、秀〇エディタさんやサク〇エディタさんでも使えないもので、余計なことをしてしまったかな…と思っていました😅

    > 未選択状態でアンインデント自体はけっこう嬉しいと思いますが、メンテが難しい(そして面倒くさい)のであれば、勿体ないですがロールバックもやむなしでしょうかね。

    > > 確かに、他のエディターで試してみたらすべて、1 列目にカーソルはアンインデント対象外のようですね。

    ↑ の仕様を生かすためには未選択アンインデントを潰すしかないなーと思ったのですが、VSCode や Sublime Text の仕様をよく見てみると、選択範囲がない場合は 1 列目にカーソルがあってもアンインデント対象になるみたいですね。

    つまり、選択範囲がある場合は Ver 3.5.5 以前の仕様。選択範囲がない場合は Ver 3.6.7 の仕様と分ければ対応できそうな気がしてきました。

    > それなりに需要のある仕様ではないかなぁと思っているんですけどねー

    ですよね。未選択アンインデントって Sublime Text だとデフォルトで無効ですし、実装されると逆に使いづらくなってしまうというユーザーさんもいるのかしら。

     |  Kuro  |  返信
  25. > おぉ、スゴイ!マクロで実現できるとは…。

    あ、いえいえ、そんな大層なものでなく、未選択時に SelectLine() をしてから Unindent() を呼び出すだけの、そんな代物ですw

    > 秀〇エディタさんやサク〇エディタさんでも使えないもので、

    そうなんですよね。なので秀丸、サクラを使うときがあったりすると、 ↑ のようなマクロを用意して使っていたりしました。

    > つまり、選択範囲がある場合は Ver 3.5.5 以前の仕様。選択範囲がない場合は Ver 3.6.7 の仕様と分ければ対応できそうな気がしてきました。

    そうですね。Ver 3.6.5 以前の選択状態でのアンインデントは、選択中のボトム位置が1列目の場合の動きがVSCodeとも遜色なかったと思います。なので、未選択の場合の動きだけ Ver 3.6.7 相当になると嬉しい感じになりそうです。

    > ですよね。未選択アンインデントって Sublime Text だとデフォルトで無効ですし、実装されると逆に使いづらくなってしまうというユーザーさんもいるのかしら。

    Sublime Textだと初期状態で無効なんですね…というか設定でOn/Offできるなんて仕様とは、初めて知りました…😳

    今まで開発系のテキストエディタだとVSCodeにIntelliJ、ノート系アプリだとObsidianやInkdropなど使ってきましたが、いずれも未選択アンインデントが使えるので(Markdownエディタなら当然の動きかもしれませんが…)、まぁそこまで異色な仕様ではないと思いますけれどねー。自分自身、未選択アンインデントが必需品の身なので、ちょっと「使いづらくなるケース」というのが想像できないですね…🤔

     |  yuko  |  返信
  26. > あ、いえいえ、そんな大層なものでなく、未選択時に SelectLine() をしてから Unindent() を呼び出すだけの、そんな代物ですw

    なんと…。私は一体、何と戦っていたのでしょう😱

    > なので、未選択の場合の動きだけ Ver 3.6.7 相当になると嬉しい感じになりそうです。

    単純に SelectLine() してから Unindent() するのを内部でやってみたら、if 文 2 個の追加で終わりました😂 簡単すぎて、逆に何か落とし穴がないか心配ではありますが。

    > Sublime Textだと初期状態で無効なんですね…というか設定でOn/Offできるなんて仕様とは、初めて知りました…😳

    調べてみましたところ、どうやら Sublime Text はデフォルトで Tab キーが [単語補完] で候補の確定に割り当てられているようで、候補の一覧が表示されている状態でタブ文字を入力したいとき、Shift + Tab を使うみたいです。

    "shift_tab_unindent" というオプションを true にすると、その仕様が上書きされて、アンインデントに割り当てられるっぽいです。

    > 自分自身、未選択アンインデントが必需品の身なので、ちょっと「使いづらくなるケース」というのが想像できないですね…🤔

    なるほど、Markdown エディターだとあたりまえの動作とのことで安心しました。

    Sublime Text のデフォルトでオフな件も、Mery の仕様だとあまり関係なさそうなので、「使いづらくなるケース」という心配はなさそうですね。

    とりあえず Ver 3.5.8 を作ったので、リリースしておきましょうか…。これで、心置きなく夏休みにはいらせていただきたいなーと😁

     |  Kuro  |  返信
  27. > 単純に SelectLine() してから Unindent() するのを内部でやってみたら、if 文 2 個の追加で終わりました😂 簡単すぎて、逆に何か落とし穴がないか心配ではありますが。

    シンプルに実現できるのはいいことですね👏

    ところで、今私が使っているアンインデントマクロの断片ですが、参考までに共有しておきます。
    もしVSCodeとより似た動作にするのであれば、以下のようなイメージで、「アンインデントによる文字数減少を考慮しつつ、未選択状態に戻す」という動作になるかなと思います。

    未選択状態に戻すことのメリットは、アンインデント後にすぐ入力に移れるところですね。
    インデント/アンインデントをしながらメモをするときには未選択状態に戻ってくれた方が、アンインデント直後の選択解除という1ステップが減らせるので便利だったりします。これは、Markdownのリスト表記をインデント~アンインデント~としながら書くような場面を想像すると分かりやすいかもしれません。

    とはいえ Ver3.5.8 の動作で特に不具合はないですし、それに標準仕様と違うものは今までどおりマクロで実現すればいい話ですから、そのうちお暇なときに仕様検討の末席にでも加えていただければと思います。

    サンプル:

    var sel = document.Selection;
    if (sel.isEmpty) {
        // 現在位置の取得
        var curPointX = sel.GetActivePointX(mePosLogical);
        var curPointY = sel.GetActivePointY(mePosLogical);
    
        // Ver 3.5.8 で不要になった
        //sel.SelectLine();
    
        // アンインデント前後の差分を取りつつアンインデント
        var beforeLength = document.GetLine(curPointY).length;
        sel.UnIndent();
        var afterLength = document.GetLine(curPointY).length;
        curPointX -= beforeLength - afterLength
    
        // カーソル位置の復帰
        sel.SetActivePoint(mePosLogical, curPointX, curPointY, false);
    }
    

    > 調べてみましたところ、どうやら Sublime Text はデフォルトで Tab キーが [単語補完] で候補の確定に割り当てられているようで、候補の一覧が表示されている状態でタブ文字を入力したいとき、Shift + Tab を使うみたいです。

    Shift+Tabでタブ入力とは、、、直感的に使いこなせる気がしないキーバインドですね、、、 (それゆえにオプションが用意されたのでしょうけど)

    > とりあえず Ver 3.5.8 を作ったので、リリースしておきましょうか…。これで、心置きなく夏休みにはいらせていただきたいなーと😁

    怒涛の修正作業、たいへんお疲れさまでした。
    夏も本気な時期ですから、熱中症にはお気をつけください。

     |  yuko  |  返信
  28. > ところで、今私が使っているアンインデントマクロの断片ですが、参考までに共有しておきます。

    ありがとうございます。アンインデントしたあとの選択状態については私も考えたのですが、結局、現状に落ち着きました。

    マクロを作られたとのことで、実は前回の返信のときに、選択状態の仕様についてもご意見をうかがいたく説明を書いていたのですが、あまりに文章が長くなりすぎたのでご迷惑かなと思い割愛してしまいました😅

    > 未選択状態に戻すことのメリットは、アンインデント後にすぐ入力に移れるところですね。

    そうなんですよね。アンインデントしたあとに未選択状態に戻す (選択範囲を維持する) エディターは VSCode、Sublime Text、E〇Editor さん。

    逆に、アンインデントしたあとは選択範囲を拡張して行選択にするのが秀〇エディタさん、サク〇エディタさんでした。

    VSCode 方式ですと、アンインデント後にすぐに入力に移れるというメリットはありますが、アンインデントしてからインデントしたいとき、Tab キーではインデントができないというデメリットもあります。

    秀〇エディタさん方式ですと変更した行が分かりやすいのと、Tab と Shift + Tab でインデントとアンインデントを自由に繰り返すことができるので、個人的にはそちらが好みでした。

    とはいえ、私はあまり Mery を使いこなしていないので、どちらの仕様が良いかはみなさんのご意見次第かなと思っています。

    > 怒涛の修正作業、たいへんお疲れさまでした。

    こちらこそ、検証作業のご協力と、貴重なご意見をありがとうございました。Ver 3.5 系はこれで打ち止めにしたいところです😓

    > 夏も本気な時期ですから、熱中症にはお気をつけください。

    お気遣いいただきありがとうございます。ほんと、暑いですよね。PC がポンコツなので暖房器具みたいです。yuko さんも暑さにお気をつけくださいませ。

     |  Kuro  |  返信
  29. Kuroさん、Ver 3.5.8 の開発お疲れさまでした。

    yukoさんが「未選択状態でもアンインデントできるマクロ」のサンプルを掲載されていましたが、MeryWiki のマクロライブラリにも「非選択状態でも逆インデント」という同じようなマクロが掲載されていたので、一応報告しておきます。
    (Ver 3.5.6 で Mery 本体に非選択状態でアンインデント機能が搭載されたので、マクロライブラリの一覧から除去してしまいましたが)。

    「非選択状態でも逆インデント」マクロ
    https://www.haijin-boys.com/wiki/非選択状態でも逆インデント

     |  MSY-07  |  返信
  30. すいません、分かりやすいかなと思ってURLをデコードしたらリンクが機能しなくなったので、再度リンクを張り直しますね。

    「非選択状態でも逆インデント」マクロ
    https://www.haijin-boys.com/wiki/非選択状態でも逆インデント

     |  MSY-07  |  返信
  31. > Kuroさん、Ver 3.5.8 の開発お疲れさまでした。

    ありがとうございます。今回の新機能、折り返しインデントはヤバかったですね。手を出すべきではなかったと思いました。

    > MeryWiki のマクロライブラリにも「非選択状態でも逆インデント」という同じようなマクロが掲載されていたので、一応報告しておきます。

    ご報告ありがとうございます。

    MeryWiki は、サーバーの管理はしていますが、みなさんが編集する内容については私の許可などは必要ありませんので、常識の範囲でご自由にお使いいただければと思います。

    他の方が登録されたマクロを勝手に削除しちゃうと、怒られてしまうのではないかなと心配になりますが…。

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