ok/jj
1
0
Fork 0
forked from mirrors/jj

revset: parse hg/git-like '^' postfix operator and show hint

This commit is contained in:
Yuya Nishihara 2022-12-22 20:18:25 +09:00
parent 7cd01b27a7
commit 36020a2bbf
3 changed files with 45 additions and 2 deletions

View file

@ -26,6 +26,7 @@ whitespace = _{ " " }
parents_op = { "-" }
children_op = { "+" }
compat_parents_op = { "^" }
dag_range_op = { ":" }
dag_range_pre_op = { ":" }
@ -61,7 +62,7 @@ primary = {
| symbol
}
neighbors_expression = _{ primary ~ (parents_op | children_op)* }
neighbors_expression = _{ primary ~ (parents_op | children_op | compat_parents_op)* }
range_expression = _{
neighbors_expression ~ range_ops ~ neighbors_expression

View file

@ -215,6 +215,12 @@ pub struct RevsetParseError {
pub enum RevsetParseErrorKind {
#[error("Syntax error")]
SyntaxError,
#[error("'{op}' is not a postfix operator (Did you mean '{similar_op}' for {description}?)")]
NotPostfixOperator {
op: String,
similar_op: String,
description: String,
},
#[error("'{op}' is not an infix operator (Did you mean '{similar_op}' for {description}?)")]
NotInfixOperator {
op: String,
@ -701,6 +707,21 @@ fn parse_expression_rule(
pairs: Pairs<Rule>,
state: ParseState,
) -> Result<Rc<RevsetExpression>, RevsetParseError> {
fn not_postfix_op(
op: &Pair<Rule>,
similar_op: impl Into<String>,
description: impl Into<String>,
) -> RevsetParseError {
RevsetParseError::with_span(
RevsetParseErrorKind::NotPostfixOperator {
op: op.as_str().to_owned(),
similar_op: similar_op.into(),
description: description.into(),
},
op.as_span(),
)
}
fn not_infix_op(
op: &Pair<Rule>,
similar_op: impl Into<String>,
@ -729,7 +750,9 @@ fn parse_expression_rule(
.op(Op::prefix(Rule::dag_range_pre_op) | Op::prefix(Rule::range_pre_op))
.op(Op::postfix(Rule::dag_range_post_op) | Op::postfix(Rule::range_post_op))
// Neighbors
.op(Op::postfix(Rule::parents_op) | Op::postfix(Rule::children_op))
.op(Op::postfix(Rule::parents_op)
| Op::postfix(Rule::children_op)
| Op::postfix(Rule::compat_parents_op))
});
PRATT
.map_primary(|primary| parse_primary_rule(primary, state))
@ -743,6 +766,7 @@ fn parse_expression_rule(
Rule::range_post_op => Ok(lhs?.range(&RevsetExpression::visible_heads())),
Rule::parents_op => Ok(lhs?.parents()),
Rule::children_op => Ok(lhs?.children()),
Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents")),
r => panic!("unexpected postfix operator rule {r:?}"),
})
.map_infix(|lhs, op, rhs| match op.as_rule() {
@ -2315,6 +2339,14 @@ mod tests {
#[test]
fn test_parse_revset_compat_operator() {
assert_eq!(
parse("foo^"),
Err(RevsetParseErrorKind::NotPostfixOperator {
op: "^".to_owned(),
similar_op: "-".to_owned(),
description: "parents".to_owned(),
})
);
assert_eq!(
parse("foo + bar"),
Err(RevsetParseErrorKind::NotInfixOperator {

View file

@ -41,6 +41,16 @@ fn test_syntax_error() {
|
= '-' is not an infix operator (Did you mean '~' for difference?)
"###);
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "HEAD^"]);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse revset: --> 1:5
|
1 | HEAD^
| ^
|
= '^' is not a postfix operator (Did you mean '-' for parents?)
"###);
}
#[test]