forked from extern/nushell
More specific errors for missing values in records (#11423)
# Description Currently, when writing a record, if you don't give the value for a field, the syntax error highlights the entire record instead of pinpointing the issue. Here's some examples: ```nushell > { a: 2, 3 } # Missing colon (and value) Error: nu::parser::parse_mismatch × Parse mismatch during operation. ╭─[entry #2:1:1] 1 │ { a: 2, 3 } · ─────┬───── · ╰── expected record ╰──── > { a: 2, 3: } # Missing value Error: nu::parser::parse_mismatch × Parse mismatch during operation. ╭─[entry #3:1:1] 1 │ { a: 2, 3: } · ──────┬───── · ╰── expected record ╰──── > { a: 2, 3 4 } # Missing colon Error: nu::parser::parse_mismatch × Parse mismatch during operation. ╭─[entry #4:1:1] 1 │ { a: 2, 3 4 } · ──────┬────── · ╰── expected record ╰──── ``` In all of them, the entire record is highlighted red because an `Expr::Garbage` is returned covering that whole span: ![image](https://github.com/nushell/nushell/assets/45539777/36660b50-23be-4353-b180-3f84eff3c220) This PR is for highlighting only the part inside the record that could not be parsed. If the record literal is big, an error message pointing to the start of where the parser thinks things went wrong should help people fix their code. # User-Facing Changes Below are screenshots of the new errors: If there's a stray record key right before the record ends, it highlights only that key and tells the user it expected a colon after it: ![image](https://github.com/nushell/nushell/assets/45539777/94503256-8ea2-47dd-b69a-4b520c66f7b6) If the record ends before the value for the last field was given, it highlights the key and colon of that field and tells the user it expected a value after the colon: ![image](https://github.com/nushell/nushell/assets/45539777/2f3837ec-3b35-4b81-8c57-706f8056ac04) If there are two consecutive expressions without a colon between them, it highlights everything from the second expression to the end of the record and tells the user it expected a colon. I was tempted to add a help message suggesting adding a colon in between, but that may not always be the right thing to do. ![image](https://github.com/nushell/nushell/assets/45539777/1abaaaa8-1896-4909-bbb7-9a38cece5250) # Tests + Formatting # After Submitting
This commit is contained in:
parent
ba880277bf
commit
9522052063
@ -5272,15 +5272,43 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression
|
|||||||
|
|
||||||
idx += 1;
|
idx += 1;
|
||||||
if idx == tokens.len() {
|
if idx == tokens.len() {
|
||||||
working_set.error(ParseError::Expected("record", span));
|
working_set.error(ParseError::Expected(
|
||||||
return garbage(span);
|
"':'",
|
||||||
|
Span::new(curr_span.end, curr_span.end),
|
||||||
|
));
|
||||||
|
output.push(RecordItem::Pair(
|
||||||
|
garbage(curr_span),
|
||||||
|
garbage(Span::new(curr_span.end, curr_span.end)),
|
||||||
|
));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
let colon = working_set.get_span_contents(tokens[idx].span);
|
let colon_span = tokens[idx].span;
|
||||||
|
let colon = working_set.get_span_contents(colon_span);
|
||||||
idx += 1;
|
idx += 1;
|
||||||
if idx == tokens.len() || colon != b":" {
|
if colon != b":" {
|
||||||
//FIXME: need better error
|
working_set.error(ParseError::Expected(
|
||||||
working_set.error(ParseError::Expected("record", span));
|
"':'",
|
||||||
return garbage(span);
|
Span::new(colon_span.start, colon_span.start),
|
||||||
|
));
|
||||||
|
output.push(RecordItem::Pair(
|
||||||
|
field,
|
||||||
|
garbage(Span::new(
|
||||||
|
colon_span.start,
|
||||||
|
tokens[tokens.len() - 1].span.end,
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if idx == tokens.len() {
|
||||||
|
working_set.error(ParseError::Expected(
|
||||||
|
"value for record field",
|
||||||
|
Span::new(colon_span.end, colon_span.end),
|
||||||
|
));
|
||||||
|
output.push(RecordItem::Pair(
|
||||||
|
garbage(Span::new(curr_span.start, colon_span.end)),
|
||||||
|
garbage(Span::new(colon_span.end, tokens[tokens.len() - 1].span.end)),
|
||||||
|
));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
let value = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any);
|
let value = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any);
|
||||||
idx += 1;
|
idx += 1;
|
||||||
|
@ -763,3 +763,14 @@ fn properly_typecheck_rest_param() -> TestResult {
|
|||||||
fn implied_collect_has_compatible_type() -> TestResult {
|
fn implied_collect_has_compatible_type() -> TestResult {
|
||||||
run_test(r#"let idx = 3 | $in; $idx < 1"#, "false")
|
run_test(r#"let idx = 3 | $in; $idx < 1"#, "false")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn record_expected_colon() -> TestResult {
|
||||||
|
fail_test(r#"{ a: 2 b }"#, "expected ':'")?;
|
||||||
|
fail_test(r#"{ a: 2 b 3 }"#, "expected ':'")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn record_missing_value() -> TestResult {
|
||||||
|
fail_test(r#"{ a: 2 b: }"#, "expected value for record field")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user