-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Attempt at fixing find_common_string #540
base: main
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,12 +145,24 @@ pub fn parse_selection_char(buffer: &str, marker: char) -> ParseResult { | |
pub fn find_common_string(values: &[Suggestion]) -> (Option<&Suggestion>, Option<usize>) { | ||
let first = values.iter().next(); | ||
|
||
let mut new_index: Option<usize> = match first { | ||
Some(first) => Some(first.value.len()), | ||
None => Some(0), | ||
}; | ||
|
||
if values.len() <= 1 { | ||
return (first, new_index); | ||
} | ||
Comment on lines
+153
to
+155
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe worth adding a comment what the different cases are. We have this early return and the chain from hell below. |
||
|
||
let index = first.and_then(|first| { | ||
values.iter().skip(1).fold(None, |index, suggestion| { | ||
if suggestion.value.starts_with(&first.value) { | ||
Some(first.value.len()) | ||
} else { | ||
first | ||
let vals = values | ||
.iter() | ||
.skip(1) | ||
.try_fold(None, |index: Option<usize>, suggestion| { | ||
if first.value.get(..1) != suggestion.value.get(..1) { | ||
return Err(0); | ||
} | ||
let tmp_index = first | ||
.value | ||
.char_indices() | ||
.zip(suggestion.value.char_indices()) | ||
|
@@ -169,9 +181,18 @@ pub fn find_common_string(values: &[Suggestion]) -> (Option<&Suggestion>, Option | |
} | ||
} | ||
None => new_index, | ||
}) | ||
} | ||
}) | ||
}); | ||
|
||
if tmp_index > Some(0) { | ||
new_index = tmp_index; | ||
} | ||
Ok(new_index) | ||
}); | ||
|
||
match vals { | ||
Ok(index) => index, | ||
Err(_) => Some(0), | ||
} | ||
}); | ||
|
||
(first, index) | ||
|
@@ -250,6 +271,8 @@ pub fn string_difference<'a>(new_string: &'a str, old_string: &str) -> (usize, & | |
|
||
#[cfg(test)] | ||
mod tests { | ||
use itertools::Itertools; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
|
@@ -451,9 +474,28 @@ mod tests { | |
fn find_common_string_with_ansi() { | ||
use crate::Span; | ||
|
||
let input: Vec<_> = ["nushell", "null"] | ||
let source = [ | ||
"qml", | ||
"qmake", | ||
"qmltc", | ||
"qmlls", | ||
"qmldom", | ||
"qmake6", | ||
"qmltime", | ||
"qmllint", | ||
"qmlscene", | ||
"qmlformat", | ||
"qmleasing", | ||
"qmlpreview", | ||
"qmlprofiler", | ||
"qmlplugindump", | ||
"qmltestrunner", | ||
]; | ||
// Test against empty haystack | ||
let input: Vec<_> = source | ||
.into_iter() | ||
.map(|s| Suggestion { | ||
.take(0) | ||
.map(|s: &str| Suggestion { | ||
value: s.into(), | ||
description: None, | ||
extra: None, | ||
|
@@ -463,7 +505,101 @@ mod tests { | |
.collect(); | ||
let res = find_common_string(&input); | ||
|
||
assert!(matches!(res, (Some(elem), Some(2)) if elem == &input[0])); | ||
match res.0 { | ||
Some(_) => assert!(false, "There shouldn't be any elements"), | ||
None => assert!(res.1 == Some(0)), | ||
} | ||
|
||
// Test against haystack of size 1 | ||
let input: Vec<_> = source | ||
.into_iter() | ||
.take(1) | ||
.map(|s: &str| Suggestion { | ||
value: s.into(), | ||
description: None, | ||
extra: None, | ||
span: Span::new(0, s.len()), | ||
append_whitespace: false, | ||
}) | ||
.collect(); | ||
let res = find_common_string(&input); | ||
|
||
match res { | ||
(Some(first), Some(index)) => assert!( | ||
first.value == input.first().unwrap().value && index == first.value.len()), | ||
_ => assert!(false, "There should be a result with both options as some with one element to check against"), | ||
} | ||
Comment on lines
+513
to
+531
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This whole pattern is repeated, can we factor it out so the tests are more readable and we are more confident what the differences between the tests are (and avoid introducing a bug in the test fixture) |
||
|
||
// Test against entire haystack that's originally errored | ||
let input: Vec<_> = source | ||
.into_iter() | ||
.map(|s: &str| Suggestion { | ||
value: s.into(), | ||
description: None, | ||
extra: None, | ||
span: Span::new(0, s.len()), | ||
append_whitespace: false, | ||
}) | ||
.collect(); | ||
let res = find_common_string(&input); | ||
|
||
match res { | ||
(Some(first), Some(index)) => { | ||
assert!(res.1 == Some(2), "Index check failed for full haystack"); | ||
input.iter().for_each(|suggestion| { | ||
assert!(first.value.chars().take(index - 1).collect::<String>() == suggestion.value.chars().take(index - 1).collect::<String>()) | ||
}) | ||
}, | ||
_ => assert!(false, "There should be a result with both options as some with one element to check against for full haystack"), | ||
} | ||
|
||
// Test against reduced haystack | ||
let input: Vec<_> = source | ||
.into_iter() | ||
.filter(|i| i.starts_with("qma")) | ||
.collect_vec() | ||
.into_iter() | ||
.map(|s: &str| Suggestion { | ||
value: s.into(), | ||
description: None, | ||
extra: None, | ||
span: Span::new(0, s.len()), | ||
append_whitespace: false, | ||
}) | ||
.into_iter() | ||
.collect(); | ||
let res = find_common_string(&input); | ||
|
||
match res { | ||
(Some(first), Some(index)) => { | ||
assert!(res.1 == Some(5), "Index check failed for haystack of 'qma*'"); | ||
input.iter().for_each(|suggestion| { | ||
assert!(first.value.chars().take(index - 1).collect::<String>() == suggestion.value.chars().take(index - 1).collect::<String>()) | ||
}) | ||
}, | ||
_ => assert!(false, "There should be a result with both options as some with one element to check against for reduced haystack"), | ||
} | ||
|
||
// Test against reduced haystack that differs at first character | ||
let input: Vec<_> = ["qma", "lsf"] | ||
.into_iter() | ||
.map(|s: &str| Suggestion { | ||
value: s.into(), | ||
description: None, | ||
extra: None, | ||
span: Span::new(0, s.len()), | ||
append_whitespace: false, | ||
}) | ||
.into_iter() | ||
.collect(); | ||
let res = find_common_string(&input); | ||
|
||
match res { | ||
(Some(_), Some(_)) => { | ||
assert!(res.1 == Some(0), "Index check failed for haystack of different first chars"); | ||
}, | ||
_ => assert!(false, "There should be a result with both options as some with one element to check against for different first chars"), | ||
} | ||
} | ||
|
||
#[test] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a
.map(...).unwrap_or_default()