Skip to main content

Crate cratefield_text_diff

Crate cratefield_text_diff 

Source
Expand description

cratefield-text-diff: a word-level diff for showing what a rewrite changed (issue #836).

diff_words compares two texts word by word and answers with Segments that are Op::Removed, Op::Added or Op::Same. diff_words_locked also takes the byte ranges of each text that are protected — a figure, a name, a quotation, a line of code, as cratefield-text-guard finds them, or ranges from anywhere else. A protected range is one atomic token: it is never split into words, and when it is unchanged it comes back as Op::Locked so a UI can box it.

use cratefield_text_diff::{Op, diff_words};

let segments = diff_words("revenue grew by 18% to $4.2M", "revenue rose 18% to $4.2M");
let ops: Vec<_> = segments.iter().map(|s| (s.op, s.text.as_str())).collect();
assert_eq!(ops, [
    (Op::Same, "revenue "),
    (Op::Removed, "grew by "),
    (Op::Added, "rose "),
    (Op::Same, "18% to $4.2M"),
]);

§Tokens and whitespace

A token is a protected range, a word (letters and digits, with ' ’ - . , % allowed between or after them, so don't, 4.2M and 18% stay whole), or a single other character. Whitespace is not a token: it rides on the token before it and is not compared, so re-wrapping a paragraph is not a change. Each segment’s text carries its trailing whitespace from the side it came from — the rewrite’s for Same, Locked and Added, the original’s for Removed — so the texts of every segment that is not Removed, in order, are exactly the rewrite.

§Algorithm

Myers’ O(ND) difference algorithm in its linear-space form (the “middle snake”), after stripping the common prefix and suffix: a full rewrite of a long text costs memory proportional to its length, not its square. The result is a shortest edit script, so a minimal diff, and within each change everything removed is listed before everything added.

Structs§

Segment
A run of text with one Op. Adjacent segments never share an op, except Op::Locked, which is one segment per protected range.

Enums§

Op
What happened to a piece of text between the two versions.

Functions§

diff_words
The word diff of before and after, with nothing protected.
diff_words_locked
The word diff of before and after, where before_locked and after_locked are protected byte ranges of each. A range that is out of bounds, not on a char boundary, or overlaps an earlier one is ignored.