From 0173a4e5deb5dbe71c91a68c02ef88e3de778068 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 28 Nov 2022 00:20:44 +0100 Subject: fix(frontend): content assist error recovery --- subprojects/frontend/src/language/problem.grammar | 10 +++---- .../frontend/src/xtext/ContentAssistService.ts | 32 ++++++++++++++++++---- 2 files changed, 31 insertions(+), 11 deletions(-) (limited to 'subprojects/frontend/src') diff --git a/subprojects/frontend/src/language/problem.grammar b/subprojects/frontend/src/language/problem.grammar index f4cf1712..704badab 100644 --- a/subprojects/frontend/src/language/problem.grammar +++ b/subprojects/frontend/src/language/problem.grammar @@ -16,6 +16,11 @@ @top Problem { statement* } statement { + Assertion { + kw<"default">? (NotOp | UnknownOp)? RelationName + ParameterList + (":" Expr)? "." + } | ProblemDeclaration { kw<"problem"> QualifiedName "." } | @@ -45,11 +50,6 @@ statement { // RuleName ParameterList? // RuleBody { ":" sep "==>" sep "." } //} | - Assertion { - kw<"default">? (NotOp | UnknownOp)? RelationName - ParameterList - (":" Expr)? "." - } | IndividualDeclaration { kw<"indiv"> sep<",", IndividualNodeName> "." } | diff --git a/subprojects/frontend/src/xtext/ContentAssistService.ts b/subprojects/frontend/src/xtext/ContentAssistService.ts index fa894e4d..78f61c06 100644 --- a/subprojects/frontend/src/xtext/ContentAssistService.ts +++ b/subprojects/frontend/src/xtext/ContentAssistService.ts @@ -33,16 +33,36 @@ interface IFoundToken { function findToken({ pos, state }: CompletionContext): IFoundToken | undefined { const token = syntaxTree(state).resolveInner(pos, -1); - if (token.firstChild !== null) { - // We only autocomplete terminal nodes. If the current node is nonterminal, - // returning `undefined` makes us autocomplete with the empty prefix instead. + const { from } = token; + if (from > pos) { + // We haven't found the token we want to complete. + // Complete with an empty prefix from `pos` instead. + // The other `return undefined;` lines also handle this condition. + return undefined; + } + // We look at the text at the beginning of the token. + // For QualifiedName tokens right before a comment, this may be a comment token. + const endIndex = token.firstChild?.from ?? token.to; + if (pos > endIndex) { + return undefined; + } + const text = state.sliceDoc(from, endIndex).trimEnd(); + // Due to parser error recovery, we may get spurious whitespace + // at the end of the token. + const to = from + text.length; + if (to > endIndex) { + return undefined; + } + if (from > pos || endIndex < pos) { + // We haven't found the token we want to complete. + // Complete with an empty prefix from `pos` instead. return undefined; } return { - from: token.from, - to: token.to, + from, + to, implicitCompletion: token.type.prop(implicitCompletion) || false, - text: state.sliceDoc(token.from, token.to), + text, }; } -- cgit v1.2.3-54-g00ecf