From f3d92e3fa1ee8d42fe1ef79225247fd849afb1cc Mon Sep 17 00:00:00 2001 From: Bahex Date: Fri, 25 Jul 2025 08:19:15 +0300 Subject: [PATCH] fix bare interpolation regression (#16235) Regression from #16204 Before: ![](https://raw.githubusercontent.com/gist/Bahex/d9b654c119625a43fbf5fa05939648bb/raw/f1995bc71f2f5c51068df8dad72823379799443a/before.svg) After: ![](https://raw.githubusercontent.com/gist/Bahex/d9b654c119625a43fbf5fa05939648bb/raw/f1995bc71f2f5c51068df8dad72823379799443a/after.svg) # Tests + Formatting +1 --------- Co-authored-by: Bahex <17417311+Bahex@users.noreply.github.com> --- crates/nu-parser/src/parser.rs | 6 +++- crates/nu-parser/tests/test_parser.rs | 40 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 6eb87aadc2..418f0dca70 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -2004,7 +2004,11 @@ pub fn parse_paren_expr( if fcp_error_count > starting_error_count { let malformed_subexpr = working_set.parse_errors[starting_error_count..] .first() - .is_some_and(|e| matches!(e, ParseError::Unclosed(right, _) if right == ")" )); + .is_some_and(|e| match e { + ParseError::Unclosed(right, _) if (right == ")") => true, + ParseError::Unbalanced(left, right, _) if left == "(" && right == ")" => true, + _ => false, + }); if malformed_subexpr { working_set.parse_errors.truncate(starting_error_count); parse_string_interpolation(working_set, span) diff --git a/crates/nu-parser/tests/test_parser.rs b/crates/nu-parser/tests/test_parser.rs index be6c515987..2267916322 100644 --- a/crates/nu-parser/tests/test_parser.rs +++ b/crates/nu-parser/tests/test_parser.rs @@ -1636,6 +1636,46 @@ mod string { assert_eq!(subexprs[3], &Expr::String("bar".to_string())); } + /// PR with summary of the issue: https://github.com/nushell/nushell/pull/16235 + /// Release Notes Mention: https://www.nushell.sh/blog/2025-07-23-nushell_0_106_0.html#regression-bare-word-interpolation-on-both-sides-does-not-work-toc + #[test] + pub fn parse_string_interpolation_bare_starting_and_ending_subexpr() { + let engine_state = EngineState::new(); + let mut working_set = StateWorkingSet::new(&engine_state); + + let block = parse( + &mut working_set, + None, + b"(100 + 20 + 3)/bar/(300 + 20 + 1)", + true, + ); + + assert!(working_set.parse_errors.is_empty(),); + + let [pipeline] = block.pipelines.as_slice() else { + panic!("expected 1 pipeline") + }; + let [element] = pipeline.elements.as_slice() else { + panic!("expected 1 pipeline element") + }; + assert!(element.redirection.is_none()); + + let Expr::StringInterpolation(expressions) = &element.expr.expr else { + panic!("Expected an `Expr::StringInterpolation`") + }; + let subexprs: Vec<_> = expressions.iter().map(|e| &e.expr).collect(); + + let [ + Expr::FullCellPath(..), + Expr::String(s), + Expr::FullCellPath(..), + ] = subexprs.as_slice() + else { + panic!("AST does not have the expected structure") + }; + assert_eq!(s, "/bar/"); + } + #[test] pub fn parse_string_interpolation_bare_starting_subexpr_external_arg() { let engine_state = EngineState::new();