notebook

都内でWEB系エンジニアやってます。

ObsidianのTemplaterでTable Of Contentsを差し込み、更新するテンプレート

ObsidianのTemplaterネタ

Markdownファイルのコンテンツの中身を見て見出しのリスト(Table Of Contents)を作成する

すでに作成されている場合はTOCを最新状態に差し替える

毎度のことながら作ったテンプレートスクリプトをホットキー設定に追加することで実行可能になる

サンプルでの実行結果

>[!info]- 目次
>  - [見出し1: 概要](#見出し1%20%20概要)
>  - [見出し2: 詳細](#見出し2%20%20詳細)
>    - [サブ見出し2.1: 背景](#サブ見出し2.1%20%20背景)
>    - [サブ見出し2.2: 現状](#サブ見出し2.2%20%20現状)
>  - [見出し3: 結論](#見出し3%20%20結論)

## 見出し1: 概要

このセクションでは、サンプルドキュメントの概要について説明します。

## 見出し2: 詳細

このセクションでは、サンプルドキュメントの詳細な情報を提供します。

### サブ見出し2.1: 背景

このサブセクションでは、背景情報を説明します。

### サブ見出し2.2: 現状

このサブセクションでは、現状について詳述します。

## 見出し3: 結論

このセクションでは、サンプルドキュメントの結論をまとめます。

行の先頭が>の行がTOC

こんな感じになる

コード

  • templates/toc
<%*
  const tocRegex = /^>\[!info\]- 目次.*$(\n^>.*$)*/m;
  const toc = ">[!info]- 目次\n" + tp.file.content.split("\n")
        .filter(line => line.match(/^#+\s/))
        .map(line => {
            const level = line.split(" ")[0].length;
            const title = line.substr(level+1);
            const link = `[${title}](#${title.replace(/[ %\[\]]/g, (m) => encodeURIComponent(m)).replace(/[:|#]/g, "%20")})`;
            return ">" + "  ".repeat(level-1) + `- ${link}`;
        }).join("\n");

  if (!tp.file.content.match(tocRegex)) {
    return toc
  }

  const replacedContent = tp.file.content.replace(tocRegex, toc);
  const editor = app.workspace.activeLeaf.view.editor;
  editor.getDoc().setValue(replacedContent);
%>

目次用途での使用であれば、1つのMarkdownファイルにTOCは1つあればよい

なので既存のファイルから>[!info]- 目次という文字列を探し、マッチした場合はその行を含む>で囲われたブロックすべてを現状の状態から生成したTOCでリプレイスする

TOCが存在しない場合はカーソル下に生成したTOCを挿入する

TOCの中身自体は見出しのレベルによってインデントを変えてリスト化しているだけ

以降でポイントやはまったところを掘り下げる

URLエンコード

いくつかサンプルを試していたらスペースが見出しに含まれる場合リンクが機能しなかった

Obsidianでのリンク記法のドキュメントは下記

Internal links - Obsidian Help

help.obsidian.md

リンク先は必ずURLエンコードしてねというふうに書いてあった

見出しにスペースが含まれている場合はURLエンコードしてあげればしっかりリンクとして認識してくれた

ということで、素直にencodeURIComponentで文字列すべてをURLエンコードしてみたら、それはそれでうまく機能しないリンクがあった

色々試した結果、下記の場合リンク先とリンク元が同一と判断されずリンク先に飛べないよう

  • マルチバイト文字列をURLエンコードした場合
    • URLエンコードしないことにした
  • :,#の記号をURLエンコードした場合
    • :,#はObsidian上のリンクでは%20(スペース)として判断されていた(wikiリンクの設定を外してサジェストでリンクを生成させて確認した)
    • 他にもいくつかスペースとしても判断される記号があった、しかし記号のままでもリンクが機能したため変換対象からは除外した
    • :,#に関してはリンク先の文字列に含まれている場合Externalリンクとして判断されるよう、これはObsidianの仕様に見えるので素直にスペース(%20)に変換する処理を入れた
  • 一部の記号が見出しに含まれる場合
    • スペースや%はURLエンコードしないとリンクが機能しなかったため変換対象とした
    • [,]はURLエンコードエンコードしないと見た目が変になってしまうため変換対象とした

この辺の事情がリンクの文字列生成のコードに含まれている

Callouts

GitHubにも似た機能があるが、特定の書き方でコンテンツ上に意味をもたせたることができる

Callouts - Obsidian Help

help.obsidian.md

>![info]と先頭に書くことで該当行からのブロッククオート範囲のブロックは装飾される

結構種類があるようなので覚えておけば色々活用できる場面があると思う

>![info]-というように識別子のあとに-+をつけると情報が折りたためる

-の場合は折りたたまれた状態がデフォルト、+の場合は展開された状態がデフォルト

おわり

あまりエッジケースを想定しないパターンで以前から活用してたのでブログネタになるかなと思って記事書きだしたら色々不備が出てきて調べてたらかなり時間使ってしまった

勉強にはなったので結果オーライ

良ければ活用してみてください