我一直在思考如何让编辑器的核心功能与 vim 兼容,类似于 yzis。
最大的问题是使用什么类型的缓冲区。
要求是:
- 可以实现快速语法突出显示、正则表达式。
- 可以在单个文件中实现多个语法突出显示。类似于 textmates 范围
- 删除插入时正确的移动标记。以便它们在列中正确调整。与 vim 不同。
- 处理并突出显示至少 100 MB 的文件,不会出现太大问题和内存开销。
可能的缓冲区类型:
- 间隙缓冲区
- 基于行的编辑
我读到间隙缓冲区在较长的运行中会导致相当大的内存碎片。而且 emacs 语法高亮引擎非常慢。(不知道为什么,可能与缓冲区类型没有真正关系)
所以问题是:
- 哪种缓冲区类型最适合快速编程编辑器?
- 什么是快速/完整的正则表达式引擎? (也许这包括下一点)。 TextMate 使用 oniguruma,这是一个明智的选择吗?
- 什么是快速语法突出显示引擎?
- 关于标记和语法高亮。 emacs 叠加层是如何工作的,有帮助吗?
谢谢, 礼萨
最佳答案
一个好的文本编辑器应该对程序员可能从事的各种工作都有用,其中包括打开有时可能有几千兆字节大小的文件。因此,我不建议将所有内容都缓冲在 RAM 中。
我建议设置代表文件的切片搜索树,其中单个切片可能是:
- 对磁盘上实际文件中的字节范围的引用,或
- 对已编辑“页面”的引用。
当您打开文件时,首先将单个项目插入树中,该项目只是代表整个文件的范围,例如对于 10 MiB 文件:
std::map<size_t, slice_info> slices;
slices[0].size = 10*1024*1024;
当用户编辑文件时,在编辑点周围创建一个合理大小的“页面”,例如 4 KiB。树在此时被拼接。在示例中,编辑点位于 5 MiB:
size_t const PAGE_SIZE = 4*1024;
slices[0].size = 5*1024*1024;
slices[5*1024*1024].size = PAGE_SIZE;
slices[5*1024*1024].buffer = create_buffer(file, 5*1024*1024, PAGE_SIZE);
slices[5*1024*1024 + PAGE_SIZE].size = 5*1024*1024 - PAGE_SIZE
您可以将内存映射文件用于只读缓冲区(源文件)和复制的可编辑缓冲区(后者将放置在临时目录中)。这也允许在编辑器崩溃时进行恢复。
使用固定大小的页面将大大减少内存堆的碎片,因为所有 block 都具有相同的大小,并且插入文本永远不需要在您前面移动超过 4 KiB 的数据。
这是一个简化的描述,旨在给出总体思路,而不会涉及太多具体细节。真正的实现很可能需要更加复杂,例如允许页面中的可变数据量来处理溢出的页面,并将许多小切片合并在一起,以便在大文件中运行正则表达式替换不会创建太多的小缓冲区。树中同时拥有的切片数量可能需要受到限制,但关键点是,当您开始插入某处时,您应该确保使用的切片不太大。
对于正则表达式,我认为只要整个编辑器在运行时不挂起,性能就不是什么大问题。试试Boost.Regex ,它很可能足够快,足以满足您的需求,而且它也足够通用,可以插入您需要的任何缓冲策略。
这同样适用于语法突出显示,如果您在后台运行它,它不会在用户打字时打扰太多。您可以在此处使用切片方法来获得好处:
- 每个切片都可以有一个互斥锁,可以在编辑操作期间锁定该互斥锁,从而允许语法突出显示或“智能感知”类型分析在后台线程中运行。
- 您可以存储语法突出显示引擎的状态,以便每当您在切片中进行编辑时,都可以从该切片的开头(而不是从文件的开头)重新启动语法突出显示。
我不知道有任何独立的语法突出显示引擎,但它们通常基于正则表达式替换(例如,参见 vim 中的语法突出显示文件)。
关于c++ - 编辑器核心缓冲区类型和语法突出显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/531957/