技术解读
comparePlus:把“差异查看”焊进 Notepad++ 的技术样本
项目背景与痛点
Notepad++ 是一款“够快、够小、够顺手”的编辑器,但原生不提供文件比较功能。日常开发里,比较两个文件最直接的做法是打开 WinMerge 或 Beyond Compare:把文件从编辑器拖过去,对比完再回到编辑器继续改。这个动作本身没有技术难度;真正的成本在于流程反复被打断:从编辑器拖出去、对比、再切回来,在代码评审和配置排查中会不断打断注意力。
早年的 Notepad++ Compare 插件缓解了这个问题,却留下不少问题:面对大文件容易卡顿,只有粗糙的行级对比,忽略空白和大小写的规则不灵活,并且与新版宿主兼容性不佳。pnedev/comparePlus 是对这一类插件的重写:它不追求做成“全能对比工具”,而是努力在编辑器内实现“原地比较”,从而省去把文件拖到外部工具的步骤。这个取舍也决定了后面的架构选择。
核心技术揭秘
作为 Notepad++ 插件,comparePlus 以 DLL 形式加载进宿主进程,通过 Npp API 与 Scintilla 消息(SCI_*)直接和编辑器内核通信,中间没有额外抽象层。这个选择有利也有弊:好处是能拿到最细粒度的编辑状态与视图信息;代价是行为与宿主版本强耦合。
比较流程大致如下:采集文本、归一化、预筛、差分、建模、渲染。
以下是几处值得注意的实现细节:
文本采集采用逐行拉取,避免整块复制。 一次性 SCI_GETTEXT 会把两侧文档完整复制两份,对大文件来说,两遍遍历和两份拷贝都很浪费;逐行读取则便于同时维护“原始行号到归一化行”的映射,后续渲染和导航都依赖这个映射。此外,它不修改文档内容,也就不进入 undo 栈。
预处理阶段用行哈希预筛。 先按忽略规则归一化每一行(去掉行尾空白、压缩空白、统一大小写),计算哈希,再用哈希值快速筛出必然相同的行段。只有候选区段才进入精确差分。这层预筛是对最坏情况(两侧几乎全同的大文件)最有效的优化,能让差异算法少做大量无意义比较。
差分核心大概率采用 Myers 的 O(ND) 算法或其变体。 这类算法以“编辑距离”为代价寻找最短编辑脚本,复杂度只与差异量 D 相关,对文本高度相似的真实场景很友好。风险集中在两处:D 很大时性能会急剧下降,需要设置上限并降级处理;另外,完整回溯需要保存中间路径,需要内存开销,成熟实现通常采用线性空间变体或分治,并保留前后缀修剪。从插件对超大文件采取保守策略来看,它很可能设置有阈值与保护机制。
渲染是非侵入式的。 差异高亮使用 Scintilla 的 indicator(半透明背景叠加),行级标记使用 margin marker,缺失段落用折叠槽连线表达对齐关系。这些都只改变视图展示,不改变字符内容,因此不会污染文件、不触发误保存,也不会与被比较文件的语法高亮冲突。
同步滚动依赖行号映射,而非 1:1 绑定。 由于两侧行数不同(存在增删块),简单按行号同步会立刻错位。差异块模型同时充当“对齐表”:滚动时根据当前视图位置找到最近的差异块,换算出另一侧的目标行,再滚过去。这是体验好坏的关键,也是这类插件最容易做差的地方。
功能亮点与差异
与 WinMerge 这类外部工具相比,comparePlus 的主要优势在于零上下文切换:比较动作内嵌在菜单里,结果直接影响当前编辑视图,甚至可以把差异块直接当作导航锚点逐条跳转。
它的差异化主要体现在三点:
- 视图级装饰而非文档级修改。很多简易对比工具靠替换文本、插入标记行来展示差异,结果是“比完要撤销”。comparePlus 的方案天然不影响文件内容。
- 可组合的忽略规则。忽略大小写、忽略空白、忽略全部空白等开关可以叠加,对比较格式化后的 JSON、SQL 或日志这类场景很实用。
- 与宿主工作流整合。无论是双视图并排比较,还是配合版本管理类插件查看工作区与历史版本的差异,都能把“查看 diff”从外部工具拉回编辑器。
它的短板也很明确:只做文件级比较,没有目录级递归比较、三路合并和补丁生成,这些仍需交给专业工具。
应用场景与落地建议
适合:配置文件与日志的快速比对、代码评审前查看局部改动、查找两份文本中“看起来一样”的隐性差异(如空白、编码、行尾符),以及在网络受限或不允许安装大型工具的环境中,用便携版 Notepad++ 加插件完成轻量比对。
需要注意:
- 编码与行尾符需先统一。两侧一个是 CRLF、一个是 LF,或一个是 UTF-8、另一个是 ANSI,插件看到的就是字节层面的差异,比较结果会全是噪声。建议先统一,再启用忽略规则。
- 大文件应控制文件规模。差异量 D 很大时,任何基于 Myers 的实现都会变慢;对数百 MB 的日志,建议先切片或抽样。
- 版本锁定。Notepad++ 的插件 ABI 与宿主版本绑定紧密;升级编辑器前,最好先在独立环境验证插件版本,避免生产环境启动异常。
- 不替代版本控制。它擅长查看差异,不负责合并与回滚。
综合评价
优点:定位精准,把“比较”做成编辑器内的高频小动作;渲染方案克制,采用视图级装饰,不影响文件内容;忽略规则与跨视图导航做得扎实;代码体量小,易于理解与二次开发。
缺点:功能边界明显,没有目录比较和三路合并;与宿主版本强耦合,升级有风险;社区与文档规模有限,遇到边缘问题(超长行、混合编码)时,可依赖的支持较少。
一句话结论:它适合那些“一天要比较十次、每次只差几行”的开发者。它并不打算替代 WinMerge,价值在于把最频繁的那一类比较从工具切换中解放出来,直接以菜单命令的形式完成。

评论