2

我一直在考虑如何让编辑器核心功能明智地兼容 vim,类似于 yzis。

最大的问题是使用什么缓冲区类型。

要求是:

  • 实现快速语法高亮的可能性,在它之上的正则表达式。
  • 在单个文件中实现多个语法突出显示的可能性。类似于 textmates 范围
  • 删除插入上的正确移动标记。以便他们在列中正确调整。不像在vim中。
  • 处理并突出显示至少 100 mb 的文件,而不会出现太大的问题和内存开销。

可能的缓冲区类型:

  • 间隙缓冲区
  • 基于行的编辑

我读到间隙缓冲区会在较长时间运行时导致相当大的内存碎片。此外,emacs 语法高亮引擎非常慢。(不知道为什么,可能与缓冲区类型无关)

所以问题:

  1. 哪种缓冲区类型最适合快速编程编辑器?
  2. 什么是快速/完整的正则表达式引擎?(也许这包括下一点)。TextMate 使用 oniguruma,这是一个明智的选择吗?
  3. 什么是快速语法高亮引擎?
  4. 关于标记和语法高亮。emacs 覆盖如何工作,它们有帮助吗?

谢谢,礼萨

4

2 回答 2

4

一个好的文本编辑器应该对程序员可能做的各种工作都有用,包括打开有时可能有几 GB 大小的文件。因此,我不建议将所有内容都缓存在 RAM 中的思维定势。

我建议设置一个表示文件的切片搜索树,其中单个切片可能是:

  1. 对磁盘上实际文件中字节范围的引用,或
  2. 对已编辑“页面”的引用。

当您打开一个文件时,您首先将单个项目插入到树中,这只是一个代表整个文件的范围,例如对于 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

您可以将内存映射文件用于只读缓冲区(源文件)和复制的可编辑缓冲区(后者将放置在临时目录中)。如果编辑器崩溃,这也允许恢复。

使用固定大小的页面将大大减少内存堆的碎片,因为所有块都具有相同的大小,并且插入文本永远不需要移动超过 4 KiB 的数据。

这是一个简化的描述,给出了一般的想法,而不涉及太多的细节。真正的实现很可能需要更复杂,例如允许页面中的可变数据量以应对溢出的页面,并将许多小切片合并在一起,以便在大文件中运行正则表达式替换不会创建太多许多小缓冲区。可能需要对树中应该同时拥有的切片数量进行限制,但关键是当您开始在某处插入时,您应该确保使用的切片不太大。

对于正则表达式,只要整个编辑器在运行时不挂起,我认为性能不会有太大问题。试试Boost.Regex,它很可能足够快满足您的需求,而且它也足够通用,可以插入您需要的任何缓冲策略。

这同样适用于语法高亮,如果你在后台运行它,它不会在用户打字时对他造成太大的干扰。您可以在这里使用切片方法为您带来好处:

  • 每个切片都可以有一个互斥锁,可以在编辑操作期间锁定,从而允许语法突出显示或“智能感知”类型分析在后台线程中运行。
  • 您可以存储语法高亮引擎的状态,这样每当您在切片中进行编辑时,您都可以从该切片的开头重新开始语法高亮,而不是从文件的开头。

我不知道有任何独立的语法高亮引擎,但它们通常基于正则表达式替换(参见例如 vim 中的语法高亮文件)。

于 2009-02-15T16:18:49.620 回答
0

您可以使用 Scintilla 类。您的视图可以从 Scintilla 视图派生,它提供语法突出显示。

于 2009-02-10T15:20:29.767 回答