diff --git a/src/checker/mod.rs b/src/checker/mod.rs index e257ebc9..1673c19b 100644 --- a/src/checker/mod.rs +++ b/src/checker/mod.rs @@ -10,6 +10,8 @@ use crate::errors::*; mod cached; use self::cached::Cached; +use std::collections::HashSet; + mod tokenize; pub(crate) use self::hunspell::HunspellChecker; pub(crate) use self::nlprules::NlpRulesChecker; @@ -102,7 +104,7 @@ impl Checker for Checkers { where 'a: 's, { - let mut collective = Vec::>::with_capacity(chunks.len()); + let mut collective = HashSet::>::new(); if let Some(ref hunspell) = self.hunspell { collective.extend(hunspell.check(origin, chunks)?); } @@ -110,9 +112,24 @@ impl Checker for Checkers { collective.extend(nlprule.check(origin, chunks)?); } - collective.sort(); + let mut suggestions: Vec> = Vec::from_iter(collective); + suggestions.sort(); + if suggestions.len() == 0 { + return Ok(suggestions); + } + + // Iterate through suggestions and identify overlapping ones. + let suggestions = Vec::from_iter(suggestions.clone().into_iter().enumerate().filter_map( + |(idx, cur)| { + if idx == 0 || !cur.is_overlapped(&suggestions[idx - 1]) { + Some(cur) + } else { + None + } + }, + )); - Ok(collective) + Ok(suggestions) } } diff --git a/src/suggestion.rs b/src/suggestion.rs index 1fbd3221..dbfe6b87 100644 --- a/src/suggestion.rs +++ b/src/suggestion.rs @@ -315,6 +315,29 @@ pub struct Suggestion<'s> { pub description: Option, } +impl<'s> Suggestion<'s> { + /// Determine if there is overlap. + pub fn is_overlapped(&self, other: &Self) -> bool { + if self.origin != other.origin { + return false; + } + + if self.span.end.line < other.span.start.line || other.span.end.line < self.span.start.line + { + return false; + } + + if self.span.start.line < other.span.start.line + || (self.span.start.line == other.span.start.line + && self.span.start.column < other.span.start.column) + { + self.span.end.column > other.span.start.column + } else { + self.span.start.column < other.span.end.column + } + } +} + impl<'s> fmt::Display for Suggestion<'s> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { use console::Style; @@ -710,15 +733,15 @@ mod tests { let chunk = CheckableChunk::from_str( CONTENT, indexmap::indexmap! { 0..18 => Span { - start: LineColumn { - line: 1, - column: 0, - }, - end: LineColumn { - line: 1, - column: 17, - } + start: LineColumn { + line: 1, + column: 0, + }, + end: LineColumn { + line: 1, + column: 17, } + } }, CommentVariant::TripleSlash, ); @@ -761,15 +784,15 @@ mod tests { let chunk = CheckableChunk::from_str( CONTENT, indexmap::indexmap! { 0..18 => Span { - start: LineColumn { - line: 1, - column: 0, - }, - end: LineColumn { - line: 1, - column: 17, - } + start: LineColumn { + line: 1, + column: 0, + }, + end: LineColumn { + line: 1, + column: 17, } + } }, CommentVariant::TripleSlash, ); @@ -994,4 +1017,82 @@ mod tests { log::info!("fmt debug=\n{:?}\n<", suggestion); log::info!("fmt display=\n{}\n<", suggestion); } + + #[test] + fn overlapped() { + let chunk = CheckableChunk::from_str( + r#"0 +2345 +7@n"#, + indexmap::indexmap! { 0..10 => Span { + start : LineColumn { + line: 7usize, + column: 8usize, + }, + end : LineColumn { + line: 9usize, + column: 4usize, + } + } }, + CommentVariant::TripleSlash, + ); + let suggestion = Suggestion { + detector: Detector::Dummy, + origin: ContentOrigin::TestEntityRust, + chunk: &chunk, + span: Span { + start: LineColumn { + line: 8usize, + column: 1, + }, + end: LineColumn { + line: 8usize, + column: 3, + }, + }, + range: 2..6, + replacements: vec!["whocares".to_owned()], + description: None, + }; + let overlapped_smaller_suggestion = Suggestion { + detector: Detector::Dummy, + origin: ContentOrigin::TestEntityRust, + chunk: &chunk, + span: Span { + start: LineColumn { + line: 8usize, + column: 0, + }, + end: LineColumn { + line: 8usize, + column: 2, + }, + }, + range: 2..6, + replacements: vec!["whocares".to_owned()], + description: None, + }; + + let overlapped_larger_suggestion = Suggestion { + detector: Detector::Dummy, + origin: ContentOrigin::TestEntityRust, + chunk: &chunk, + span: Span { + start: LineColumn { + line: 8usize, + column: 2, + }, + end: LineColumn { + line: 8usize, + column: 3, + }, + }, + range: 2..6, + replacements: vec!["whocares".to_owned()], + description: None, + }; + + assert!(suggestion.is_overlapped(&overlapped_smaller_suggestion)); + assert!(suggestion.is_overlapped(&overlapped_larger_suggestion)); + } }