Improve partial completion/highlight (#3564)

This commit is contained in:
JT 2021-06-07 16:33:44 +12:00 committed by GitHub
parent 82d69305b6
commit 128f5bce30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 23 deletions

View File

@ -28,6 +28,9 @@ pub enum ParseErrorReason {
actual: Spanned<String>,
},
/// Unclosed delimiter
Unclosed { delimiter: String, span: Span },
/// An unexpected internal error has occurred
InternalError { message: Spanned<String> },
@ -98,6 +101,13 @@ impl ParseError {
},
}
}
/// Unclosed delimiter
pub fn unclosed(delimiter: String, span: Span) -> ParseError {
ParseError {
reason: ParseErrorReason::Unclosed { delimiter, span },
}
}
}
/// Convert a [ParseError](ParseError) into a [ShellError](ShellError)
@ -117,6 +127,11 @@ impl From<ParseError> for ShellError {
ParseErrorReason::ArgumentError { command, error } => {
ShellError::argument_error(command, error)
}
ParseErrorReason::Unclosed { delimiter, span } => ShellError::labeled_error(
"Unclosed delimiter",
format!("expected '{}'", delimiter),
span,
),
}
}
}

View File

@ -54,7 +54,7 @@ pub fn parse_simple_column_path(
if c == delimiter {
inside_delimiter = false;
}
} else if c == '\'' || c == '"' || c == '`' {
} else if c == '\'' || c == '"' {
inside_delimiter = true;
delimiter = c;
} else if c == '.' {
@ -474,6 +474,8 @@ fn parse_invocation(
lite_arg: &Spanned<String>,
scope: &dyn ParserScope,
) -> (SpannedExpression, Option<ParseError>) {
let mut error = None;
// We have a command invocation
let string: String = lite_arg
.item
@ -484,21 +486,24 @@ fn parse_invocation(
// We haven't done much with the inner string, so let's go ahead and work with it
let (tokens, err) = lex(&string, lite_arg.span.start() + 1);
if err.is_some() {
return (garbage(lite_arg.span), err);
if error.is_none() {
error = err;
};
let (lite_block, err) = parse_block(tokens);
if err.is_some() {
return (garbage(lite_arg.span), err);
if error.is_none() {
error = err;
};
scope.enter_scope();
let (classified_block, err) = classify_block(&lite_block, scope);
if error.is_none() {
error = err;
};
scope.exit_scope();
(
SpannedExpression::new(Expression::Invocation(classified_block), lite_arg.span),
err,
error,
)
}
@ -625,7 +630,7 @@ fn format(input: &str, start: usize) -> (Vec<FormatCommand>, Option<ParseError>)
if !found_end {
error = Some(ParseError::argument_error(
input.spanned(Span::new(original_start, end)),
ArgumentError::MissingValueForName("unclosed { }".to_string()),
ArgumentError::MissingValueForName("unclosed ()".to_string()),
));
}
@ -1048,17 +1053,28 @@ fn parse_arg(
SyntaxShape::Block | SyntaxShape::RowCondition => {
// Blocks have one of two forms: the literal block and the implied block
// To parse a literal block, we need to detect that what we have is itself a block
let mut chars = lite_arg.item.chars();
let mut chars: Vec<_> = lite_arg.item.chars().collect();
match (chars.next(), chars.next_back()) {
(Some('{'), Some('}')) => {
match chars.first() {
Some('{') => {
let mut error = None;
if let Some('}') = chars.last() {
chars = chars[1..(chars.len() - 1)].to_vec();
} else {
chars = chars[1..].to_vec();
error = Some(ParseError::unclosed(
"}".into(),
Span::new(lite_arg.span.end(), lite_arg.span.end()),
));
}
// We have a literal block
let string: String = chars.collect();
let string: String = chars.into_iter().collect();
// We haven't done much with the inner string, so let's go ahead and work with it
let (mut tokens, err) = lex(&string, lite_arg.span.start() + 1);
if err.is_some() {
return (garbage(lite_arg.span), err);
if error.is_none() {
error = err;
}
// Check to see if we have parameters
@ -1118,12 +1134,15 @@ fn parse_arg(
};
let (lite_block, err) = parse_block(tokens);
if err.is_some() {
return (garbage(lite_arg.span), err);
if error.is_none() {
error = err;
}
scope.enter_scope();
let (mut classified_block, err) = classify_block(&lite_block, scope);
if error.is_none() {
error = err;
}
scope.exit_scope();
if let Some(classified_block) = Arc::get_mut(&mut classified_block) {
@ -1141,7 +1160,7 @@ fn parse_arg(
(
SpannedExpression::new(Expression::Block(classified_block), lite_arg.span),
err,
error,
)
}
_ => {
@ -2104,16 +2123,22 @@ pub fn parse(
span_offset: usize,
scope: &dyn ParserScope,
) -> (Arc<Block>, Option<ParseError>) {
let (output, error) = lex(input, span_offset);
if error.is_some() {
return (Arc::new(Block::basic()), error);
let mut error = None;
let (output, err) = lex(input, span_offset);
if error.is_none() {
error = err;
}
let (lite_block, error) = parse_block(output);
if error.is_some() {
return (Arc::new(Block::basic()), error);
let (lite_block, err) = parse_block(output);
if error.is_none() {
error = err;
}
classify_block(&lite_block, scope)
let (block, err) = classify_block(&lite_block, scope);
if error.is_none() {
error = err;
}
(block, error)
}
#[test]