秀丸エディタで 1 ペインのアウトライナーを実現できない理由

アウトライナーは 2 ペインよりも 1 ペインが使いやすい(シームレスだから)が、秀丸エディタでは 1 ペイン型のアウトライナーを実現できそうにないことがわかった。試行の過程を書き殴っておく。

前提

  • 秀丸エディタ V8.58

現状の成果物

houtliner というブツとして公開している。

github.com

中身は強調定義ファイルとマクロのセット。「・」から始まる箇条書きをアウトラインと捉え、折りたたみやアウトライン枠などの機能を提供する感じ。

2 ペインのアウトライナーを一応実現できていると思う。

以下、実現にあたって欠かせないコアな部分を軽くまとめておく。

アウトライン解析の枠

秀丸エディタには「アウトライン解析の枠」というペインがある。

これは指定した書式に一致する行を「見出し」とみなし、その見出しを階層込みで目次のように表示するペインである。たとえば Markdown の見出しを実現するなら、「# ……」を大見出し、「## ……」を中見出し、というふうに解釈させる(指定は正規表現を使う)。

このペインを使えば、見出しの単位で目次を一覧表示できるため文章全体の視認性が向上する他、クリック一発で指定見出しにジャンプしたり、D&D で並び替えができたりもする。

折りたたみ

折りたたみとは、指定した書式に一致する行(が包含する部分)を丸ごと折りたたむ(表示上見えなくする)機能である。

これを使えば、たとえば「この大見出し以下の文章を折りたたむ」といった使い方ができる。1 ペインのアウトライナーを実現したいなら欠かせない。

すべて折りたたみ

これは折りたたみ操作を文書全体に適用する操作である。

ちなみに、レベルを指定した折りたたみはできない。たとえば「中見出し以下をすべて折りたたむ」といったことはできない。すべて折りたたみは、必ずトップレベル(大見出し)単位での折りたたみになる。

1 ペインに向けて

houtliner を元に、1 ペインのアウトライナーを実現しようと思う。

しかし道のりは険しく、そして潰えていることがわかった。順に見ていく。

ゴールを定める

まずは「何をしたら 1 ペインを実現したと言えるか」を定めたい。

以下三つを満たすもの、と定めよう。

  • (1) 任意のアウトラインについて、その配下を自由に折りたたみ・折りたたみ解除ができる
  • (2) 文書全体について、指定したレベルですべて折りたたみ・折りたたみ解除ができる
  • (3) 折りたたんだテキストを編集(たとえばコピペや並び替え)しても、折りたたみは解除されない

これだけ実現できれば、アウトライン解析の枠がなくても、十分アウトライン内を縦横無尽に行き来できる。

あとは、これら 1~3 をすべて実装するだけだ。

(1) 単体配下の折りたたみ

結論: 実現できる

というより、houtliner で既に実現できている。

マクロで言えば以下部分。

if(#si==#I_TOGGLE_FOLD){
    if(folded==1){
        unfold;
        endmacro;
    }

    // 0x0002 インデントの深さ

    // fold の挙動:
    //   if カーソル行が折りたたみ可能 → 折りたたむ
    //   if カーソル行が折りたたみ不可 → 折りたたみ可能行にジャンプ

    if(foldable(0x0002)){
        fold 0x0002;
        endmacro;
    }

    // ここに来た = 折りたたみ不可能.
    //   案1: fold x2 で直近の親で折りたたむ
    //   案2: 折り畳まない
    // 試用したところ, 案1 で直近の親にカーソルが移るのは煩わしいと感じた.
    // 案2で.
    /*
    // fold を二回行えば, 折りたたみ可能行にジャンプ → 折りたたむ, ができる.
    fold 0x0002;
    fold 0x0002;
    */
    endmacro;
}

細々としているが、要するに

  • もし既に折りたたまれているなら → 折りたたみを解除する
  • もし折りたたまれていないなら → 折りたたむ

上記が上手いこと動くように工夫しているだけだ。命令で言えば fold と unfold の二つを使うのみ。

(2) 指定レベルでのすべて折りたたみ

結論: 実現できない

すべて折りたたみを行うには foldall 命令を使うしかないのだが、この命令に「指定レベルでたたむ」的なパラメーターが存在しない。

if(#si==#I_FOLD_ALL){
  // 0x0002 → どんな表現を折りたたみ対象行とみなすかの指定(0x0002はインデントベース)
  // 0      → 確認ダイアログを出さない
  foldall 0x0002, 0;
  endmacro;
}

パラメーターは上記の二つだけである。

理想を言えば、以下二つの命令が欲しい。

// レベル3以下のみすべておりたたむ
foldall 0x0002, 3, 0;

// カーソル行が折りたたみ対象行として何レベルであるか(-1、0~n が返る)
foldlevel;

(3) 折りたたんだテキストが勝手に解除されない

結論: 実現できない

現状の秀丸エディタでは、折りたたんだテキストに対してコピペで並び替えをしたり、「前(後)の見出しに移動」で移動したりすると、折りたたんだテキストが勝手に開かれてしまうという仕様がある。

そして、これを制御する設定は、設定画面およびマクロ命令を一通り見た限りでは、存在しない。

理想は おりたたんだテキストは、ユーザーが明示的に解除しない限り、展開されない 仕様にすることだろう。アウトライナーにおいては「レベルnまで見る」といった用途でレベルn以下をすべて折りたたむ、という用途が多い。勝手に展開されては困るのだ。

ここまでの結論

以下理由により、秀丸エディタでは 1 ペインのアウトライナーは実現できない。

  • (2) 指定レベルでのすべて折りたたみ、に対応していないから
  • (3) 折りたたんだテキストが勝手に解除されない、を満たさないから

もう少し粘る

秀丸エディタの強みは「アウトライン解析の枠」だ。私も日頃からお世話になっているし、秀丸エディタから離れられない理由でもある。

仕方ないので、「アウトライン解析の枠」を使った 2 ペインベースで、1 ペインに近い使い心地を実現する 方向で頑張ってみることにする。

まずは「アウトライン解析の枠」の機能をチェック

まずは上記 3 要件が、枠の範囲内で実現できるかを調べてみる。調べてみた。結果は、

  • OK (1) 単体配下の折りたたみ
  • OK (2) 指定レベルでのすべて折りたたみ
  • NG (3) 折りたたんだテキストが勝手に解除されない

となった。勝手に解除される件以外は、実現できる。

……ひとまず (3) は諦めることとして、(1) と (2) のみ満たした妥協案の実現を考える。

(1) はカーソルキーで既にたためる。

(2) についても、実は実現できる。

以下の部分だ。

if(#si==#I_LV1){
    #ret = sendmessage(outlinehandle, 0x111, 7181, 0);
    endmacro;
}

if(#si==#I_LV2){
    #ret = sendmessage(outlinehandle, 0x111, 7182, 0);
    endmacro;
}

わかりづらいのでヘルプから抜粋する。

7181 ツリー表示:レベル1まで展開
7182 ツリー表示:レベル2まで展開
7183 ツリー表示:レベル3まで展開
7184 ツリー表示:レベル4まで展開

つまり レベル4までなら、指定レベル配下のみすべて折りたたむ を実現できる。houtliner にも既に搭載済だ。

ゴールを決める

もう一度ゴールを決める。

実現したいのは「2ペインでも、1ペインみたいに使えるアウトライナー」。

具体的には、私は vi の概念を取り入れることにした。

vi には モード がある。編集モードとコマンドモードがあり、これを切り替えて操作する。これと同じ概念を取り入れる。つまり、

  • 本文編集モード(文章編集)
  • アウトライン解析の枠操作モード(折りたたみはじめアウトライン操作)

この二つである。

「そんなの既に実現できているじゃないか」と思うかもしれないが、そうじゃない。vi がキー一つでモードを行き来できるように、秀丸エディタでもキー一発で行き来したい。 それくらいシームレスでなければ、1 ペインみたいに使える、は実現できないだろう

おそらくはキー割り当てを使うレベルでカスタマイズが発生するはずだ。しかし、不可能ではなさそうだ。

早速、実装をはじめた。

思わぬトラブルに遭遇

ここで思わぬトラブルに遭遇した。

アウトプット解析の枠の表示設定はグローバルで一つ、というものだ。

言うまでもなく、アウトプット解析の枠に表示する内容はファイルタイプ別ごとに異なるので、表示設定もファイルタイプ別に分離されているべきだが、実はそうなっていない。

アウトライナー用に表示内容を変えた(たとえば表示位置=上、表示領域も大きめ)とする。すると、他のファイルタイプにおける枠も同じ表示になってしまう。これは言うなれば「アウトライナーを実現したいなら、アウトプット解析の枠というグローバルな設定は私のためだけに使いなさい(他の設定は知らんがな)」である。

既に Markdown などでアウトプット解析の枠を使っている私としては、これは容認できない。せめてアウトプット解析の枠の表示状態をマクロで変えることができるならば、まだ手を打てなくもないが、そんなマクロはない。詰んだ。

さらに粘る

淡い期待をする。

「最新版では上記で挙げた機能が実はサポートされていたりする?」

というわけで覗いてみたのだが、

残念ながらその旨はなかった。

本当に詰んだ。

おわりに

というわけで、秀丸エディタで 1 ペインアウトライナーを実現する試みは潰えた。悔しい。