Run cargo fmt

This commit is contained in:
nmlgc
2018-06-15 11:54:48 +02:00
parent 1805d9a548
commit a053cc079a
7 changed files with 322 additions and 230 deletions
+20 -7
View File
@@ -1,6 +1,6 @@
# Difflib [![Build Status](https://travis-ci.org/DimaKudosh/difflib.svg?branch=master)](https://travis-ci.org/DimaKudosh/difflib) # Difflib [![Build Status](https://travis-ci.org/DimaKudosh/difflib.svg?branch=master)](https://travis-ci.org/DimaKudosh/difflib)
Port of Python's difflib library to Rust. Port of Python's difflib library to Rust.
It's provide all necessary tools for comparing word sequences. It's provide all necessary tools for comparing word sequences.
## Installation ## Installation
@@ -21,20 +21,33 @@ extern crate difflib;
use difflib::differ::Differ; use difflib::differ::Differ;
use difflib::sequencematcher::SequenceMatcher; use difflib::sequencematcher::SequenceMatcher;
fn main() { fn main() {
// unified_diff // unified_diff
let first_text = "one two three four".split(" ").collect::<Vec<&str>>(); let first_text = "one two three four".split(" ").collect::<Vec<&str>>();
let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>(); let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>();
let diff = difflib::unified_diff(&first_text, &second_text, "Original", "Current", let diff = difflib::unified_diff(
"2005-01-26 23:30:50", "2010-04-02 10:20:52", 3); &first_text,
&second_text,
"Original",
"Current",
"2005-01-26 23:30:50",
"2010-04-02 10:20:52",
3,
);
for line in &diff { for line in &diff {
println!("{:?}", line); println!("{:?}", line);
} }
//context_diff //context_diff
let diff = difflib::context_diff(&first_text, &second_text, "Original", "Current", let diff = difflib::context_diff(
"2005-01-26 23:30:50", "2010-04-02 10:20:52", 3); &first_text,
&second_text,
"Original",
"Current",
"2005-01-26 23:30:50",
"2010-04-02 10:20:52",
3,
);
for line in &diff { for line in &diff {
println!("{:?}", line); println!("{:?}", line);
} }
@@ -62,7 +75,7 @@ fn main() {
let grouped_opcodes = matcher.get_grouped_opcodes(2); let grouped_opcodes = matcher.get_grouped_opcodes(2);
println!("{:?}", grouped_opcodes); println!("{:?}", grouped_opcodes);
let ratio = matcher.ratio(); let ratio = matcher.ratio();
println!("{:?}", ratio); println!("{:?}", ratio);
matcher.set_seqs("aaaaa", "aaaab"); matcher.set_seqs("aaaaa", "aaaab");
println!("{:?}", matcher.ratio()); println!("{:?}", matcher.ratio());
} }
+18 -15
View File
@@ -3,30 +3,33 @@ extern crate difflib;
use difflib::differ::Differ; use difflib::differ::Differ;
use difflib::sequencematcher::SequenceMatcher; use difflib::sequencematcher::SequenceMatcher;
fn main() { fn main() {
// unified_diff // unified_diff
let first_text = "one two three four".split(" ").collect::<Vec<&str>>(); let first_text = "one two three four".split(" ").collect::<Vec<&str>>();
let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>(); let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>();
let diff = difflib::unified_diff(&first_text, let diff = difflib::unified_diff(
&second_text, &first_text,
"Original", &second_text,
"Current", "Original",
"2005-01-26 23:30:50", "Current",
"2010-04-02 10:20:52", "2005-01-26 23:30:50",
3); "2010-04-02 10:20:52",
3,
);
for line in &diff { for line in &diff {
println!("{:?}", line); println!("{:?}", line);
} }
//context_diff //context_diff
let diff = difflib::context_diff(&first_text, let diff = difflib::context_diff(
&second_text, &first_text,
"Original", &second_text,
"Current", "Original",
"2005-01-26 23:30:50", "Current",
"2010-04-02 10:20:52", "2005-01-26 23:30:50",
3); "2010-04-02 10:20:52",
3,
);
for line in &diff { for line in &diff {
println!("{:?}", line); println!("{:?}", line);
} }
+145 -101
View File
@@ -1,7 +1,6 @@
use sequencematcher::{SequenceMatcher, Sequence}; use sequencematcher::{Sequence, SequenceMatcher};
use utils::{str_with_similar_chars, count_leading};
use std::cmp; use std::cmp;
use utils::{count_leading, str_with_similar_chars};
pub struct Differ { pub struct Differ {
pub line_junk: Option<fn(&str) -> bool>, pub line_junk: Option<fn(&str) -> bool>,
@@ -16,10 +15,11 @@ impl Differ {
} }
} }
pub fn compare<T: ?Sized + Sequence>(&self, pub fn compare<T: ?Sized + Sequence>(
first_sequence: &T, &self,
second_sequence: &T) first_sequence: &T,
-> Vec<String> { second_sequence: &T,
) -> Vec<String> {
let mut matcher = SequenceMatcher::new(first_sequence, second_sequence); let mut matcher = SequenceMatcher::new(first_sequence, second_sequence);
matcher.set_is_junk(self.line_junk); matcher.set_is_junk(self.line_junk);
let mut res = Vec::new(); let mut res = Vec::new();
@@ -27,12 +27,14 @@ impl Differ {
let mut gen = Vec::new(); let mut gen = Vec::new();
match opcode.tag.as_ref() { match opcode.tag.as_ref() {
"replace" => { "replace" => {
gen = self.fancy_replace(first_sequence, gen = self.fancy_replace(
opcode.first_start, first_sequence,
opcode.first_end, opcode.first_start,
second_sequence, opcode.first_end,
opcode.second_start, second_sequence,
opcode.second_end) opcode.second_start,
opcode.second_end,
)
} }
"delete" => { "delete" => {
gen = self.dump("-", first_sequence, opcode.first_start, opcode.first_end) gen = self.dump("-", first_sequence, opcode.first_start, opcode.first_end)
@@ -52,12 +54,13 @@ impl Differ {
res res
} }
fn dump<T: ?Sized + Sequence>(&self, fn dump<T: ?Sized + Sequence>(
tag: &str, &self,
sequence: &T, tag: &str,
start: usize, sequence: &T,
end: usize) start: usize,
-> Vec<String> { end: usize,
) -> Vec<String> {
let mut res = Vec::new(); let mut res = Vec::new();
for i in start..end { for i in start..end {
match sequence.at_index(i) { match sequence.at_index(i) {
@@ -68,14 +71,15 @@ impl Differ {
res res
} }
fn plain_replace<T: ?Sized + Sequence>(&self, fn plain_replace<T: ?Sized + Sequence>(
first_sequence: &T, &self,
first_start: usize, first_sequence: &T,
first_end: usize, first_start: usize,
second_sequence: &T, first_end: usize,
second_start: usize, second_sequence: &T,
second_end: usize) second_start: usize,
-> Vec<String> { second_end: usize,
) -> Vec<String> {
if !(first_start < first_end && second_start < second_end) { if !(first_start < first_end && second_start < second_end) {
return Vec::new(); return Vec::new();
} }
@@ -94,14 +98,15 @@ impl Differ {
first first
} }
fn fancy_replace<T: ?Sized + Sequence>(&self, fn fancy_replace<T: ?Sized + Sequence>(
first_sequence: &T, &self,
first_start: usize, first_sequence: &T,
first_end: usize, first_start: usize,
second_sequence: &T, first_end: usize,
second_start: usize, second_sequence: &T,
second_end: usize) second_start: usize,
-> Vec<String> { second_end: usize,
) -> Vec<String> {
let mut res = Vec::new(); let mut res = Vec::new();
let (mut best_ratio, cutoff) = (0.74, 0.75); let (mut best_ratio, cutoff) = (0.74, 0.75);
let (mut best_i, mut best_j) = (0, 0); let (mut best_i, mut best_j) = (0, 0);
@@ -130,14 +135,17 @@ impl Differ {
} }
if best_ratio < cutoff { if best_ratio < cutoff {
if eqi.is_none() { if eqi.is_none() {
res.extend(self.plain_replace(first_sequence, res.extend(
first_start, self.plain_replace(
first_end, first_sequence,
second_sequence, first_start,
second_start, first_end,
second_end) second_sequence,
.iter() second_start,
.cloned()); second_end,
).iter()
.cloned(),
);
return res; return res;
} }
best_i = eqi.unwrap(); best_i = eqi.unwrap();
@@ -145,23 +153,30 @@ impl Differ {
} else { } else {
eqi = None; eqi = None;
} }
res.extend(self.fancy_helper(first_sequence, res.extend(
first_start, self.fancy_helper(
best_i, first_sequence,
second_sequence, first_start,
second_start, best_i,
best_j) second_sequence,
.iter() second_start,
.cloned()); best_j,
let (first_element, second_element) = (first_sequence.at_index(best_i).unwrap(), ).iter()
second_sequence.at_index(best_j).unwrap()); .cloned(),
);
let (first_element, second_element) = (
first_sequence.at_index(best_i).unwrap(),
second_sequence.at_index(best_j).unwrap(),
);
if eqi.is_none() { if eqi.is_none() {
let (mut first_tag, mut second_tag) = (String::new(), String::new()); let (mut first_tag, mut second_tag) = (String::new(), String::new());
let mut cruncher = SequenceMatcher::new(first_element, second_element); let mut cruncher = SequenceMatcher::new(first_element, second_element);
cruncher.set_is_junk(self.char_junk); cruncher.set_is_junk(self.char_junk);
for opcode in &cruncher.get_opcodes() { for opcode in &cruncher.get_opcodes() {
let (first_length, second_length) = (opcode.first_end - opcode.first_start, let (first_length, second_length) = (
opcode.second_end - opcode.second_start); opcode.first_end - opcode.first_start,
opcode.second_end - opcode.second_start,
);
match opcode.tag.as_ref() { match opcode.tag.as_ref() {
"replace" => { "replace" => {
first_tag.push_str(&str_with_similar_chars('^', first_length)); first_tag.push_str(&str_with_similar_chars('^', first_length));
@@ -180,42 +195,50 @@ impl Differ {
_ => {} _ => {}
} }
} }
res.extend(self.qformat(&first_element, &second_element, &first_tag, &second_tag) res.extend(
.iter() self.qformat(&first_element, &second_element, &first_tag, &second_tag)
.cloned()); .iter()
.cloned(),
);
} else { } else {
let mut s = String::from(" "); let mut s = String::from(" ");
s.push_str(&first_element); s.push_str(&first_element);
res.push(s); res.push(s);
} }
res.extend(self.fancy_helper(first_sequence, res.extend(
best_i + 1, self.fancy_helper(
first_end, first_sequence,
second_sequence, best_i + 1,
best_j + 1, first_end,
second_end) second_sequence,
.iter() best_j + 1,
.cloned()); second_end,
).iter()
.cloned(),
);
res res
} }
fn fancy_helper<T: ?Sized + Sequence>(&self, fn fancy_helper<T: ?Sized + Sequence>(
first_sequence: &T, &self,
first_start: usize, first_sequence: &T,
first_end: usize, first_start: usize,
second_sequence: &T, first_end: usize,
second_start: usize, second_sequence: &T,
second_end: usize) second_start: usize,
-> Vec<String> { second_end: usize,
) -> Vec<String> {
let mut res = Vec::new(); let mut res = Vec::new();
if first_start < first_end { if first_start < first_end {
if second_start < second_end { if second_start < second_end {
res = self.fancy_replace(first_sequence, res = self.fancy_replace(
first_start, first_sequence,
first_end, first_start,
second_sequence, first_end,
second_start, second_sequence,
second_end); second_start,
second_end,
);
} else { } else {
res = self.dump("-", first_sequence, first_start, first_end); res = self.dump("-", first_sequence, first_start, first_end);
} }
@@ -225,17 +248,20 @@ impl Differ {
res res
} }
fn qformat(&self, fn qformat(
first_line: &str, &self,
second_line: &str, first_line: &str,
first_tags: &str, second_line: &str,
second_tags: &str) first_tags: &str,
-> Vec<String> { second_tags: &str,
) -> Vec<String> {
let mut res = Vec::new(); let mut res = Vec::new();
let mut first_tags = first_tags; let mut first_tags = first_tags;
let mut second_tags = second_tags; let mut second_tags = second_tags;
let mut common = cmp::min(count_leading(first_line, '\t'), let mut common = cmp::min(
count_leading(second_line, '\t')); count_leading(first_line, '\t'),
count_leading(second_line, '\t'),
);
common = cmp::min(common, count_leading(first_tags.split_at(common).0, ' ')); common = cmp::min(common, count_leading(first_tags.split_at(common).0, ' '));
common = cmp::min(common, count_leading(first_tags.split_at(common).0, ' ')); common = cmp::min(common, count_leading(first_tags.split_at(common).0, ' '));
first_tags = first_tags.split_at(common).1.trim_right(); first_tags = first_tags.split_at(common).1.trim_right();
@@ -243,15 +269,21 @@ impl Differ {
let mut s = String::from(format!("- {}", first_line)); let mut s = String::from(format!("- {}", first_line));
res.push(s); res.push(s);
if first_tags != "" { if first_tags != "" {
s = String::from(format!("? {}{}\n", str_with_similar_chars('\t', common), first_tags)); s = String::from(format!(
"? {}{}\n",
str_with_similar_chars('\t', common),
first_tags
));
res.push(s); res.push(s);
} }
s = String::from(format!("+ {}", second_line)); s = String::from(format!("+ {}", second_line));
res.push(s); res.push(s);
if second_tags != "" { if second_tags != "" {
s = String::from(format!("? {}{}\n", s = String::from(format!(
str_with_similar_chars('\t', common), "? {}{}\n",
second_tags)); str_with_similar_chars('\t', common),
second_tags
));
res.push(s); res.push(s);
} }
res res
@@ -283,19 +315,31 @@ impl Differ {
#[test] #[test]
fn test_fancy_replace() { fn test_fancy_replace() {
let differ = Differ::new(); let differ = Differ::new();
let result = differ.fancy_replace(&vec!["abcDefghiJkl\n"], 0, 1, &vec!["abcdefGhijkl\n"], 0, 1) let result = differ
.fancy_replace(&vec!["abcDefghiJkl\n"], 0, 1, &vec!["abcdefGhijkl\n"], 0, 1)
.join(""); .join("");
assert_eq!(result, assert_eq!(
"- abcDefghiJkl\n? ^ ^ ^\n+ abcdefGhijkl\n? ^ ^ ^\n"); result,
"- abcDefghiJkl\n? ^ ^ ^\n+ abcdefGhijkl\n? ^ ^ ^\n"
);
} }
#[test] #[test]
fn test_qformat() { fn test_qformat() {
let differ = Differ::new(); let differ = Differ::new();
let result = differ.qformat("\tabcDefghiJkl\n", let result = differ.qformat(
"\tabcdefGhijkl\n", "\tabcDefghiJkl\n",
" ^ ^ ^ ", "\tabcdefGhijkl\n",
" ^ ^ ^ "); " ^ ^ ^ ",
assert_eq!(result, " ^ ^ ^ ",
vec!["- \tabcDefghiJkl\n", "? \t ^ ^ ^\n", "+ \tabcdefGhijkl\n", "? \t ^ ^ ^\n"]); );
assert_eq!(
result,
vec![
"- \tabcDefghiJkl\n",
"? \t ^ ^ ^\n",
"+ \tabcdefGhijkl\n",
"? \t ^ ^ ^\n",
]
);
} }
+41 -34
View File
@@ -1,18 +1,17 @@
pub mod sequencematcher;
pub mod differ; pub mod differ;
pub mod sequencematcher;
mod utils; mod utils;
use sequencematcher::{Sequence, SequenceMatcher};
use std::collections::HashMap; use std::collections::HashMap;
use sequencematcher::{SequenceMatcher, Sequence}; use utils::{format_range_context, format_range_unified};
use utils::{format_range_unified, format_range_context};
pub fn get_close_matches<'a>(
pub fn get_close_matches<'a>(word: &str, word: &str,
possibilities: Vec<&'a str>, possibilities: Vec<&'a str>,
n: usize, n: usize,
cutoff: f32) cutoff: f32,
-> Vec<&'a str> { ) -> Vec<&'a str> {
if !(0.0 <= cutoff && cutoff <= 1.0) { if !(0.0 <= cutoff && cutoff <= 1.0) {
panic!("Cutoff must be greater than 0.0 and lower than 1.0"); panic!("Cutoff must be greater than 0.0 and lower than 1.0");
} }
@@ -30,14 +29,15 @@ pub fn get_close_matches<'a>(word: &str,
res.iter().map(|x| x.1).collect() res.iter().map(|x| x.1).collect()
} }
pub fn unified_diff<T: Sequence>(first_sequence: &T, pub fn unified_diff<T: Sequence>(
second_sequence: &T, first_sequence: &T,
from_file: &str, second_sequence: &T,
to_file: &str, from_file: &str,
from_file_date: &str, to_file: &str,
to_file_date: &str, from_file_date: &str,
n: usize) to_file_date: &str,
-> Vec<String> { n: usize,
) -> Vec<String> {
let mut res = Vec::new(); let mut res = Vec::new();
let lineterm = '\n'; let lineterm = '\n';
let mut started = false; let mut started = false;
@@ -53,7 +53,10 @@ pub fn unified_diff<T: Sequence>(first_sequence: &T,
let (first, last) = (group.first().unwrap(), group.last().unwrap()); let (first, last) = (group.first().unwrap(), group.last().unwrap());
let file1_range = format_range_unified(first.first_start, last.first_end); let file1_range = format_range_unified(first.first_start, last.first_end);
let file2_range = format_range_unified(first.second_start, last.second_end); let file2_range = format_range_unified(first.second_start, last.second_end);
res.push(format!("@@ -{} +{} @@{}", file1_range, file2_range, lineterm)); res.push(format!(
"@@ -{} +{} @@{}",
file1_range, file2_range, lineterm
));
for code in group { for code in group {
if code.tag == "equal" { if code.tag == "equal" {
for i in code.first_start..code.first_end { for i in code.first_start..code.first_end {
@@ -76,15 +79,15 @@ pub fn unified_diff<T: Sequence>(first_sequence: &T,
res res
} }
pub fn context_diff<T: Sequence>(
pub fn context_diff<T: Sequence>(first_sequence: &T, first_sequence: &T,
second_sequence: &T, second_sequence: &T,
from_file: &str, from_file: &str,
to_file: &str, to_file: &str,
from_file_date: &str, from_file_date: &str,
to_file_date: &str, to_file_date: &str,
n: usize) n: usize,
-> Vec<String> { ) -> Vec<String> {
let mut res = Vec::new(); let mut res = Vec::new();
let lineterm = '\n'; let lineterm = '\n';
let mut prefix: HashMap<String, String> = HashMap::new(); let mut prefix: HashMap<String, String> = HashMap::new();
@@ -117,9 +120,11 @@ pub fn context_diff<T: Sequence>(first_sequence: &T,
for opcode in group { for opcode in group {
if opcode.tag != "insert" { if opcode.tag != "insert" {
for i in opcode.first_start..opcode.first_end { for i in opcode.first_start..opcode.first_end {
res.push(format!("{}{}", res.push(format!(
prefix.get(&opcode.tag).unwrap(), "{}{}",
first_sequence.at_index(i).unwrap())); prefix.get(&opcode.tag).unwrap(),
first_sequence.at_index(i).unwrap()
));
} }
} }
} }
@@ -137,9 +142,11 @@ pub fn context_diff<T: Sequence>(first_sequence: &T,
for opcode in group { for opcode in group {
if opcode.tag != "delete" { if opcode.tag != "delete" {
for i in opcode.second_start..opcode.second_end { for i in opcode.second_start..opcode.second_end {
res.push(format!("{}{}", res.push(format!(
prefix.get(&opcode.tag).unwrap(), "{}{}",
second_sequence.at_index(i).unwrap())); prefix.get(&opcode.tag).unwrap(),
second_sequence.at_index(i).unwrap()
));
} }
} }
} }
+60 -41
View File
@@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet};
use std::cmp::{max, min}; use std::cmp::{max, min};
use utils::calculate_ratio; use std::collections::{HashMap, HashSet};
use std::fmt::Debug; use std::fmt::Debug;
use utils::calculate_ratio;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
pub struct Match { pub struct Match {
@@ -30,12 +30,13 @@ pub struct Opcode {
} }
impl Opcode { impl Opcode {
fn new(tag: String, fn new(
first_start: usize, tag: String,
first_end: usize, first_start: usize,
second_start: usize, first_end: usize,
second_end: usize) second_start: usize,
-> Opcode { second_end: usize,
) -> Opcode {
Opcode { Opcode {
tag: tag, tag: tag,
first_start: first_start, first_start: first_start,
@@ -113,7 +114,6 @@ pub struct SequenceMatcher<'a, T: 'a + ?Sized + Sequence> {
second_sequence_popular: HashSet<&'a str>, second_sequence_popular: HashSet<&'a str>,
} }
impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> { impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
pub fn new(first_sequence: &'a T, second_sequence: &'a T) -> SequenceMatcher<'a, T> { pub fn new(first_sequence: &'a T, second_sequence: &'a T) -> SequenceMatcher<'a, T> {
let mut matcher = SequenceMatcher { let mut matcher = SequenceMatcher {
@@ -156,7 +156,8 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
let second_sequence = self.second_sequence; let second_sequence = self.second_sequence;
let mut second_sequence_elements = HashMap::new(); let mut second_sequence_elements = HashMap::new();
for i in 0..second_sequence.len() { for i in 0..second_sequence.len() {
let mut counter = second_sequence_elements.entry(second_sequence.at_index(i).unwrap()) let mut counter = second_sequence_elements
.entry(second_sequence.at_index(i).unwrap())
.or_insert(Vec::new()); .or_insert(Vec::new());
counter.push(i); counter.push(i);
} }
@@ -188,12 +189,13 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
self.second_sequence_popular = popular; self.second_sequence_popular = popular;
} }
pub fn find_longest_match(&self, pub fn find_longest_match(
first_start: usize, &self,
first_end: usize, first_start: usize,
second_start: usize, first_end: usize,
second_end: usize) second_start: usize,
-> Match { second_end: usize,
) -> Match {
let first_sequence = &self.first_sequence; let first_sequence = &self.first_sequence;
let second_sequence = &self.second_sequence; let second_sequence = &self.second_sequence;
let second_sequence_elements = &self.second_sequence_elements; let second_sequence_elements = &self.second_sequence_elements;
@@ -234,15 +236,18 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
j2len = new_j2len; j2len = new_j2len;
} }
for _ in 0..2 { for _ in 0..2 {
while best_i > first_start && best_j > second_start && while best_i > first_start
first_sequence.at_index(best_i - 1) == second_sequence.at_index(best_j - 1) { && best_j > second_start
&& first_sequence.at_index(best_i - 1) == second_sequence.at_index(best_j - 1)
{
best_i = best_i - 1; best_i = best_i - 1;
best_j = best_j - 1; best_j = best_j - 1;
best_size = best_size + 1; best_size = best_size + 1;
} }
while best_i + best_size < first_end && best_j + best_size < second_end && while best_i + best_size < first_end && best_j + best_size < second_end
first_sequence.at_index(best_i + best_size) == && first_sequence.at_index(best_i + best_size)
second_sequence.at_index(best_j + best_size) { == second_sequence.at_index(best_j + best_size)
{
best_size += 1; best_size += 1;
} }
} }
@@ -266,10 +271,12 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
queue.push((first_start, m.first_start, second_start, m.second_start)); queue.push((first_start, m.first_start, second_start, m.second_start));
} }
if m.first_start + m.size < first_end && m.second_start + m.size < second_end { if m.first_start + m.size < first_end && m.second_start + m.size < second_end {
queue.push((m.first_start + m.size, queue.push((
first_end, m.first_start + m.size,
m.second_start + m.size, first_end,
second_end)); m.second_start + m.size,
second_end,
));
} }
matches.push(m); matches.push(m);
} }
@@ -319,9 +326,13 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
i = m.first_start + m.size; i = m.first_start + m.size;
j = m.second_start + m.size; j = m.second_start + m.size;
if m.size != 0 { if m.size != 0 {
opcodes.push( opcodes.push(Opcode::new(
Opcode::new(String::from("equal"), m.first_start, i, m.second_start, j) String::from("equal"),
); m.first_start,
i,
m.second_start,
j,
));
} }
} }
self.opcodes = Some(opcodes); self.opcodes = Some(opcodes);
@@ -350,21 +361,25 @@ Opcode::new(String::from("equal"), m.first_start, i, m.second_start, j)
for code in &codes { for code in &codes {
let (mut first_start, mut second_start) = (code.first_start, code.second_start); let (mut first_start, mut second_start) = (code.first_start, code.second_start);
if code.tag == "equal" && code.first_end - code.first_start > nn { if code.tag == "equal" && code.first_end - code.first_start > nn {
group.push(Opcode::new(code.tag.clone(), group.push(Opcode::new(
code.first_start, code.tag.clone(),
min(code.first_end, code.first_start + n), code.first_start,
code.second_start, min(code.first_end, code.first_start + n),
min(code.second_end, code.second_start + n))); code.second_start,
min(code.second_end, code.second_start + n),
));
res.push(group.clone()); res.push(group.clone());
group.clear(); group.clear();
first_start = max(first_start, code.first_end.saturating_sub(n)); first_start = max(first_start, code.first_end.saturating_sub(n));
second_start = max(second_start, code.second_end.saturating_sub(n)); second_start = max(second_start, code.second_end.saturating_sub(n));
} }
group.push(Opcode::new(code.tag.clone(), group.push(Opcode::new(
first_start, code.tag.clone(),
code.first_end, first_start,
second_start, code.first_end,
code.second_end)); second_start,
code.second_end,
));
} }
if !group.is_empty() && !(group.len() == 1 && group.first().unwrap().tag == "equal") { if !group.is_empty() && !(group.len() == 1 && group.first().unwrap().tag == "equal") {
res.push(group.clone()); res.push(group.clone());
@@ -373,8 +388,12 @@ Opcode::new(String::from("equal"), m.first_start, i, m.second_start, j)
} }
pub fn ratio(&mut self) -> f32 { pub fn ratio(&mut self) -> f32 {
let matches = self.get_matching_blocks().iter().fold(0, |res, &m| res + m.size); let matches = self.get_matching_blocks()
calculate_ratio(matches, .iter()
self.first_sequence.len() + self.second_sequence.len()) .fold(0, |res, &m| res + m.size);
calculate_ratio(
matches,
self.first_sequence.len() + self.second_sequence.len(),
)
} }
} }
-4
View File
@@ -5,7 +5,6 @@ pub fn calculate_ratio(matches: usize, length: usize) -> f32 {
return 1.0; return 1.0;
} }
pub fn str_with_similar_chars(c: char, length: usize) -> String { pub fn str_with_similar_chars(c: char, length: usize) -> String {
let mut s = String::new(); let mut s = String::new();
for _ in 0..length { for _ in 0..length {
@@ -14,7 +13,6 @@ pub fn str_with_similar_chars(c: char, length: usize) -> String {
s s
} }
pub fn count_leading(line: &str, c: char) -> usize { pub fn count_leading(line: &str, c: char) -> usize {
let (mut i, n) = (0, line.len()); let (mut i, n) = (0, line.len());
let line: Vec<char> = line.chars().collect(); let line: Vec<char> = line.chars().collect();
@@ -24,7 +22,6 @@ pub fn count_leading(line: &str, c: char) -> usize {
return i; return i;
} }
pub fn format_range_unified(start: usize, end: usize) -> String { pub fn format_range_unified(start: usize, end: usize) -> String {
let mut beginning = start + 1; let mut beginning = start + 1;
let length = end - start; let length = end - start;
@@ -37,7 +34,6 @@ pub fn format_range_unified(start: usize, end: usize) -> String {
format!("{},{}", beginning, length) format!("{},{}", beginning, length)
} }
pub fn format_range_context(start: usize, end: usize) -> String { pub fn format_range_context(start: usize, end: usize) -> String {
let mut beginning = start + 1; let mut beginning = start + 1;
let length = end - start; let length = end - start;
+38 -28
View File
@@ -1,7 +1,7 @@
extern crate difflib; extern crate difflib;
use difflib::sequencematcher::{SequenceMatcher, Match, Opcode};
use difflib::differ::Differ; use difflib::differ::Differ;
use difflib::sequencematcher::{Match, Opcode, SequenceMatcher};
#[test] #[test]
fn test_longest_match() { fn test_longest_match() {
@@ -97,8 +97,10 @@ fn test_differ_compare() {
let second_text = vec!["ore\n", "tree\n", "emu\n"]; let second_text = vec!["ore\n", "tree\n", "emu\n"];
let differ = Differ::new(); let differ = Differ::new();
let result = differ.compare(&first_text, &second_text).join(""); let result = differ.compare(&first_text, &second_text).join("");
assert_eq!(result, assert_eq!(
"- one\n? ^\n+ ore\n? ^\n- two\n- three\n? -\n+ tree\n+ emu\n"); result,
"- one\n? ^\n+ ore\n? ^\n- two\n- three\n? -\n+ tree\n+ emu\n"
);
} }
fn is_junk_char(ch: &str) -> bool { fn is_junk_char(ch: &str) -> bool {
@@ -115,8 +117,10 @@ fn test_differ_compare_with_func() {
let mut differ = Differ::new(); let mut differ = Differ::new();
differ.char_junk = Some(is_junk_char); differ.char_junk = Some(is_junk_char);
let result = differ.compare(&first_text, &second_text).join(""); let result = differ.compare(&first_text, &second_text).join("");
assert_eq!(result, assert_eq!(
"- one\n? ^\n+ ore\n? ^\n- two\n- three\n? -\n+ tree\n+ emu\n"); result,
"- one\n? ^\n+ ore\n? ^\n- two\n- three\n? -\n+ tree\n+ emu\n"
);
} }
#[test] #[test]
@@ -133,33 +137,39 @@ fn test_differ_restore() {
fn test_unified_diff() { fn test_unified_diff() {
let first_text = "one two three four".split(" ").collect::<Vec<&str>>(); let first_text = "one two three four".split(" ").collect::<Vec<&str>>();
let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>(); let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>();
let result = difflib::unified_diff(&first_text, let result = difflib::unified_diff(
&second_text, &first_text,
"Original", &second_text,
"Current", "Original",
"2005-01-26 23:30:50", "Current",
"2010-04-02 10:20:52", "2005-01-26 23:30:50",
3) "2010-04-02 10:20:52",
.join(""); 3,
assert_eq!(result, ).join("");
"--- Original\t2005-01-26 23:30:50\n+++ Current\t2010-04-02 10:20:52\n@@ -1,4 \ assert_eq!(
+1,4 @@\n+zero one-two-three+tree four"); result,
"--- Original\t2005-01-26 23:30:50\n+++ Current\t2010-04-02 10:20:52\n@@ -1,4 \
+1,4 @@\n+zero one-two-three+tree four"
);
} }
#[test] #[test]
fn test_context_diff() { fn test_context_diff() {
let first_text = "one two three four".split(" ").collect::<Vec<&str>>(); let first_text = "one two three four".split(" ").collect::<Vec<&str>>();
let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>(); let second_text = "zero one tree four".split(" ").collect::<Vec<&str>>();
let result = difflib::context_diff(&first_text, let result = difflib::context_diff(
&second_text, &first_text,
"Original", &second_text,
"Current", "Original",
"2005-01-26 23:30:50", "Current",
"2010-04-02 10:20:52", "2005-01-26 23:30:50",
3) "2010-04-02 10:20:52",
.join(""); 3,
assert_eq!(result, ).join("");
"*** Original\t2005-01-26 23:30:50\n--- Current\t2010-04-02 \ assert_eq!(
10:20:52\n***************\n*** 1,4 ****\n one! two! three four--- 1,4 ----\n+ \ result,
zero one! tree four"); "*** Original\t2005-01-26 23:30:50\n--- Current\t2010-04-02 \
10:20:52\n***************\n*** 1,4 ****\n one! two! three four--- 1,4 ----\n+ \
zero one! tree four"
);
} }