Ropey is a utf8 text rope for Rust, designed to be the backing text-buffer for applications such as text editors. Ropey is fast, robust, and can handle huge texts and memory-incoherent edits with ease.
// 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 is designed and built to be the backing text buffer for applications such as text editors, and its design trade-offs reflect that. Ropey is good at:
On the other hand, Ropey is not good at:
Keep this in mind when selecting Ropey for your project. Ropey is very good at what it does, but like all software it is designed with certain applications in mind.
Ropey's atomic unit of text is
Unicode scalar values
(or char
s in Rust)
encoded as utf8. All of Ropey's editing and slicing operations are done
in terms of char indices, which prevents accidental creation of invalid
utf8 data.
Ropey also supports converting between scalar value indices and utf16 code unit indices, for interoperation with external APIs that may still use utf16.
Ropey knows about line breaks, allowing you to index into and iterate over lines of text.
The line breaks Ropey recognizes are also configurable at build time via feature flags. See Ropey's documentation for details.
Ropey has rope slices that allow you to work with just parts of a rope, using all the read-only operations of a full rope including iterators and making sub-slices.
Although Ropey is intentionally limited in scope, it also provides APIs for efficiently accessing and working with its internal text chunk representation, allowing additional functionality to be efficiently implemented by client code with minimal overhead.
Ropey is fast and minimizes memory usage:
Ropey ensures that even though clones share memory, everything is thread-safe. Clones can be sent to other threads for both reading and writing.
Ropey uses unsafe code to help achieve some of its space and performance characteristics. Although effort has been put into keeping the unsafe code compartmentalized and making it correct, please be cautious about using Ropey in software that may face adversarial conditions.
Auditing, fuzzing, etc. of the unsafe code in Ropey is extremely welcome. If you find any unsoundness, please file an issue! Also welcome are recommendations for how to remove any of the unsafe code without introducing significant space or performance regressions, or how to compartmentalize the unsafe code even better.
Ropey is licensed under the MIT license (LICENSE.md or http://opensource.org/licenses/MIT)
Contributions are absolutely welcome! However, please open an issue to discuss larger changes, to avoid doing a lot of work that may get rejected. Also note that PRs that add dependencies are very likely to be rejected (Ropey aims to have minimal dependencies).
An overview of Ropey's design can be found here.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Ropey by you will be licensed as above, without any additional terms or conditions.