📝

previm で式やグラフが表示できる様になりました。

2022/06/15に公開

はじめに

previm は Vim で Markdown 編集する際にブラウザでプレビューできるプラグインです。
これまで plantuml と textile くらいしかサポートしていませんでしたが、katex や plolyjs 等をユーザ自身で追加できる様にしました。

https://github.com/previm/previm

経緯

以前から previm のメンテナをさせて頂いていたのですが、やはり Markdown で式やグラフを扱いたいというニーズは皆さんお持ちです。そしてその都度 pull-request が寄せられ、式やグラフ等を使いたくない人でも大きな previm に大きな変更が入り、ロード時間も長くなる事が懸念され、いずれの pull-request もマージできない状態になってしまいました。

また既存の markdown-it ライブラリのバージョン追従にも手間が掛かっていた為、気付けばどんどん古くなり、また手作業による更新作業の面倒さが起因してレビューにも時間が掛かってしまっていました。

結果的に pull-request は放置されてしまい、年単位で活動が無くなってしまいました。

アドオンな仕組み

今回 previm に動的にサードパーティライブラリを追加できる様にしました。他のメンテナの皆さんと協議なく、わずか1日で実施し master ブランチをお騒がせしてしまったので、申し訳なさがありますが、結果的に良い物が出来た気がするので勘弁下さい。

previm の基本的な動作は以下になります。

  1. PrevimOpen が実行された際にプレビューテンプレートをコピーする
  2. その際、css にユーザカスタマイズ css を追加するようパッチを当てる
  3. 更新用 js をロードする

今回はこの2の部分を拡張し、プレビューの html や js も動的にパッチを当てる様にしました。具体的には、vimrc で宣言したサードパーティライブラリのロード、ライブラリによるレンダリング処理コードの埋め込みです。

let g:previm_extra_libraries = [
\  {
\    'name': 'katex',
\    'files': [
\      {
\        'type': 'css',
\        'path': '_/js/extra/texmath.min.css',
\        'url': 'https://cdn.jsdelivr.net/npm/markdown-it-texmath/css/texmath.min.css',
\      },
\      {
\        'type': 'css',
\        'path': '_/css/extra/katex.min.css',
\        'url': 'https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.css',
\        'code': [
\          'renderMathInElement(document.body)',
\        ],
\      },
\      {
\        'type': 'js',
\        'path': '_/js/extra/katex-auto-render.min.js',
\        'url': 'https://cdn.jsdelivr.net/npm/katex@latest/dist/contrib/auto-render.min.js',
\        'code': [
\          'renderMathInElement(document.body)',
\        ],
\      },
\      {
\        'type': 'js',
\        'path': '_/js/extra/katex.min.js',
\        'url': 'https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.js',
\        'code': [
\          'document.querySelectorAll(''pre code.language-katex'').forEach(elem => {',
\          '  const html = katex.renderToString(elem.innerText, {',
\          '    displayMode: true,',
\          '    output: ''html'',',
\          '    throwOnError: false,',
\          '  })',
\          '  const span = document.createElement(''span'')',
\          '  span.innerHTML = html',
\          '  elem.parentNode.replaceWith(span)',
\          '})',
\          'document.querySelectorAll(''.inlkatex'').forEach(elem => {',
\          '  const html = katex.renderToString(elem.innerText, {',
\          '    output: ''html'',',
\          '    throwOnError: false,',
\          '  })',
\          '  const span = document.createElement(''span'')',
\          '  span.innerHTML = html',
\          '  elem.replaceWith(span)',
\          '})',
\        ],
\      },
\    ],
\  },
\]

html には type の値が css なエントリの path を link タグに追加し type の値が js なエントリの path を script タグで追加しています。なお code は Markdown のレンダリング前に実行される様に埋め込まれます。

一括更新

今回のこの変更を入れる際に、ライブラリの minify js を更新できる仕組みもいれました。設定の url が使われます。

:PrevimUpdateAssets

このコマンドを実行すると全てのライブラリを一括更新できる様にしてあります。これでメンテナとしての作業が随分楽になります。

独自コード

js のコードは url や path が無くても差し込める様にしてあるので、例えば

\  {
\    'name': 'my customize',
\    'files': [
\      {
\        'type': 'js',
\        'code': ['// あやしいコード'],
\      },
\      {
\        'type': 'css',
\        'style': ['body {background-color: gray}'],
\      },
\    ],
\  },

この様なコードも実行できるので、お好きなカスタマイズを入れて頂けるようになりました。

画面

今回の対応によりプレビュー画面が随分とリッチになりました。

この様な Markdown のプレビューが以下の様になります。

emoji、katex、plolyjs を使っています。設定方法は previm の Wiki に書いてあります。

おわりに

今回 previm に入れた以下の2点により、停滞してしまっていた previm が復活できたと思います。

  • サードパーティライブラリのロード
  • ライブラリの一括更新

こうならない為にも、ユーザカスタマイズ要件には早めに重い腰を上げて対応した方が良い、という気付きを得ました。

気付けば沢山溜まっていた pull-request が昨日だけでゼロになりました。めでたしめでたし。

Discussion