
## やりたいこと
[[Obsidian]] で、アウトライン機能を用い、複数レベルのリストをよく作成します。そして「特定レベルより深い階層を一括で折りたたむ機能」があると便利だろうなと感じていました。
以前、org-modeを使用していたときは「C-{n} S-Tab」のキーバインドで行えて便利でした。
この願いを前進させる手がかりとなったのは、 [📘Templaterでoutlinerを強化](https://masaki39.github.io/Templater%E3%81%A7outliner%E3%82%92%E5%BC%B7%E5%8C%96) という記事でした。この記事のおかげで、実現する方法が見えてきました。しかし
- わたしのリストは、タブとスペースをインデントに混在させてしまっている
- Templaterを使うとカーソル行のあとに空白行が入ってしまう
という問題がありました。

<span class="mxt-caption"> ▲ 今となっては経緯不明だが、タブとスペースが混じった運用になってしまっている……</span>
## 原因と対策1:空白行が入ってしまう
Templaterを使うと、空白行が入ってしまう原因は、わかってしまえば簡単なことでした。
ダメなtemplater.md:
```templater.md
<%*
......
%>
← この空行がダメ
```
ヨイtemplater.md:
```templater.md
<%*
......
%>
```
> [!tip] Templaterは、xxx.mdを挿入するので、空行があると、空行を挿入してしまうのでした。
## 原因と対策2:タブとスペースの両対応
下記コードで決着しました。
```javascript
<%*
const tabSize = 4;
const lines = tp.file.content.split(/\r?\n/);
const text = await tp.system.suggester(
["Fold to Level 1", "Fold to Level 2", "Fold to Level 3", "Fold to Level 4", "Unfold"],
["1", "2", "3", "4", "99"]
);
if (!text) {
return;
}
const targetLevel = parseInt(text, 10);
// console.log(`Target Level: ${targetLevel}`);
lines.forEach((line, index) => {
app.workspace.activeLeaf.view.editor.setCursor(index, 0);
app.commands.executeCommandById(`obsidian-outliner:unfold`);
});
lines.forEach((line, index) => {
let level = 0;
const matchTabs = line.match(/^(\t*)-/);
const matchSpaces = line.match(/^( *)-\s*/);
if (matchTabs) {
level = matchTabs[1].length + 1;
} else if (matchSpaces) {
const leadingSpaces = matchSpaces[1].length;
level = Math.ceil(leadingSpaces / (tabSize)) + 1;
}
// console.log(`Ln ${index+1} Lv ${level}, Contents: ${line}`);
if (level == targetLevel) {
app.workspace.activeLeaf.view.editor.setCursor(index, 0);
app.commands.executeCommandById(`obsidian-outliner:fold`);
// console.log(`Fold Ln ${index+1} Lv ${level} Tg ${targetLevel}: ${line}`);
}
});
%>
```
> [!note] 折りたたみコマンドを `obsidian-outliner:fold` に変更しました。@ 2024-03-23(土)
- タブにせよスペースにせよ、その行のインデントレベルを求めます。
- 指定のレベルの行を、折りたたみます。
- 折りたたみ解除もできるようにしました。

<span class="mxt-caption"> ▲ 個人的にはレベル3まででいいかも。折りたたみ解除が思ったより便利</span>

<span class="mxt-caption"> ▲ タスクリストも、今は見たくないFutureが折りたたまれていると心安らか(左が折りたたみ後)</span>
## 備忘録:Templaterの使いかたのキホン
Templaterをふだん使わないので、いちばんのキホンを忘れていました。
便利記事:[Obsidian Templaterスクリプトのまとめ(暫定版) - Jazzと読書の日々](https://wineroses.hatenablog.com/entry/2023/03/18/110031)
- 指定フォルダに、テンプレートファイル(.md)を作成する。
- リボンのTemplaterボタンを押すと、テンプレートファイルを選べる。
- テンプレートファイルに、Javascriptを埋め込める(`<%* ... %>`)
- テンプレートファイルにホットキーを割り当てることもできる。
- Templater設定で、ホットキー割り当て対象にする
- ホットキー設定で、キーを割り当てる
> [!danger] リボンのボタンを消しているので、すっかり存在を忘れていました。
## 備忘録:スクリプト作成のコツ
- console.logを使ってデバッグ(opt + cmd + I)
- ひとつひとつ実装する
- 今回の場合、行ごとのレベル判定→レベルごとの処理(折りたたみ)
- consoleで `app.commands` と打てば `app.commands.executeCommandById()` で使うコマンドを探せる
- 出典:[📕Templaterでよく使うコマンド・スニペット - Minerva](https://minerva.mamansoft.net/Notes/%F0%9F%93%95Templater%E3%81%A7%E3%82%88%E3%81%8F%E4%BD%BF%E3%81%86%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%BB%E3%82%B9%E3%83%8B%E3%83%9A%E3%83%83%E3%83%88)
> [!smile] 今週は忙しかったし、かなりストレスフルだったので、ちょうどよい気晴らしになりました