37 个版本 (12 个稳定版)

使用旧的 Rust 2015

1.6.1 2023 年 10 月 18 日
1.6.0 2023 年 2 月 1 日
1.5.1 2023 年 1 月 1 日
1.5.1-alpha2022 年 11 月 28 日
0.2.0 2015 年 3 月 3 日

#8 in 数据结构

Download history 10915/week @ 2024-04-16 11217/week @ 2024-04-23 11669/week @ 2024-04-30 11130/week @ 2024-05-07 11533/week @ 2024-05-14 11254/week @ 2024-05-21 11641/week @ 2024-05-28 10060/week @ 2024-06-04 10435/week @ 2024-06-11 11397/week @ 2024-06-18 12701/week @ 2024-06-25 9207/week @ 2024-07-02 11460/week @ 2024-07-09 11083/week @ 2024-07-16 14505/week @ 2024-07-23 14294/week @ 2024-07-30

53,726 个月下载量
用于 170 包 (76 个直接使用)

MIT 许可协议

480KB
10K SLoC

Ropey

CI Build Status Latest Release Documentation

Ropey 是一个针对 Rust 的 utf8 文本绳索,旨在作为文本编辑器等应用的底层文本缓冲区。Ropey 快速、健壮,可以轻松处理大量文本和内存不连续的编辑。

示例用法

// Load a text file.
let mut text = ropey::Rope::from_reader(
    File::open("my_great_book.txt")?
)?;

// Print the 516th line (zero-indexed).
println!("{}", text.line(515));

// Get the start/end char indices of the line.
let start_idx = text.line_to_char(515);
let end_idx = text.line_to_char(516);

// Remove the line...
text.remove(start_idx..end_idx);

// ...and replace it with something better.
text.insert(start_idx, "The flowers are... so... dunno.\n");

// Print the changes, along with the previous few lines for context.
let start_idx = text.line_to_char(511);
let end_idx = text.line_to_char(516);
println!("{}", text.slice(start_idx..end_idx));

// Write the file back out to disk.
text.write_to(
    BufWriter::new(File::create("my_great_book.txt")?)
)?;

何时应使用 Ropey?

Ropey 设计和构建为文本编辑器等应用的底层文本缓冲区,其设计权衡反映了这一点。Ropey 在以下方面表现良好:

  • 处理中等到大型文本的频繁编辑。即使在多吉字节大小的文本上,编辑时间也以微秒计算。
  • 正确处理 Unicode。通过 Ropey 无法创建无效的 utf8,并且可以正确跟踪包括 CRLF 在内的所有 Unicode 行结束。
  • 具有平坦、可预测的性能特征。Ropey 从不会成为你软件中的干扰或卡顿源。

另一方面,Ropey 在以下方面表现不佳:

  • 处理小于几KB的文本。也就是说,Ropey 可以很好地处理它们,但 Ropey 以 KB 为单位分配空间,如果文本几乎总是很小的,这会引入不必要的膨胀。
  • 处理大于可用内存的文本。Ropey 是一个内存中的数据结构。
  • 为每个可能的使用场景提供最佳性能。Ropey 在跟踪行结束和 Unicode 标量值方面投入了大量工作,这可能是你的使用场景不需要的性能开销。

在选择 Ropey 作为你的项目时请记住这一点。Ropey 在其擅长的领域表现非常好,但像所有软件一样,它是针对某些应用场景设计的。

功能

强大的 Unicode 支持

Ropey 的文本原子单位是 Unicode 标量值(或在 Rust 中的 char 类型),以 utf8 编码。Ropey 的所有编辑和切片操作都是以字符索引为单位的,这可以防止意外创建无效的 utf8 数据。

Ropey 还支持在标量值索引和 utf16 代码单元索引之间进行转换,以便与可能仍然使用 utf16 的外部 API 进行交互。

行感知

Ropey 了解换行符,允许您索引和迭代文本的行。

Ropey 识别的换行符也可以通过构建时的功能标志进行配置。有关详细信息,请参阅 Ropey 的文档。

Rope 切片

Ropey 提供了 rope 切片,允许您仅使用 rope 的一部分,并使用 rope 的所有只读操作,包括迭代器和子切片。

灵活的 API 和底层访问

尽管 Ropey 故意限制了范围,但它也提供了 API 以有效地访问和操作其内部文本块表示,允许客户端代码以最小的开销高效地实现附加功能。

高效

Ropey 快速且内存使用量最小化

  • 在最近的一台移动式 i7 英特尔 CPU 上,Ropey 在构建大约 100 MB 大小的文本时,每秒执行了超过 180 万次小的无序插入。有序插入(即所有插入都接近文本的同一位置)更快,每秒执行超过 330 万次相同的任务。
  • 从磁盘加载新文件仅产生大约 10% 的内存开销。例如,一个 100 MB 的文本文件在 Ropey 加载时将占用大约 110 MB 的内存。
  • 克隆 rope 的成本极低。Rope 克隆共享数据,因此初始克隆仅占用 8 字节内存。之后,内存使用量将随着克隆由于编辑而分离而逐步增长。

线程安全

Ropey 确保即使克隆共享内存,一切也都是线程安全的。克隆可以发送到其他线程进行读取和写入。

不安全代码

Ropey 使用不安全代码来帮助实现其空间和性能特征。尽管已付出努力将不安全代码封装并确保其正确性,但请谨慎使用 Ropey 在可能面临对抗性条件的软件中。

欢迎对 Ropey 中的不安全代码进行审计、模糊测试等。如果您发现任何不一致性, 提交一个问题!也欢迎提供有关如何在不引入重大空间或性能退化的情况下删除任何不安全代码的建议,或如何更好地封装不安全代码的建议。

许可

Ropey 在 MIT 许可证下发布(LICENSE.md 或 http://opensource.org/licenses/MIT

贡献

欢迎贡献!但是,请先打开一个问题或给我发邮件讨论较大的更改,以避免做大量可能被拒绝的工作。

Ropey 的设计概述可以在这里找到。

除非您明确声明,否则您有意提交以包含在 Ropey 中的任何贡献都将按上述方式许可,不附加任何额外条款或条件。

依赖项