forked from extern/nushell
Relax the closure syntax, highlight differently (#8846)
# Description This relaxes the closure syntax so that `||` is no longer required. This allows for `ls | each { $in.name }` for example. I've gone ahead and changed the syntax highlighting so that blocks and closures are distinct for now. # User-Facing Changes Removes `||` requirement for closures. # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
parent
46dba8853a
commit
8ee52b6ee1
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user