Vimでmarkdownをプレビューするプラグインを作った

kat0h

kat0h

20211206に作成
この記事は最終更新から1年以上が経過しています

VimでMarkdownをプレビューするプラグインを作成しました(この記事は9月にZennに投稿した記事と同じテーマです)

9月頃からbufpreview.vimというVim向けのプラグインを作成していました。

GitHub - kat0h/bufpreview.vim: A markdown previewer for Vim and Neovim

A markdown previewer for Vim and Neovim. Contribute to kat0h/bufpreview.vim development by creating an account on GitHub.

github.com

Vim向けのMarkdownプレビュープラグインは過去にも存在していましたが、このプラグインは下記のような特徴をもっています。

  • Typescriptで記述されたVimとは独立して動作する高速なサーバー
  • nodejs製プラグインで必要だった依存関係のインストールが不要
  • Github風のMarkdownレンダリング(yamlヘッダのレンダリングも含めて)
  • 入力の即時反映
  • カーソル位置とブラウザーの表示位置の同期

この記事はそれぞれの特徴について解説します。

Typescript製サーバー

このプラグインはdenops.vimを利用してTypescript実行環境であるDenoとVimを繋げ、通信しています。

GitHub - vim-denops/denops.vim: 🐜 An ecosystem of Vim/Neovim which allows developers to write cross-platform plugins in Deno

🐜 An ecosystem of Vim/Neovim which allows developers to write cross-platform plugins in Deno - GitHub - vim-denops/denops.vim: 🐜 An ecosystem of Vim/Neovim which allows developers to write cross-...

github.com

Websocketでブラウザー間とJsonをやり取りしているので、Vimの状態を即座に反映することができます。

nodejs製プラグインで必要だった依存関係のインストールが不要

この特徴はhttps://github.com/iamcco/markdown-preview.nvimにあるものです。

GitHub - iamcco/markdown-preview.nvim: markdown preview plugin for (neo)vim

markdown preview plugin for (neo)vim. Contribute to iamcco/markdown-preview.nvim development by creating an account on GitHub.

github.com

bufpreview.vimはmarkdown-preview.nvimの挙動を参考にして作成しました。非常に使い心地の良いプラグインでお勧めなのですが、nodejs製のプラグインであるため起動前に依存関係をインストールする必要があります。 依存関係の解消に(多少)手間がかかることは気軽に使うにあたって問題になることがあるかもしれません。

bufpreview.vimではサーバにDenoを使用しているため、依存関係が自動でインストールされます。

Github風Markdownレンダリング

Markdownの仕様は核レンダラーごとに様々であり、混沌とした状況になっています。 このプラグインではレンダラーにjavascript製Markdownレンダラーのmarkdown-itを利用し、各種プラグインを取り入れおおまかにGFMを再現するようにしています。

GitHub - markdown-it/markdown-it: Markdown parser, done right. 100% CommonMark support, extensions, syntax plugins & high speed

Markdown parser, done right. 100% CommonMark support, extensions, syntax plugins & high speed - GitHub - markdown-it/markdown-it: Markdown parser, done right. 100% CommonMark support, extension...

github.com

また、Markdownの先頭にyaml形式の情報を付けるyamlヘッダのレンダリングにも対応しています。これは他のMarkdownレンダラにはない特徴です。 この機能を実現するためにmarkdown-it-yaml-headerというmarkdown-itプラグインを作成しました。(まだmainで利用していませんが。。)

GitHub - kat0h/markdown-it-meta-header: markdown-it plugin to render github like yaml header

markdown-it plugin to render github like yaml header - GitHub - kat0h/markdown-it-meta-header: markdown-it plugin to render github like yaml header

github.com

esm.sh

このプラグインではMarkdownのレンダリングをブラウザーで行なっています。普通nodejs向けに作られたライブラリはそのままブラウザーで読み込むことができません。 そこで、esm.shというnpmに公開されているモジュールをESModuleとして変換してくれるCDNを利用しています。これを利用することでブラウザーから下記の例のようにnpmが提供するライブラリを読み込めます。

<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/github-markdown.min.css"> </head> <body> <textarea id="text" style="height: 162px; width: 250px"></textarea><br> <button type="button" onclick="render()" label="Render"> Render </button><br> <div class="markdown-body" id="body"> </div><br> <script type='module'> import MarkdownIt from "https://esm.sh/markdown-it?bundle" const md = new MarkdownIt(); const render = () => { var text = document.getElementById("text").value; text = text == null ? "" : text; const body = document.getElementById("body"); body.innerHTML = md.render(text); } window.render = render; window.md = md; render(); </script> </body> </html>

ブラウザーからESModuleを利用するには<script type='module'></script>としてjavascriptを記述する必要があります。また、moduleとして記述したjavascriptはstrictモードで読み込まれます。注意してください。(一敗)

ESModuleを利用することで、HTML一枚のみで様々なライブラリを管理しやすく実装することができました。(この仕組みがなければ、ここまでシンプルに依存関係を管理できませんでした)

入力の即時反映

Vimとサーバーをwebsocketで常時接続しているため、Vimへの入力はブラウザーへすぐに反映されます。

カーソル位置とブラウザーの表示位置の同期

markdown-itのプラグインである、https://github.com/digitalmoksha/markdown-it-inject-linenumbersを利用して入力行とレンダリングされた結果を対応させています。

GitHub - digitalmoksha/markdown-it-inject-linenumbers: Insert line numbers to support sync scrolling for the markdown-it parser.

Insert line numbers to support sync scrolling for the markdown-it parser. - GitHub - digitalmoksha/markdown-it-inject-linenumbers: Insert line numbers to support sync scrolling for the markdown-it ...

github.com

今後

現状bufpreview.vimはmarkdown-itを利用したmarkdownのレンダリングのみにした対応していません。 現在任意のレンダラーを追加して利用できる仕組みを実装しようとしているのですが、仕様を考えるのが難しく未だ実装できていません。

任意のレンダラーに対応できるようになれば

  • Markdown -> スライド
  • 小説
  • markdown-it以外のレンダリングエンジンに変更 などかなり柔軟に使えるようになると考えています。

SHARE


kat0h

kat0h

高専ではない

kato