diff --git a/crates/nu-cli/src/syntax_highlight.rs b/crates/nu-cli/src/syntax_highlight.rs index 38e5d5220..bec6fff28 100644 --- a/crates/nu-cli/src/syntax_highlight.rs +++ b/crates/nu-cli/src/syntax_highlight.rs @@ -111,6 +111,9 @@ impl Highlighter for NuHighlighter { FlatShape::Block => { add_colored_token_with_bracket_highlight!(shape.1, shape.0, next_token) } + FlatShape::Closure => { + add_colored_token_with_bracket_highlight!(shape.1, shape.0, next_token) + } FlatShape::Filepath => add_colored_token(&shape.1, next_token), FlatShape::Directory => add_colored_token(&shape.1, next_token), diff --git a/crates/nu-color-config/src/shape_color.rs b/crates/nu-color-config/src/shape_color.rs index fab25b47e..a3db8a377 100644 --- a/crates/nu-color-config/src/shape_color.rs +++ b/crates/nu-color-config/src/shape_color.rs @@ -9,6 +9,7 @@ pub fn default_shape_color(shape: String) -> Style { "shape_binary" => Style::new().fg(Color::Purple).bold(), "shape_block" => Style::new().fg(Color::Blue).bold(), "shape_bool" => Style::new().fg(Color::LightCyan), + "shape_closure" => Style::new().fg(Color::Green).bold(), "shape_custom" => Style::new().fg(Color::Green), "shape_datetime" => Style::new().fg(Color::Cyan).bold(), "shape_directory" => Style::new().fg(Color::Cyan), diff --git a/crates/nu-parser/src/flatten.rs b/crates/nu-parser/src/flatten.rs index 9182609e4..8ffd35463 100644 --- a/crates/nu-parser/src/flatten.rs +++ b/crates/nu-parser/src/flatten.rs @@ -12,6 +12,7 @@ pub enum FlatShape { Binary, Block, Bool, + Closure, Custom(DeclId), DateTime, Directory, @@ -50,6 +51,7 @@ impl Display for FlatShape { FlatShape::Binary => write!(f, "shape_binary"), FlatShape::Block => write!(f, "shape_block"), FlatShape::Bool => write!(f, "shape_bool"), + FlatShape::Closure => write!(f, "shape_closure"), FlatShape::Custom(_) => write!(f, "shape_custom"), FlatShape::DateTime => write!(f, "shape_datetime"), FlatShape::Directory => write!(f, "shape_directory"), @@ -85,6 +87,7 @@ impl Display for FlatShape { pub fn flatten_block(working_set: &StateWorkingSet, block: &Block) -> Vec<(Span, FlatShape)> { let mut output = vec![]; + for pipeline in &block.pipelines { output.extend(flatten_pipeline(working_set, pipeline)); } @@ -115,10 +118,41 @@ pub fn flatten_expression( output.extend(flatten_expression(working_set, inner_expr)); output } - Expr::Block(block_id) - | Expr::Closure(block_id) - | Expr::RowCondition(block_id) - | Expr::Subexpression(block_id) => { + Expr::Closure(block_id) => { + let outer_span = expr.span; + + let mut output = vec![]; + + let block = working_set.get_block(*block_id); + let flattened = flatten_block(working_set, block); + + if let Some(first) = flattened.first() { + if first.0.start > outer_span.start { + output.push(( + Span::new(outer_span.start, first.0.start), + FlatShape::Closure, + )); + } + } + + let last = if let Some(last) = flattened.last() { + if last.0.end < outer_span.end { + Some((Span::new(last.0.end, outer_span.end), FlatShape::Closure)) + } else { + None + } + } else { + None + }; + + output.extend(flattened); + if let Some(last) = last { + output.push(last) + } + + output + } + Expr::Block(block_id) | Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let outer_span = expr.span; let mut output = vec![]; @@ -149,14 +183,23 @@ pub fn flatten_expression( output } Expr::Call(call) => { - let mut output = vec![(call.head, FlatShape::InternalCall(call.decl_id))]; + let mut output = vec![]; + + if call.head.end != 0 { + // Make sure we don't push synthetic calls + output.push((call.head, FlatShape::InternalCall(call.decl_id))); + } let mut args = vec![]; for positional in call.positional_iter() { - args.extend(flatten_expression(working_set, positional)); + let flattened = flatten_expression(working_set, positional); + args.extend(flattened); } for named in call.named_iter() { - args.push((named.0.span, FlatShape::Flag)); + if named.0.span.end != 0 { + // Ignore synthetic flags + args.push((named.0.span, FlatShape::Flag)); + } if let Some(expr) = &named.2 { args.extend(flatten_expression(working_set, expr)); } diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index c593a855d..b72fd066d 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1589,10 +1589,8 @@ pub fn parse_brace_expr( if matches!(second_token, None) { // If we're empty, that means an empty record or closure - if matches!(shape, SyntaxShape::Closure(None)) { - parse_closure_expression(working_set, shape, span, false) - } else if matches!(shape, SyntaxShape::Closure(Some(_))) { - parse_closure_expression(working_set, shape, span, true) + if matches!(shape, SyntaxShape::Closure(_)) { + parse_closure_expression(working_set, shape, span) } else if matches!(shape, SyntaxShape::Block) { parse_block_expression(working_set, span) } else if matches!(shape, SyntaxShape::MatchBlock) { @@ -1603,13 +1601,11 @@ pub fn parse_brace_expr( } else if matches!(second_token_contents, Some(TokenContents::Pipe)) || matches!(second_token_contents, Some(TokenContents::PipePipe)) { - parse_closure_expression(working_set, shape, span, true) + parse_closure_expression(working_set, shape, span) } else if matches!(third_token, Some(b":")) { parse_full_cell_path(working_set, None, span) - } else if matches!(shape, SyntaxShape::Closure(None)) { - parse_closure_expression(working_set, shape, span, false) - } else if matches!(shape, SyntaxShape::Closure(Some(_))) || matches!(shape, SyntaxShape::Any) { - parse_closure_expression(working_set, shape, span, true) + } else if matches!(shape, SyntaxShape::Closure(_)) || matches!(shape, SyntaxShape::Any) { + parse_closure_expression(working_set, shape, span) } else if matches!(shape, SyntaxShape::Block) { parse_block_expression(working_set, span) } else if matches!(shape, SyntaxShape::MatchBlock) { @@ -4201,7 +4197,6 @@ pub fn parse_closure_expression( working_set: &mut StateWorkingSet, shape: &SyntaxShape, span: Span, - require_pipe: bool, ) -> Expression { trace!("parsing: closure expression"); @@ -4275,15 +4270,7 @@ pub fn parse_closure_expression( Some((Box::new(Signature::new("closure".to_string())), *span)), 1, ), - _ => { - if require_pipe { - working_set.error(ParseError::ClosureMissingPipe(span)); - working_set.exit_scope(); - return garbage(span); - } else { - (None, 0) - } - } + _ => (None, 0), }; // TODO: Finish this diff --git a/crates/nu-protocol/src/parse_error.rs b/crates/nu-protocol/src/parse_error.rs index 54fe0060c..98799ec09 100644 --- a/crates/nu-protocol/src/parse_error.rs +++ b/crates/nu-protocol/src/parse_error.rs @@ -38,13 +38,6 @@ pub enum ParseError { #[diagnostic(code(nu::parser::parse_mismatch))] Expected(String, #[label("expected {0}")] Span), - #[error("Missing || inside closure")] - #[diagnostic( - code(nu::parser::closure_missing_pipe), - help("Try add || to the beginning of closure") - )] - ClosureMissingPipe(#[label("Parsing as a closure, but || is missing")] Span), - #[error("Type mismatch during operation.")] #[diagnostic(code(nu::parser::type_mismatch))] Mismatch(String, String, #[label("expected {0}, found {1}")] Span), // expected, found, span @@ -510,7 +503,6 @@ impl ParseError { ParseError::UnknownOperator(_, _, s) => *s, ParseError::InvalidLiteral(_, _, s) => *s, ParseError::NotAConstant(s) => *s, - ParseError::ClosureMissingPipe(s) => *s, } } } diff --git a/crates/nu-utils/src/sample_config/default_config.nu b/crates/nu-utils/src/sample_config/default_config.nu index 25f818e45..adeafb0f3 100644 --- a/crates/nu-utils/src/sample_config/default_config.nu +++ b/crates/nu-utils/src/sample_config/default_config.nu @@ -57,6 +57,7 @@ let dark_theme = { shape_binary: purple_bold shape_block: blue_bold shape_bool: light_cyan + shape_closure: green_bold shape_custom: green shape_datetime: cyan_bold shape_directory: cyan @@ -140,6 +141,7 @@ let light_theme = { shape_binary: purple_bold shape_block: blue_bold shape_bool: light_cyan + shape_closure: green_bold shape_custom: green shape_datetime: cyan_bold shape_directory: cyan