From 3781894ffc29456c5039daddab9482a02a70dd82 Mon Sep 17 00:00:00 2001 From: Dima Kudosh Date: Sun, 28 Feb 2016 19:14:11 +0300 Subject: [PATCH] Add context diff and tests for it --- src/lib.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/utils.rs | 15 +++++++++++- tests/test.rs | 8 +++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 38082df..52c2150 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,9 @@ pub mod differ; mod utils; +use std::collections::HashMap; use sequencematcher::{SequenceMatcher, Sequence}; -use utils::{format_range_unified}; +use utils::{format_range_unified, format_range_context}; pub fn get_close_matches<'a>(word: &str, possibilities: Vec<&'a str>, n: usize, cutoff: f32) -> Vec<&'a str> { @@ -63,3 +64,64 @@ pub fn unified_diff(first_sequence: &T, second_sequence: &T, from_f } res } + + +pub fn context_diff(first_sequence: &T, second_sequence: &T, from_file: &str, to_file: &str, + from_file_date: &str, to_file_date: &str, n: usize, lineterm: &str) -> Vec { + let mut res = Vec::new(); + let mut prefix: HashMap = HashMap::new(); + prefix.insert(String::from("insert"), String::from("+ ")); + prefix.insert(String::from("delete"), String::from("- ")); + prefix.insert(String::from("replace"), String::from("! ")); + prefix.insert(String::from("equal"), String::from(" ")); + let mut started = false; + let mut matcher = SequenceMatcher::new(first_sequence, second_sequence); + for group in &matcher.get_grouped_opcodes(n) { + if !started { + started = true; + let from_date = format!("\t{}", from_file_date); + let to_date = format!("\t{}", to_file_date); + res.push( format!("*** {}{}{}", from_file, from_date, lineterm) ); + res.push( format!("--- {}{}{}", to_file, to_date, lineterm) ); + } + let (first, last) = (group.first().unwrap(), group.last().unwrap()); + res.push(format!("***************{}", lineterm)); + let file1_range = format_range_context(first.first_start, last.first_end); + res.push(format!("*** {} ****{}", file1_range, lineterm)); + let mut any = false; + for opcode in group { + if opcode.tag == "replace" || opcode.tag == "delete" { + any = true; + break; + } + } + if any { + for opcode in group { + if opcode.tag != "insert" { + for i in opcode.first_start..opcode.first_end { + res.push( format!("{}{}", prefix.get(&opcode.tag).unwrap(), first_sequence.at_index(i).unwrap()) ); + } + } + } + } + let file2_range = format_range_context(first.second_start, last.second_end); + res.push(format!("--- {} ----{}", file1_range, lineterm)); + any = false; + for opcode in group { + if opcode.tag == "replace" || opcode.tag == "insert" { + any = true; + break; + } + } + if any { + for opcode in group { + if opcode.tag != "delete" { + for i in opcode.second_start..opcode.second_end { + res.push( format!("{}{}", prefix.get(&opcode.tag).unwrap(), second_sequence.at_index(i).unwrap()) ); + } + } + } + } + } + res +} \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index a855a9e..da3f1e3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -30,10 +30,23 @@ pub fn format_range_unified(start:usize, end: usize) -> String { println!("{:?} {}", start, end); let length = end - start; if length == 1 { - return format!("{}", beginning) + return beginning.to_string() } if length == 0 { beginning -= 1; } format!("{},{}", beginning, length) +} + + +pub fn format_range_context(start: usize, end: usize) -> String { + let mut beginning = start + 1; + let length = end - start; + if length == 0 { + beginning -= 1 + } + if length <= 1 { + return beginning.to_string() + } + format!("{},{}", beginning, beginning + length - 1) } \ No newline at end of file diff --git a/tests/test.rs b/tests/test.rs index 58ef026..b0f5051 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -109,5 +109,13 @@ fn test_unified_diff() { let result = difflib::unified_diff(&first_text, &second_text, "Original", "Current", "2005-01-26 23:30:50", "2010-04-02 10:20:52", 3, "").join(""); assert_eq!(result, "--- Original\t2005-01-26 23:30:50+++ Current\t2010-04-02 10:20:52@@ -1,4 +1,4 @@+zero one-two-three+tree four"); +} +#[test] +fn test_context_diff() { + let first_text = "one two three four".split(" ").collect::>(); + let second_text = "zero one tree four".split(" ").collect::>(); + let result = difflib::context_diff(&first_text, &second_text, "Original", "Current", + "2005-01-26 23:30:50", "2010-04-02 10:20:52", 3, "").join(""); + assert_eq!(result, "*** Original\t2005-01-26 23:30:50--- Current\t2010-04-02 10:20:52****************** 1,4 **** one! two! three four--- 1,4 ----+ zero one! tree four"); } \ No newline at end of file