diff options
Diffstat (limited to 'subprojects/frontend')
-rw-r--r-- | subprojects/frontend/src/language/problem.grammar | 10 | ||||
-rw-r--r-- | subprojects/frontend/src/xtext/ContentAssistService.ts | 32 |
2 files changed, 31 insertions, 11 deletions
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 @@ | |||
16 | @top Problem { statement* } | 16 | @top Problem { statement* } |
17 | 17 | ||
18 | statement { | 18 | statement { |
19 | Assertion { | ||
20 | kw<"default">? (NotOp | UnknownOp)? RelationName | ||
21 | ParameterList<AssertionArgument> | ||
22 | (":" Expr)? "." | ||
23 | } | | ||
19 | ProblemDeclaration { | 24 | ProblemDeclaration { |
20 | kw<"problem"> QualifiedName "." | 25 | kw<"problem"> QualifiedName "." |
21 | } | | 26 | } | |
@@ -45,11 +50,6 @@ statement { | |||
45 | // RuleName ParameterList<Parameter>? | 50 | // RuleName ParameterList<Parameter>? |
46 | // RuleBody { ":" sep<OrOp, Conjunction> "==>" sep<OrOp, Consequent> "." } | 51 | // RuleBody { ":" sep<OrOp, Conjunction> "==>" sep<OrOp, Consequent> "." } |
47 | //} | | 52 | //} | |
48 | Assertion { | ||
49 | kw<"default">? (NotOp | UnknownOp)? RelationName | ||
50 | ParameterList<AssertionArgument> | ||
51 | (":" Expr)? "." | ||
52 | } | | ||
53 | IndividualDeclaration { | 53 | IndividualDeclaration { |
54 | kw<"indiv"> sep<",", IndividualNodeName> "." | 54 | kw<"indiv"> sep<",", IndividualNodeName> "." |
55 | } | | 55 | } | |
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 { | |||
33 | 33 | ||
34 | function findToken({ pos, state }: CompletionContext): IFoundToken | undefined { | 34 | function findToken({ pos, state }: CompletionContext): IFoundToken | undefined { |
35 | const token = syntaxTree(state).resolveInner(pos, -1); | 35 | const token = syntaxTree(state).resolveInner(pos, -1); |
36 | if (token.firstChild !== null) { | 36 | const { from } = token; |
37 | // We only autocomplete terminal nodes. If the current node is nonterminal, | 37 | if (from > pos) { |
38 | // returning `undefined` makes us autocomplete with the empty prefix instead. | 38 | // We haven't found the token we want to complete. |
39 | // Complete with an empty prefix from `pos` instead. | ||
40 | // The other `return undefined;` lines also handle this condition. | ||
41 | return undefined; | ||
42 | } | ||
43 | // We look at the text at the beginning of the token. | ||
44 | // For QualifiedName tokens right before a comment, this may be a comment token. | ||
45 | const endIndex = token.firstChild?.from ?? token.to; | ||
46 | if (pos > endIndex) { | ||
47 | return undefined; | ||
48 | } | ||
49 | const text = state.sliceDoc(from, endIndex).trimEnd(); | ||
50 | // Due to parser error recovery, we may get spurious whitespace | ||
51 | // at the end of the token. | ||
52 | const to = from + text.length; | ||
53 | if (to > endIndex) { | ||
54 | return undefined; | ||
55 | } | ||
56 | if (from > pos || endIndex < pos) { | ||
57 | // We haven't found the token we want to complete. | ||
58 | // Complete with an empty prefix from `pos` instead. | ||
39 | return undefined; | 59 | return undefined; |
40 | } | 60 | } |
41 | return { | 61 | return { |
42 | from: token.from, | 62 | from, |
43 | to: token.to, | 63 | to, |
44 | implicitCompletion: token.type.prop(implicitCompletion) || false, | 64 | implicitCompletion: token.type.prop(implicitCompletion) || false, |
45 | text: state.sliceDoc(token.from, token.to), | 65 | text, |
46 | }; | 66 | }; |
47 | } | 67 | } |
48 | 68 | ||