秀丸エディタで折りたたみを手軽で便利に拡張する（再帰、トグル、範囲）

# 概要
- 秀丸は高度な折りたたみ機能を持っています。
- 一方で、アウトライナー（アウトラインプロセッサ）にあるような手軽で便利に折りたたむ機能はついていません。
    - 例えば、`トグル` & `再帰的な折りたたみ/展開` & `範囲選択した場合は折りたたみ/展開可能な場所を探して実行`、をショートカットキーひとつ（例えば `SHIFT+CTRL+「.」`）で手軽にできると便利です。[^1]
    - 本記事はそれを可能にする方法を提供します。
[^1]: 例えば[DynaList の Expand/collapse all](https://help.dynalist.io/article/91-keyboard-shortcut-reference)のような

# 説明
- プレーンテキストを読み書きするとき、
    - 折りたたみ/展開できると楽なことがあります。
- アウトライナー等のアプリによっては、以下のようなことが可能です。
    - ショートカットキーひとつで折りたたみ/展開できる。（例えば `SHIFT+CTRL+「.」`）
    -  トグルでできる。折りたたみ済みなら展開し、そうでないなら折りたたみ。
    -  再帰的に折りたたみ/展開できる。つまりネストした階層があるとき、浅い階層から深い階層まですべて折りたたみ/展開できる。
    - トグルと再帰は、VS Codeで例えると、 `CTRL+K CTRL+[` と `CTRL+K CTRL+]` （再帰的な折りたたみ/展開）を、トグルで行うイメージです。
    -  範囲選択した場合、最上位階層が複数あっても、まとめて折りたたみ/展開できる。
- 秀丸エディタでそれを実現するには、マクロを作成してショートカットキーに割り当てればOKです。
    - なおマクロなしの場合、秀丸エディタは、
        - ショートカットキーが割り当てられていません
        - トグルができません
        - まとめて折りたたみ/展開、ができません
            - 再帰的に（深い階層をまとめて）、ができません
            - 選択範囲をまとめて（最上位階層を複数それぞれ）、ができません
            - （選択範囲を単純に1つの階層として折りたたむことはできます）
            - （ファイル全体を対象にする折りたたみ/展開はできます）
- 掲載したマクロは、
    - トグルができます。
    - 再帰的に折りたたみ/展開できます。
    - 範囲選択した場合、範囲内に最上位階層が複数あればそれぞれ折りたたみ/展開できます。
    - 構造化ルールは `インデント` と `括弧` と `アウトライン解析で検出された構造` としています。
        -  `#foldcond` で設定しています。詳しくは、`秀丸エディタ マクロ言語ヘルプ目次`をweb検索いただき、`fold`の説明をご一読ください。
        - うまく動作しない場合
            - まず秀丸エディタ設定 `アウトライン解析の設定` をご確認ください。
                - `ファイルタイプ別の設定/アウトライン/解析` にあります。
                -  インデントよりも優先されて適用されるようです。
                    -  インデントを優先する方法はわかりませんでした。
                -  もし `アウトライン解析で検出された構造` を対象外にしたい場合、`#foldcond`から`0x0020`を外してみてください。
            - また、`#foldcond`から`0x0002`や`0x0008`を外すこともお試しください。
        - カスタマイズ（ルール変更）はおそらく楽ですので各位お試しいただければと存じます。            
            - インデントで構造化したファイルと、インデント以外で構造化したファイル、などで構造化ルールを切り替えたいとき、
                - 拡張子等のファイル情報を元に `#foldcond`を動的に変更するのも手かもしれません。
                - マクロでメニューを用意する等して、構造化ルールを切り替えるのも手かもしれません。
    - VS Codeの「トグルでない再帰」を実現したい場合、カスタマイズが必要です。おそらく楽ですので各位お試しいただければと存じます。

# 主な想定読者
- 構造化テキストの読み書きをもっと楽にやれないか、
    - 各種アウトライナーや各種アプリを試した人
    - アプリによっては、範囲選択可能で再帰的に折りたたみ/展開トグルがショートカットキー一発（`SHIFT+CTRL+「.」`等）でできるのを知り、それが秀丸でもほしくなった人
- なお、このマクロの初期設定は、構造化をインデントで行っていますが、
    - カスタマイズできるため、ほかの構造化にも対応可能と考えます。

# 秀丸マクロ
- 筆者は、`SHIFT+CTRL+「.」`に割り当てて使っています。

```js:fold_unfold_all_toggle.mac
// 折りたたみと展開 all toggle
//  カーソルのある位置の配下をすべて折りたたみます。そこが折りたたまれていた場合、すべて展開します。
//  範囲選択していた場合、そこを対象にします。
#foldcond = 0x0002 + 0x0008 + 0x0020; // 0x0040は外す。用途に合わない。selectfoldable の範囲外も巻き込んでしまう。0x0004はソース先頭で操作したときソース全体をトグルしたいなら外す。

disabledraw; // 高速化用

if (selecting) {
  // 範囲選択中の場合、選択範囲内にfoldedがあるかで分岐する
  #y0 = seltopy;
  #y1 = selendy;
  escape;
  call searchFolded #y0, #y1;
  #isFolded = ##return;
  if (#isFolded) {
    moveto 0, #y0;
    call unfoldUnder #y0, #y1;
  } else {
    call foldUnder #y0, #y1;
  }
} else {
  if (folded) {
    // 単純展開し、配下を範囲選択し、その範囲を展開する
    unfold;
    selectfoldable #foldcond;
    #y0 = seltopy;
    #y1 = selendy;
    escape;
    call unfoldUnder #y0, #y1;
  } else {
    selectfoldable #foldcond;
    #y0 = seltopy;
    #y1 = selendy;
    escape;
    if (#y1 - #y0 == linecount - 1) {
      // [用途] カーソルがファイル先頭にあるとき、折りたたみ / 展開 をtoggleする用。全選択折りたたみ直後に、全展開する用。
      call searchFolded #y0, #y1;
      #isFolded = ##return;
      if (#isFolded) {
        moveto 0, #y0;
        call unfoldUnder #y0, #y1;
      } else {
        call foldUnder #y0, #y1;
      }
    } else {
      call foldUnder #y0, #y1;
    }
  }
}

enabledraw; // 高速化用
endmacro;

searchFolded:
  ##y0 = ##1;
  ##y1 = ##2;
  moveto 0, #y0;
  while (1) {
    down;
    if (folded) return 1;
    if (#y1 <= y) return 0;
  }
  return 0;

foldUnder:
  ##y0 = ##1;
  ##y1 = ##2;
  moveto 0, #y1;
  while (1) {
    up;
//    message "before :" + str(y) + " foldable:" + str(foldable);
    if (foldable(#foldcond)) fold #foldcond;
    if (y <= #y0) break;
  }
  return;

unfoldUnder:
  ##y0 = ##1;
  ##y1 = ##2;
  moveto 0, #y0;
  while (1) {
    down;
//    message "before :" + str(y) + " foldable:" + str(foldable);
    if (#y1 <= y) break;
    unfold;
  }
  moveto 0, #y0;
  return;
```

# 1階層トグルのみの秀丸マクロ
- カーソルのある行の1階層だけを、折りたたみ/展開 トグルだけするマクロです。
- 筆者は、`CTRL+「.」`に割り当てて使っています。
- VS Codeの `CTRL+K CTRL+L` に近いふるまいです。

```js:fold_unfold_toggle.mac
// 折りたたみ / 展開 toggle
/*
制約
  よくある「選択範囲を1階層折りたたみ」には対応できませんでした。
    イメージ：
      図1：
        aaa
          bbb
        ccc
          ddd
      を範囲選択して
      図2：
        aaa
        ccc
      にはできない
*/
#foldcond = 0x0002 + 0x0008 + 0x0020; // fold_unfold_all_toggle.mac と同じ条件にし、使っていてわかりやすくする

if (folded) {
  unfold;
} else {
  if (foldable(#foldcond)) fold #foldcond;
}
```

# マクロをショートカットキーに割り当てる方法は？
- 「秀丸 マクロ ショートカット」等でweb検索してください。