Language Serverの仕組みに乗っかればscrapboxっぽいwikiをvimで実現できる

scrapboxみたいなwikiを好きなエディタ(vim)で編集したい。 そこでLanguage Serverとして作った。

github.com

こんな感じ(ちょっと長めの動画。2倍速でどうぞ):

youtube video

syntax

scrapboxpythonに大いに影響を受けている。 全ての文章が箇条書きで、タブ文字で右にシフトして入れ子的にリストをつくっていく。

地の文。
改行は改行として扱う。
    タブ文字でインデントするとリストができる
        ネストしてもよい
    2こ目の要素
    [@quote]
        引用するときはこんな風に。
        一段インデントする。


装飾:
    [* 太字]はこう。
    [/ イタリック]はこう。
    [*/ 太字イタリック]はこう。

リンク:
    [wiki内リンク]
    [https://google.com google]
    [google https://google.com] タイトルとURLはどっちが先でも可。
    [@img https://via.placeholder.com/50 width=100 height=100] 画像はこう。
    [@img https://via.placeholder.com/50 "altテキストもいれていいよ"] altテキストとurlの順番も入れ替え可。


コードハイライトはhighlight.jsがやってくれる
    [@code python]
        import numpy as np
        print(np.sum(10))
    [` インラインコードはこう `]

数式はkatexにお任せ
    [@math]
        O(n^2)\\
        sum_{i=0}^{10}{i} = 55
    インライン数式はこう: [$ O(n log(n)) $]

テーブルもタブで区切ってね
    [@table]
        hoge    fuga
        piyo    asdf

preview画像。なぜか画像が荒い

実装

pythonに慣れてるのでpythonで。 pyinstallerにかければ実行ファイルも簡単にできる。 パースはgrammarを定義すればlarkがよしなにやってくれる。 lspについては、最近はべんりなものでgeneric language serverなるものがあり、 ベースの実装にちょっと書き足すだけでLanguage Serverになる。 github.com

僕はそこにrendererもくっつけた。 なぜならrendererのwikiリンクをクリックしたらエディタ側もそのテキストを表示してほしいし、 それをするには双方向の通信が必要で、lspの仕組みにのっかるのが楽だったから。 lspにのっかっておけば他のエディタでも使える。 completionもdiagnosticsも簡単に出せる。

無論Zettelkastenに対応した。Language Serverは起動するとフォルダ内のファイルをスキャンしてグラフを作る。 [を入力するとグラフ内のページが補完される。 プレビューアの下部にはバックリンクが表示される。 これが欲しかった。

動画には入れてないけれど、zoteroのデータベースを指定するとzoteroのアイテム補完もできるようにした。べんり。

なんでmarkdownじゃないの

markdownが好きじゃないから。flavorやextensionによって挙動が異なるせいで、

  • 改行は改行と認識されるのか?
  • インデントしたときcode blockもインデントも揃えないといけないのか?
  • quote内の改行は改行として扱われるのか?
  • mathの記号はどれか?
  • リストの前に改行は必要か?

などと書いてる最中に気になることが多すぎて、何を書こうとしていたのかわからなくなって、書く気力が削がれてしまう。 二つ目のcode blockが特に嫌いで、例えば

- 箇条書きの中でコードスニペットを書こうとする
    - こんなふうに:
    - ```python
      def fn(arg):
          print(arg)
      print(fn('asdf'))
      ```
    - 箇条書きの続き

のように書こうとすると、3行目のコード片のところでインデントを揃えるためには"- "の二文字のせいでたくさんスペースを手で打ちまくる必要がある。 そもそも箇条書き中のcodeはmarkedjs等では書けるのにobsidianでは書けない。 ポータブルなマークアップ言語とはなんだったのか。

obsidianでのコードスニペットの認識のされ方の画像。箇条書きの中ではcodeとして認識されなくなる。
obsidianでは箇条書き中のcode snippetはうまく認識されない

逆に自作しちゃえば実装==仕様になる。フフン*1

そんなわけわからん言語にロックインされる方がよくないのでは

現状markdownへのexportが可能。 文法の機能的にはmarkdownやその他言語の下位互換なので、ちょっとrendererを書けば簡単に移行できるのでヨシ。

これから

とりあえず常用するには困らない分だけ実装したところで、lspの実装できてないところはたくさんある。 めんどくさくなってvim plugin側で書いてしまったところもある(DocumentLinkとか←対応した)。 vscode extensionの実装も途中で止まってしまっている。←とりあえず動いた。 ちょっとずつ進める予定→issues

*1:フフンではない。現状specはガバガバである