diff --git a/crates/nu-cli/src/commands.rs b/crates/nu-cli/src/commands.rs index 42de5d1764..a83a16dae7 100644 --- a/crates/nu-cli/src/commands.rs +++ b/crates/nu-cli/src/commands.rs @@ -56,10 +56,6 @@ pub fn evaluate_commands( } }; - // Make a note of the exceptions we see for externals that look like math expressions - let exceptions = crate::util::external_exceptions(engine_state, stack); - engine_state.external_exceptions = exceptions; - // Merge the delta in case env vars changed in the config match nu_engine::env::current_dir(engine_state, stack) { Ok(cwd) => { diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index e3c9d50f81..d7e4b084c7 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -27,10 +27,6 @@ pub fn evaluate_file( std::process::exit(1); } - // Make a note of the exceptions we see for externals that look like math expressions - let exceptions = crate::util::external_exceptions(engine_state, stack); - engine_state.external_exceptions = exceptions; - let file = std::fs::read(&path).into_diagnostic()?; let mut working_set = StateWorkingSet::new(engine_state); diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index c68e41c313..5c0f31b3cb 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -83,10 +83,6 @@ pub fn evaluate_repl( report_error(&working_set, &e); } - // Make a note of the exceptions we see for externals that look like math expressions - let exceptions = crate::util::external_exceptions(engine_state, stack); - engine_state.external_exceptions = exceptions; - // seed env vars stack.add_env_var( "CMD_DURATION_MS".into(), @@ -356,10 +352,6 @@ pub fn evaluate_repl( let _ = std::env::set_current_dir(path); engine_state.env_vars.insert("PWD".into(), cwd); } - - // Make a note of the exceptions we see for externals that look like math expressions - let exceptions = crate::util::external_exceptions(engine_state, stack); - engine_state.external_exceptions = exceptions; } Ok(Signal::CtrlC) => { // `Reedline` clears the line content. New prompt is shown diff --git a/crates/nu-cli/src/util.rs b/crates/nu-cli/src/util.rs index 74101a36f4..2777aaf14a 100644 --- a/crates/nu-cli/src/util.rs +++ b/crates/nu-cli/src/util.rs @@ -326,98 +326,6 @@ fn set_last_exit_code(stack: &mut Stack, exit_code: i64) { ); } -fn seems_like_number(bytes: &[u8]) -> bool { - if bytes.is_empty() { - false - } else { - let b = bytes[0]; - - b == b'0' - || b == b'1' - || b == b'2' - || b == b'3' - || b == b'4' - || b == b'5' - || b == b'6' - || b == b'7' - || b == b'8' - || b == b'9' - || b == b'(' - || b == b'{' - || b == b'[' - || b == b'$' - || b == b'"' - || b == b'\'' - || b == b'-' - } -} - -/// Finds externals that have names that look like math expressions -pub fn external_exceptions(engine_state: &EngineState, stack: &Stack) -> Vec> { - let mut executables = vec![]; - - if let Some(path) = stack.get_env_var(engine_state, "PATH") { - match path { - Value::List { vals, .. } => { - for val in vals { - let path = val.as_string(); - - if let Ok(path) = path { - if let Ok(mut contents) = std::fs::read_dir(path) { - while let Some(Ok(item)) = contents.next() { - if is_executable::is_executable(&item.path()) { - if let Ok(name) = item.file_name().into_string() { - if seems_like_number(name.as_bytes()) { - let name = name.as_bytes().to_vec(); - executables.push(name); - } - } - - if let Some(name) = item.path().file_stem() { - let name = name.to_string_lossy(); - if seems_like_number(name.as_bytes()) { - let name = name.as_bytes().to_vec(); - executables.push(name); - } - } - } - } - } - } - } - } - Value::String { val, .. } => { - for path in std::env::split_paths(&val) { - let path = path.to_string_lossy().to_string(); - - if let Ok(mut contents) = std::fs::read_dir(path) { - while let Some(Ok(item)) = contents.next() { - if is_executable::is_executable(&item.path()) { - if let Ok(name) = item.file_name().into_string() { - if seems_like_number(name.as_bytes()) { - let name = name.as_bytes().to_vec(); - executables.push(name); - } - } - if let Some(name) = item.path().file_stem() { - let name = name.to_string_lossy(); - if seems_like_number(name.as_bytes()) { - let name = name.as_bytes().to_vec(); - executables.push(name); - } - } - } - } - } - } - } - _ => {} - } - } - - executables -} - pub fn report_error( working_set: &StateWorkingSet, error: &(dyn miette::Diagnostic + Send + Sync + 'static), diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index e63e575615..4d6f50dad7 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -44,7 +44,12 @@ fn is_identifier_byte(b: u8) -> bool { b != b'.' && b != b'[' && b != b'(' && b != b'{' } -pub fn is_math_expression_like(bytes: &[u8]) -> bool { +pub fn is_math_expression_like( + working_set: &mut StateWorkingSet, + span: Span, + expand_aliases_denylist: &[usize], +) -> bool { + let bytes = working_set.get_span_contents(span); if bytes.is_empty() { return false; } @@ -55,17 +60,7 @@ pub fn is_math_expression_like(bytes: &[u8]) -> bool { let b = bytes[0]; - b == b'0' - || b == b'1' - || b == b'2' - || b == b'3' - || b == b'4' - || b == b'5' - || b == b'6' - || b == b'7' - || b == b'8' - || b == b'9' - || b == b'(' + if b == b'(' || b == b'{' || b == b'[' || b == b'$' @@ -73,6 +68,34 @@ pub fn is_math_expression_like(bytes: &[u8]) -> bool { || b == b'\'' || b == b'`' || b == b'-' + { + return true; + } + + if parse_number(bytes, span).1.is_none() { + return true; + } + + if parse_filesize(working_set, span).1.is_none() { + return true; + } + + if parse_duration(working_set, span).1.is_none() { + return true; + } + + if parse_binary(working_set, span).1.is_none() { + return true; + } + + if parse_range(working_set, span, expand_aliases_denylist) + .1 + .is_none() + { + return true; + } + + false } fn is_identifier(bytes: &[u8]) -> bool { @@ -869,20 +892,12 @@ pub fn parse_call( for word_span in spans[cmd_start..].iter() { // Find the longest group of words that could form a command - let bytes = working_set.get_span_contents(*word_span); - if is_math_expression_like(bytes) - && bytes != b"true" - && bytes != b"false" - && bytes != b"null" - && bytes != b"not" - && !working_set - .permanent_state - .external_exceptions - .iter() - .any(|x| x == bytes) - { - break; + if is_math_expression_like(working_set, *word_span, expand_aliases_denylist) { + let bytes = working_set.get_span_contents(*word_span); + if bytes != b"true" && bytes != b"false" && bytes != b"null" && bytes != b"not" { + break; + } } name_spans.push(*word_span); @@ -1951,7 +1966,7 @@ pub fn parse_datetime( /// Parse a duration type, eg '10day' pub fn parse_duration( - working_set: &mut StateWorkingSet, + working_set: &StateWorkingSet, span: Span, ) -> (Expression, Option) { trace!("parsing: duration"); @@ -2055,7 +2070,7 @@ pub fn parse_duration_bytes(bytes: &[u8], span: Span) -> Option { /// Parse a unit type, eg '10kb' pub fn parse_filesize( - working_set: &mut StateWorkingSet, + working_set: &StateWorkingSet, span: Span, ) -> (Expression, Option) { trace!("parsing: duration"); @@ -4228,17 +4243,12 @@ pub fn parse_expression( ); } - let bytes = working_set.get_span_contents(spans[pos]); - - let (output, err) = if is_math_expression_like(bytes) - && !working_set - .permanent_state - .external_exceptions - .iter() - .any(|x| x == bytes) + let (output, err) = if is_math_expression_like(working_set, spans[pos], expand_aliases_denylist) { parse_math_expression(working_set, &spans[pos..], None, expand_aliases_denylist) } else { + let bytes = working_set.get_span_contents(spans[pos]); + // For now, check for special parses of certain keywords match bytes { b"def" => ( diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 13cda33906..bf870a8b1d 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -178,9 +178,6 @@ pub struct EngineState { pub env_vars: im::HashMap, #[cfg(feature = "plugin")] pub plugin_signatures: Option, - - // A list of external commands that look like math expressions - pub external_exceptions: Vec>, } pub const NU_VARIABLE_ID: usize = 0; @@ -210,7 +207,6 @@ impl EngineState { env_vars: im::HashMap::new(), #[cfg(feature = "plugin")] plugin_signatures: None, - external_exceptions: vec![], } }