![DALL·E Serene Workspace.jpg](https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240322/20240322232657.jpg) ## やりたいこと [[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を使うとカーソル行のあとに空白行が入ってしまう という問題がありました。 ![SS 2024-03-22 22.56.08.png](https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240322/20240322225648.png) <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(土) - タブにせよスペースにせよ、その行のインデントレベルを求めます。 - 指定のレベルの行を、折りたたみます。 - 折りたたみ解除もできるようにしました。 ![SS 2024-03-22 23.06.01.png](https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240322/20240322230623.png) <span class="mxt-caption"> ▲ 個人的にはレベル3まででいいかも。折りたたみ解除が思ったより便利</span> ![SS 2024-03-23 0.02.58.png](https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240323/20240323000653.png) <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] 今週は忙しかったし、かなりストレスフルだったので、ちょうどよい気晴らしになりました