From a8b65e35ecadb158df35dd8eebe305f2a54928a1 Mon Sep 17 00:00:00 2001 From: Chris Gillespie <6572184+gillespiecd@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:44:24 -0700 Subject: [PATCH] Consolidate suggestions code (#2597) --- crates/nu-cli/src/commands/get.rs | 6 ++--- crates/nu-cli/src/commands/group_by.rs | 26 +-------------------- crates/nu-cli/src/commands/group_by_date.rs | 26 +-------------------- crates/nu-cli/src/commands/split_by.rs | 26 +-------------------- crates/nu-cli/src/utils.rs | 1 + crates/nu-cli/src/utils/suggestions.rs | 21 +++++++++++++++++ crates/nu-protocol/src/value/column_path.rs | 21 +++-------------- crates/nu-value-ext/src/lib.rs | 10 +++++--- crates/nu_plugin_inc/src/inc.rs | 2 +- 9 files changed, 39 insertions(+), 100 deletions(-) create mode 100644 crates/nu-cli/src/utils/suggestions.rs diff --git a/crates/nu-cli/src/commands/get.rs b/crates/nu-cli/src/commands/get.rs index bd9c72e29..1bba16f0a 100644 --- a/crates/nu-cli/src/commands/get.rs +++ b/crates/nu-cli/src/commands/get.rs @@ -129,7 +129,7 @@ pub fn get_column_path(path: &ColumnPath, obj: &Value) -> Result {} } - if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried) { + if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried.as_string()) { ShellError::labeled_error( "Unknown column", format!("did you mean '{}'?", suggestions[0]), @@ -155,7 +155,7 @@ pub fn get_column_path_from_table_error( let suggestions: IndexSet<_> = rows .iter() - .filter_map(|r| did_you_mean(&r, &column_path_tried)) + .filter_map(|r| did_you_mean(&r, column_path_tried.as_string())) .map(|s| s[0].to_owned()) .collect(); let mut existing_columns: IndexSet<_> = IndexSet::default(); @@ -232,7 +232,7 @@ pub fn get_column_from_row_error( } => { let primary_label = format!("There isn't a column named '{}'", &column); - if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried) { + if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried.as_string()) { Some(ShellError::labeled_error_with_secondary( "Unknown column", primary_label, diff --git a/crates/nu-cli/src/commands/group_by.rs b/crates/nu-cli/src/commands/group_by.rs index fba2d4b27..36cc0b8a5 100644 --- a/crates/nu-cli/src/commands/group_by.rs +++ b/crates/nu-cli/src/commands/group_by.rs @@ -1,5 +1,6 @@ use crate::commands::WholeStreamCommand; use crate::prelude::*; +use crate::utils::suggestions::suggestions; use indexmap::indexmap; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; @@ -187,31 +188,6 @@ pub async fn group_by( Ok(OutputStream::one(ReturnSuccess::value(group_value?))) } -pub fn suggestions(tried: Tagged<&str>, for_value: &Value) -> ShellError { - let possibilities = for_value.data_descriptors(); - - let mut possible_matches: Vec<_> = possibilities - .iter() - .map(|x| (natural::distance::levenshtein_distance(x, &tried), x)) - .collect(); - - possible_matches.sort(); - - if !possible_matches.is_empty() { - ShellError::labeled_error( - "Unknown column", - format!("did you mean '{}'?", possible_matches[0].1), - tried.tag(), - ) - } else { - ShellError::labeled_error( - "Unknown column", - "row does not contain this column", - tried.tag(), - ) - } -} - pub fn group( column_name: &Option>, values: &Value, diff --git a/crates/nu-cli/src/commands/group_by_date.rs b/crates/nu-cli/src/commands/group_by_date.rs index 834443dff..6f3190cd6 100644 --- a/crates/nu-cli/src/commands/group_by_date.rs +++ b/crates/nu-cli/src/commands/group_by_date.rs @@ -1,5 +1,6 @@ use crate::commands::WholeStreamCommand; use crate::prelude::*; +use crate::utils::suggestions::suggestions; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; @@ -137,31 +138,6 @@ pub async fn group_by_date( } } -pub fn suggestions(tried: Tagged<&str>, for_value: &Value) -> ShellError { - let possibilities = for_value.data_descriptors(); - - let mut possible_matches: Vec<_> = possibilities - .iter() - .map(|x| (natural::distance::levenshtein_distance(x, &tried), x)) - .collect(); - - possible_matches.sort(); - - if !possible_matches.is_empty() { - ShellError::labeled_error( - "Unknown column", - format!("did you mean '{}'?", possible_matches[0].1), - tried.tag(), - ) - } else { - ShellError::labeled_error( - "Unknown column", - "row does not contain this column", - tried.tag(), - ) - } -} - #[cfg(test)] mod tests { use super::GroupByDate; diff --git a/crates/nu-cli/src/commands/split_by.rs b/crates/nu-cli/src/commands/split_by.rs index 5ce75be9f..52b419354 100644 --- a/crates/nu-cli/src/commands/split_by.rs +++ b/crates/nu-cli/src/commands/split_by.rs @@ -1,5 +1,6 @@ use crate::commands::WholeStreamCommand; use crate::prelude::*; +use crate::utils::suggestions::suggestions; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, Value}; use nu_source::Tagged; @@ -96,31 +97,6 @@ pub fn split( } } -pub fn suggestions(tried: Tagged<&str>, for_value: &Value) -> ShellError { - let possibilities = for_value.data_descriptors(); - - let mut possible_matches: Vec<_> = possibilities - .iter() - .map(|x| (natural::distance::levenshtein_distance(x, &tried), x)) - .collect(); - - possible_matches.sort(); - - if !possible_matches.is_empty() { - ShellError::labeled_error( - "Unknown column", - format!("did you mean '{}'?", possible_matches[0].1), - tried.tag(), - ) - } else { - ShellError::labeled_error( - "Unknown column", - "row does not contain this column", - tried.tag(), - ) - } -} - #[cfg(test)] mod tests { use super::split; diff --git a/crates/nu-cli/src/utils.rs b/crates/nu-cli/src/utils.rs index 31f21ca91..1c049b3b9 100644 --- a/crates/nu-cli/src/utils.rs +++ b/crates/nu-cli/src/utils.rs @@ -1,3 +1,4 @@ +pub mod suggestions; pub mod test_bins; use crate::path::canonicalize; diff --git a/crates/nu-cli/src/utils/suggestions.rs b/crates/nu-cli/src/utils/suggestions.rs new file mode 100644 index 000000000..b96ee86ec --- /dev/null +++ b/crates/nu-cli/src/utils/suggestions.rs @@ -0,0 +1,21 @@ +use crate::did_you_mean; +use nu_errors::ShellError; +use nu_protocol::Value; +use nu_source::Tagged; + +pub fn suggestions(tried: Tagged<&str>, for_value: &Value) -> ShellError { + let possibilities = did_you_mean(for_value, tried.to_string()); + + match possibilities { + Some(p) => ShellError::labeled_error( + "Unknown column", + format!("did you mean '{}'?", p[0]), + tried.tag(), + ), + None => ShellError::labeled_error( + "Unknown column", + "row does not contain this column", + tried.tag(), + ), + } +} diff --git a/crates/nu-protocol/src/value/column_path.rs b/crates/nu-protocol/src/value/column_path.rs index ca19ea370..dc632bc32 100644 --- a/crates/nu-protocol/src/value/column_path.rs +++ b/crates/nu-protocol/src/value/column_path.rs @@ -114,12 +114,7 @@ impl PathMember { } /// Prepares a list of "sounds like" matches (using edit distance) for the string you're trying to find -pub fn did_you_mean(obj_source: &Value, field_tried: &PathMember) -> Option> { - let field_tried = match &field_tried.unspanned { - UnspannedPathMember::String(string) => string.clone(), - UnspannedPathMember::Int(int) => format!("{}", int), - }; - +pub fn did_you_mean(obj_source: &Value, field_tried: String) -> Option> { let possibilities = obj_source.data_descriptors(); let mut possible_matches: Vec<_> = possibilities @@ -159,18 +154,13 @@ mod test { value, }; - let guess = PathMember { - unspanned: UnspannedPathMember::String("hat".to_string()), - span: Default::default(), - }; - assert_eq!( Some(vec![ "cat".to_string(), "alt".to_string(), "dog".to_string() ]), - did_you_mean(&source, &guess) + did_you_mean(&source, "hat".to_string()) ) } @@ -181,11 +171,6 @@ mod test { value: UntaggedValue::row(indexmap! {}), }; - let guess = PathMember { - unspanned: UnspannedPathMember::String("hat".to_string()), - span: Default::default(), - }; - - assert_eq!(None, did_you_mean(&empty_source, &guess)) + assert_eq!(None, did_you_mean(&empty_source, "hat".to_string())) } } diff --git a/crates/nu-value-ext/src/lib.rs b/crates/nu-value-ext/src/lib.rs index 716ffef5f..e86135985 100644 --- a/crates/nu-value-ext/src/lib.rs +++ b/crates/nu-value-ext/src/lib.rs @@ -238,7 +238,9 @@ where let suggestions: IndexSet<_> = rows .iter() - .filter_map(|r| nu_protocol::did_you_mean(&r, &column_path_tried)) + .filter_map(|r| { + nu_protocol::did_you_mean(&r, column_path_tried.as_string()) + }) .map(|s| s[0].to_owned()) .collect(); let mut existing_columns: IndexSet<_> = IndexSet::default(); @@ -308,7 +310,7 @@ where let primary_label = format!("There isn't a column named '{}'", &column); if let Some(suggestions) = - nu_protocol::did_you_mean(&obj_source, &column_path_tried) + nu_protocol::did_you_mean(&obj_source, column_path_tried.as_string()) { return ShellError::labeled_error_with_secondary( "Unknown column", @@ -342,7 +344,9 @@ where _ => {} } - if let Some(suggestions) = nu_protocol::did_you_mean(&obj_source, &column_path_tried) { + if let Some(suggestions) = + nu_protocol::did_you_mean(&obj_source, column_path_tried.as_string()) + { return ShellError::labeled_error( "Unknown column", format!("did you mean '{}'?", suggestions[0]), diff --git a/crates/nu_plugin_inc/src/inc.rs b/crates/nu_plugin_inc/src/inc.rs index 4a944c6a4..1ef26b4ec 100644 --- a/crates/nu_plugin_inc/src/inc.rs +++ b/crates/nu_plugin_inc/src/inc.rs @@ -105,7 +105,7 @@ impl Inc { &f, move |obj_source, column_path_tried, _| match did_you_mean( &obj_source, - &column_path_tried, + column_path_tried.as_string(), ) { Some(suggestions) => ShellError::labeled_error( "Unknown column",