mod diff_error;
mod edited_text;
mod operation;
mod utils;
use std::fmt::Debug;
pub use diff_error::DiffError;
pub use edited_text::EditedText;
pub use operation::Operation;
use crate::{Tokenizer, types::text_with_cursors::TextWithCursors};
#[must_use]
pub fn reconcile<'a, T>(
original: &'a str,
left: &TextWithCursors,
right: &TextWithCursors,
tokenizer: &Tokenizer<T>,
) -> EditedText<'a, T>
where
T: PartialEq + Clone + Debug,
{
let left_operations = EditedText::from_strings_with_tokenizer(original, left, tokenizer);
let right_operations = EditedText::from_strings_with_tokenizer(original, right, tokenizer);
left_operations.merge(right_operations)
}
#[cfg(test)]
mod test {
use std::{fs, ops::Range, path::Path};
use pretty_assertions::assert_eq;
use test_case::test_matrix;
use super::*;
use crate::{BuiltinTokenizer, CursorPosition, types::text_with_cursors::TextWithCursors};
#[test]
fn test_cursor_complex() {
let original: &'static str = "this is some complex text to test cursor positions";
let left = TextWithCursors::new(
"this is really complex text for testing cursor positions".to_owned(),
vec![
CursorPosition {
id: 0,
char_index: 8,
}, CursorPosition {
id: 1,
char_index: 22,
}, ],
);
let right = TextWithCursors::new(
"that was some complex sample to test cursor movements".to_owned(),
vec![
CursorPosition {
id: 2,
char_index: 5,
}, CursorPosition {
id: 3,
char_index: 29,
}, ],
);
let merged = reconcile(original, &left, &right, &*BuiltinTokenizer::Word).apply();
assert_eq!(
&merged.text(),
"that was really complex sample for testing cursor movements"
);
assert_eq!(
merged.cursors(),
vec![
CursorPosition {
id: 2,
char_index: 5
}, CursorPosition {
id: 0,
char_index: 9
}, CursorPosition {
id: 1,
char_index: 23
}, CursorPosition {
id: 3,
char_index: 30
}, ]
);
}
#[ignore = "expensive to run, only run in CI"]
#[test_matrix( [
"pride_and_prejudice.txt",
"room_with_a_view.txt",
"kun_lu.txt",
"blns.txt"
], [
"pride_and_prejudice.txt",
"room_with_a_view.txt",
], [
"room_with_a_view.txt",
"kun_lu.txt",
"blns.txt"
], [0..10000], [0..10000, 10000..20000], [0..10000, 10000..20000])]
fn test_merge_files_without_panic(
file_name_1: &str,
file_name_2: &str,
file_name_3: &str,
range_1: Range<usize>,
range_2: Range<usize>,
range_3: Range<usize>,
) {
let files = [file_name_1, file_name_2, file_name_3];
let permutations = [range_1, range_2, range_3];
let root = Path::new("tests/resources/");
let contents = files
.iter()
.zip(permutations.iter())
.map(|(file, range)| {
let path = root.join(file);
fs::read_to_string(&path)
.unwrap()
.chars()
.skip(range.start)
.take(range.len())
.collect::<String>()
})
.collect::<Vec<_>>();
let _ = reconcile(
&contents[0],
&(&contents[1]).into(),
&(&contents[2]).into(),
&*BuiltinTokenizer::Word,
);
}
}