forked from extern/nushell
Improve partial completion/highlight (#3564)
This commit is contained in:
parent
82d69305b6
commit
128f5bce30
@ -28,6 +28,9 @@ pub enum ParseErrorReason {
|
|||||||
actual: Spanned<String>,
|
actual: Spanned<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Unclosed delimiter
|
||||||
|
Unclosed { delimiter: String, span: Span },
|
||||||
|
|
||||||
/// An unexpected internal error has occurred
|
/// An unexpected internal error has occurred
|
||||||
InternalError { message: Spanned<String> },
|
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)
|
/// Convert a [ParseError](ParseError) into a [ShellError](ShellError)
|
||||||
@ -117,6 +127,11 @@ impl From<ParseError> for ShellError {
|
|||||||
ParseErrorReason::ArgumentError { command, error } => {
|
ParseErrorReason::ArgumentError { command, error } => {
|
||||||
ShellError::argument_error(command, error)
|
ShellError::argument_error(command, error)
|
||||||
}
|
}
|
||||||
|
ParseErrorReason::Unclosed { delimiter, span } => ShellError::labeled_error(
|
||||||
|
"Unclosed delimiter",
|
||||||
|
format!("expected '{}'", delimiter),
|
||||||
|
span,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ pub fn parse_simple_column_path(
|
|||||||
if c == delimiter {
|
if c == delimiter {
|
||||||
inside_delimiter = false;
|
inside_delimiter = false;
|
||||||
}
|
}
|
||||||
} else if c == '\'' || c == '"' || c == '`' {
|
} else if c == '\'' || c == '"' {
|
||||||
inside_delimiter = true;
|
inside_delimiter = true;
|
||||||
delimiter = c;
|
delimiter = c;
|
||||||
} else if c == '.' {
|
} else if c == '.' {
|
||||||
@ -474,6 +474,8 @@ fn parse_invocation(
|
|||||||
lite_arg: &Spanned<String>,
|
lite_arg: &Spanned<String>,
|
||||||
scope: &dyn ParserScope,
|
scope: &dyn ParserScope,
|
||||||
) -> (SpannedExpression, Option<ParseError>) {
|
) -> (SpannedExpression, Option<ParseError>) {
|
||||||
|
let mut error = None;
|
||||||
|
|
||||||
// We have a command invocation
|
// We have a command invocation
|
||||||
let string: String = lite_arg
|
let string: String = lite_arg
|
||||||
.item
|
.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
|
// 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);
|
let (tokens, err) = lex(&string, lite_arg.span.start() + 1);
|
||||||
if err.is_some() {
|
if error.is_none() {
|
||||||
return (garbage(lite_arg.span), err);
|
error = err;
|
||||||
};
|
};
|
||||||
let (lite_block, err) = parse_block(tokens);
|
let (lite_block, err) = parse_block(tokens);
|
||||||
if err.is_some() {
|
if error.is_none() {
|
||||||
return (garbage(lite_arg.span), err);
|
error = err;
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.enter_scope();
|
scope.enter_scope();
|
||||||
let (classified_block, err) = classify_block(&lite_block, scope);
|
let (classified_block, err) = classify_block(&lite_block, scope);
|
||||||
|
if error.is_none() {
|
||||||
|
error = err;
|
||||||
|
};
|
||||||
scope.exit_scope();
|
scope.exit_scope();
|
||||||
|
|
||||||
(
|
(
|
||||||
SpannedExpression::new(Expression::Invocation(classified_block), lite_arg.span),
|
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 {
|
if !found_end {
|
||||||
error = Some(ParseError::argument_error(
|
error = Some(ParseError::argument_error(
|
||||||
input.spanned(Span::new(original_start, end)),
|
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 => {
|
SyntaxShape::Block | SyntaxShape::RowCondition => {
|
||||||
// Blocks have one of two forms: the literal block and the implied block
|
// 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
|
// 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()) {
|
match chars.first() {
|
||||||
(Some('{'), Some('}')) => {
|
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
|
// 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
|
// 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);
|
let (mut tokens, err) = lex(&string, lite_arg.span.start() + 1);
|
||||||
if err.is_some() {
|
if error.is_none() {
|
||||||
return (garbage(lite_arg.span), err);
|
error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if we have parameters
|
// Check to see if we have parameters
|
||||||
@ -1118,12 +1134,15 @@ fn parse_arg(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (lite_block, err) = parse_block(tokens);
|
let (lite_block, err) = parse_block(tokens);
|
||||||
if err.is_some() {
|
if error.is_none() {
|
||||||
return (garbage(lite_arg.span), err);
|
error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.enter_scope();
|
scope.enter_scope();
|
||||||
let (mut classified_block, err) = classify_block(&lite_block, scope);
|
let (mut classified_block, err) = classify_block(&lite_block, scope);
|
||||||
|
if error.is_none() {
|
||||||
|
error = err;
|
||||||
|
}
|
||||||
scope.exit_scope();
|
scope.exit_scope();
|
||||||
|
|
||||||
if let Some(classified_block) = Arc::get_mut(&mut classified_block) {
|
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),
|
SpannedExpression::new(Expression::Block(classified_block), lite_arg.span),
|
||||||
err,
|
error,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -2104,16 +2123,22 @@ pub fn parse(
|
|||||||
span_offset: usize,
|
span_offset: usize,
|
||||||
scope: &dyn ParserScope,
|
scope: &dyn ParserScope,
|
||||||
) -> (Arc<Block>, Option<ParseError>) {
|
) -> (Arc<Block>, Option<ParseError>) {
|
||||||
let (output, error) = lex(input, span_offset);
|
let mut error = None;
|
||||||
if error.is_some() {
|
let (output, err) = lex(input, span_offset);
|
||||||
return (Arc::new(Block::basic()), error);
|
if error.is_none() {
|
||||||
|
error = err;
|
||||||
}
|
}
|
||||||
let (lite_block, error) = parse_block(output);
|
let (lite_block, err) = parse_block(output);
|
||||||
if error.is_some() {
|
if error.is_none() {
|
||||||
return (Arc::new(Block::basic()), error);
|
error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
classify_block(&lite_block, scope)
|
let (block, err) = classify_block(&lite_block, scope);
|
||||||
|
if error.is_none() {
|
||||||
|
error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
(block, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user