思源笔记 Typst 插件发布

思源笔记目前只支持 KaTeX. 然而,Typst 发展至目前阶段,已经具备了内嵌渲染 Inline Math 的能力。

Ref: Issue #10301 · siyuan-note/siyuan https://github.com/Myriad-Dreamin/typst.ts

本文将简述思源笔记 Typst 插件的开发。

Q: 为什么不使用挂件块?
A: 挂件块无法支持 Inline Math.

初始化项目

使用 https://github.com/frostime/plugin-sample-vite-solidjs 作为模板。

不过后来发现根本就没有用上 solidjs,基本上是纯 TS 项目,拿个 vite 就行了。

核心功能开发

曾经考虑的方案是用挂件块或者类似的形式,但目前思源笔记并不支持自行拓展 Inline 的自定义块。

这意味着我们没有任何办法用合法方式自行渲染行内元素,也没有办法为行内元素直接保存数据。

经过了一番考察,最终选择的技术方案是:使用思源原生的 Math Block,在 KaTeX 完成渲染(出错)后加一个 Pass 去用 Typst 渲染。

如果能 Fork SiYuan,直接改 mathRender 函数是最方便的,但 Typst Renderer 带上 Compiler 在 10MB 以上,对于大部分用户来说比较浪费。持续维护两套渲染机制对上游来说或许也是一个问题。总之先以插件的形式实现一下。

Render Node 会将 Data Content 保存在自己的 DOM Attribute 中,我们可以直接从 DOM Tree 上拿到 Math Block 真正的数据。

image

每次输入后,编辑器会重新渲染当前更新的块,这意味着整个 DOM Node 都是非持久化的,由数据驱动,唯一持久的是 data-content.

我决定使用语法 \t{typst content} 来表示 Typst Math Block,对于行内公式和行级公式使用相同的表达。筛选理论上可以通过一个 selector 完成:span[data-type='inline-math'][data-content^='\\\\t{'][data-content$='}'],不过实际上为了性能还是稍微做了一些更复杂的更新逻辑:

使用 Observer 监听整个 Editor,遍历每一个 Mutation. 如果当前在某个块中输入,更新后该块会重新渲染并触发 Mutation. 可以通过 Mutation Target 来获取到相应的 DOM Element,随后自行渲染。

对于 Copy & Paste 的场景,需要考察 Mutation 的 addNodes 来做更新。

总之更新大概就是这样。最终的性能开销是:

  1. 在块内编辑时,当前块、当前块中的 Inline Math 会被扫描一遍并识别是否 Typst Content,若否则跳过。否则渲染。
  2. 在 Copy & Paste 时,使用 Query Selector 查找出 Typst Content 随后渲染。

行内公式过多时,每次都重新渲染会出现严重的性能问题。因此添加了一个简单的 LRU Cache,用于缓存最近渲染完成的 Typst Content. 这样编辑的流畅性就有保证了。

渲染的 Style 需要一些调整。这部分参考了 Rehype Typst,Inline 调整 baseline position,Display 的话选择了直接借用思源内部 KaTeX Display 的样式包了一层。使用 Shadow Root 避免生成的 Style 溢出污染 Scope,然后适配一下 Light/Dark mode,不幸的是现在只做了黑色和白色,对上色样式没有支持。

有点怀疑 typst.ts 存在某种内存泄漏的问题,在连续渲染数百次后会出现严重的 Performance Regression,换成了手动创建 Compiler/Renderer 也还是存在。最终选了做了一个类似 Double Buffer 的机制,每使用当前 Compiler 若干次后就直接切备用的 Brand New Compiler 并且重新创建一套。这会导致 Switch Compiler 出现一定的性能抖动,但测试了一圈感觉还好。

修改了 DOM Tree 后,被识别为 Typst Content 的 DOM Node 在后续不再是 Typst Content 时,仍然会保留相应的 Shadow Root 而无法正确显示 KaTeX 内容,因此多加一个不再是 Typst Content 时的 Cleanup,删掉自己加上的那些结构。

效果演示

总之就是凑合能用吧。

image

插件已提交集市准备上架,代码开源于 GitHub.

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    28446 引用 • 119790 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...