我一直在考虑编写一个文本编辑器控件,它可以编辑任意长度(例如,数百兆字节)的文本,在某些方面类似于Scintilla编辑器。目标是延迟读取文件,因此用户不必阅读500兆字节的数据,只是为了查看它的一小部分。我有两个问题:
在我看来,不可能为这样的编辑器实现任何合理的滚动功能,除非我预先读取整个文件一次,以便找出换行符。这是真的吗?或者有没有办法估算事物,我没想到?
由于Unicode的各种问题(例如,它允许许多字节只表示一个字符,不仅仅是因为可变长度编码而且还因为重音等),似乎几乎不可能确切地确定多少文本将适合屏幕 - 我必须使用TextOut()或其他东西绘制一个字符,测量它有多大,然后绘制下一个字符。即便如此,仍然没有说明我如何将用户的点击映射回正确的文本位置。
我是否可以在网上阅读有关处理这些问题的算法的内容?我搜索过,但是我没找到任何东西。
谢谢!
答案 0 :(得分:5)
您可以根据数据大小而不是行来设置“粗略”位置。文本窗口的“精细”位置可以基于任意入口点周围的本地扫描。
这意味着您需要编写可以本地扫描(向后和向前)以查找行开始,计算Unicode字符等的函数。这不应该太难; UTF8旨在以这种方式轻松解析。
您可能需要特别考虑如何处理极长行。由于线路的长度没有上限,这使得查找线路的开始(或结束)成为无限制的任务;我相信屏幕编辑器显示所需的一切都应该是本地的。
最后,如果你想要一个通用的文本编辑器,你需要弄清楚当你想要保存插入/删除了东西的文件时你要做什么。直截了当的是重写文件;然而,对于一个巨大的文件来说,这显然需要更长的时间。如果没有足够的空间容纳修改过的副本,您可能会遇到用户遇到问题,所以至少,您需要检查以确保文件系统上有足够的空间。
答案 1 :(得分:4)
@comingstorm基本上是正确的。为了显示,你从光标开始向后扫描,直到你确定你已经超过了屏幕的顶部。然后,您向后扫描到行尾,假设您可以识别向后扫描的行尾。现在,您向前扫描,计算并保存屏幕行开始位置,直到您走得足够远。最后,您选择要开始显示的线路。
对于简单文本,这可以在古老的处理器上快速完成,以便在每次击键时重绘内存映射视频显示。 [我30年前发明了这项技术]。正确的方法是将光标固定在屏幕的中间行。
对于实际修改文件,您可能会考虑使用Gnu的绳索。绳索基本上是缓冲区的链接列表。我们的想法是,所有本地编辑都可以在一个小缓冲区中完成,偶尔会添加一个新的缓冲区,偶尔会合并相邻的缓冲区。
我会考虑将这项技术与差异存储相结合:所有现代源控制系统都能做到这一点。如果要实现撤消功能,基本上 可以使用这种基于事务的编辑。
这个问题的关键是可逆交易,即包含足够信息以便向后应用以撤消它在向前应用时所做的事情。核心编辑器事务是:
at pos p replace old with new
有反向
at pos p replace new with old
这会处理insert(old为空)和delete(new为空)以及replace。给定事务列表,您可以通过应用反向事务列表的反向来撤消对字符串的原位修改。
现在您使用旧的检查点概念:您存储了一个相当近期的文件的就地修改图像以及尚未应用的一些最近的事务。要显示,您可以即时应用交易。要撤消,您只需丢弃一些交易。有时,您实际应用交易,制作“检查点”图像。这会加快显示速度,但代价是使撤消速度变慢。
最后:要重写一个巨大的顺序文本文件,你通常会重写整个文本,这很糟糕。如果您可以作弊,并允许文本中的任意0个字符,并且您可以访问虚拟内存系统页面管理器和低级别磁盘访问,则可以通过保留所有未更改的文本页面并重新组织它们来做得更好:换句话说,就是磁盘上的绳索。