Article
编辑器实现的挣扎与思考
两个苦行僧憋了几年,从产品整体考量,技术选择从 Swing 迁到前端 Typescript ,再到现在的Flutter。不同语言写了几遍,每种语言上反复折腾又是几十遍,现在回头看,仍旧只是原型Demo级别的水准,还有巨多的特性要去实现完善。
作为其中小和尚的我,不是主导,半只脚在门内,半只在门外。从门缝中看这绚烂的时光,借此机会,说一说、理一理,自己在参与实现编辑器过程中积累一些头绪。
开始工作至今,从来没有写过这么多的注释!从来没有那么自觉的写注释!从写第一遍的光秃秃的代码,到现在的注释、文档和代码混杂在一起。每句注释都代表了一场战役,是战场上胜利凯旋的丰碑。败下阵来的,亦印着黄灿灿的TODO旗标,提醒自己还将回来再战。
在那些过不去的坎上,一遍遍反反复复的翻腾代码,就是定位不出问题,脑子里总有声音像摆钟一样来回的敲打着:为啥要自己写,有必要吗,真TND太难了,干啥子吗?!可一旦找出症结,解决问题,又莫名的开心起来,能改、能加、完全掌控的感觉确实好呀!
学习Word
当功能实现不确定怎么选择时,我们会去看Word是怎么处理的,参考它的做法。越是进入深水区,深入到细节,越觉得Word牛逼,每一处的细节都那么的无可挑剔:
换行符选择: 点击是点不到换行符的,但拖拽选取范围时能选中换行符。

上下标: 行内修改文本为上下标,行高是不变的(实质是行的高度跟字体有关,与上小标无关)。

段内行首光标样式: 它是跟随上一行最后一个字的样式的。

极度严苛
编辑器是一个容错空间极小的程序,不能多一点也不能少一分。比如在每一页容器上加1像素的边框:
border: pageless ? null : Border.all(width: 1, color: colorScheme.outline.withOpacity(0.5)),
那就多出的一个像素,就能让你的光标跑偏。放大后看下:

因为画(渲染)和算(排版)是两张皮,不同的逻辑,稍微差池就对不齐。并且还有部分元素是用组件去绘制实现的,所以,必须严格遵守排版计算后的位置,保持最终的一致。
光标的定位
我们用鼠标点击时,不会恰好都点在空隙处,多数情况都是点在文字上时,正常情况好处理:在前一半就左边,点在后一半就右边。
但特殊的是在行末,行末的字符索引它是表示两个位置的,这一行的最末和下一行的行首,眼睛直观来看,就是点那光标就放那咯,但写代码处理的话得写不少判断。
更复杂的是:
每一次输入文字和删除文字都要更新光标的位置和样式。
如果选择的是一个区间,光标就得隐藏掉。
在选中内容中间按下鼠标进行拖拽,还要实现拖拽光标,指示拖拽完后文本移动到的位置。
排版
在Flutter中,实现比typescript方便很多,可以拿到每行、每个字的位置,然后排版的textpainter直接用在渲染绘制中,不要太简单啦。
位置、高度、渲染三位一体,一步搞定?一开始,我们确实就是这样简单实现的。还正常的跑了一阵子!
后面,随着功能的追加:下划线、上下标、段落缩进等,一次次的重构,粒度度越来越细,最后行高自己算的,一行都拆成多个部分去画了。
模型
开始写编辑器之前,有去了解当前公开主流编辑器的实现,以及开源库的实现,不同之处主要聚焦:是把文本内容放文档树,还是用文本字符串加文本索引的两种实现方式。
写的第一版时刻,文本是放在TextRun里面的。在进行文本操作时,需要对文本块进行拆分,跨区块编辑样式时又需要进行合并,这些逻辑代码写的很艰涩。虽然不用考虑文本索引,但是在文档树上操作文本,代码逻辑比较复杂、难以维护。后面就改成把文本字符单独存储在一个字符串缓存里面。
那接下来就是看,TextRun的索引位置怎么记录的问题。有几种选择:记绝对坐标加长度,还是记相对坐标加长度,还有只记长度。三种都尝试了一次,最后选择了使用只记长度这种方式,为了弥补计算这块,父节点也记了长度,这样的话进行修改的时候,只需要修改当前节点长度,以及父节点的长度就可以了。使用计算换取存储的方式。
改到这里还没完呀。
在强调协同的时代,协作也是必选项。但是原来的模型是根据具体操作去设计的,比方说插入表格就是InsertTable、图片就是InsertImage,但这样,协同ot冲突就不好处理了。后面参考Quill的Delta,全部转成增加、删除、保留的操作,加属性的方式。模型一改,牵一发而动全身,基本上所有代码都要重新过一遍,并且业务逻辑是基本完全重写,能复用的也就是交互的部分代码。
新征程
这些只是过程中印象极度深刻的几个片段。写编辑器,是一个极度考验和折磨程序员的旅程。
终点也往往意味着新的起点,接下来还需要把功能提取出独立的组件,提供给其他应用使用,以及集成产品中的数据结构。路还长,幸福在路上。
路漫漫其修远兮,吾将上下而求索!加油吧少年。
Related
Related posts
-
从使用者到创造者:用 AI 构建你的专属 VS Code 工具链
2026-02-27
-
深入剖析Carota源码:从问题出发
2025-09-25
-
富文本编辑器开发学习笔记:跟踪canvas-editor有感,是金子终会发光
2025-09-07
-
深入解析 Nano Banana:Google 技术博客四篇精华翻译
2025-08-30