Skip to content

feat: grammar-based value completion behind the experimental flag (#467 #343)#477

Open
SJrX wants to merge 2 commits into
issue-345-7from
issue-345-8
Open

feat: grammar-based value completion behind the experimental flag (#467 #343)#477
SJrX wants to merge 2 commits into
issue-345-7from
issue-345-8

Conversation

@SJrX

@SJrX SJrX commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What

The payoff of the frontier work: grammar-based autocomplete. With the experimental flag on, the value completion for any GrammarOptionValue suggests the literal/choice tokens the grammar could accept at the caret — e.g. typing RestrictAddressFamilies=AF_IN⎉ offers AF_INET / AF_INET6.

Stacked on #475 (issue-345-7). Implements #343 on top of the engine.

How

  • Combinator.nextTokenChoices(prefix) (pure, no IntelliJ): the FIRST set at the end of prefix — the enumerable choices (LiteralChoiceTerminal / FlexibleLiteralChoiceTerminal) from the Stuck values at that offset. "What was expected here" (errors) and "what could come next" (completion) are the same question.
  • UnitFileValueCompletionContributor (kept on the simple extend() path): when the flag is on and the option is grammar-backed, read the value text before the caret and scan split points (largest first) for the tightest word where the grammar expects an enumerable token matching what's typed; then resultSet.withPrefixMatcher(word) + add the choices.

Why the custom prefix matcher

The platform's default prefix is the leaf text up to the caret. For a partial token like ~AF_IN that prefix is ~AF_IN, and no family name starts with it, so everything gets filtered out. Computing the grammar-correct word (here AF_IN) and setting it via withPrefixMatcher fixes this without grammar-specific word-splitting heuristics. This was the subtlety flagged before starting.

Tests

  • NextTokenChoicesTest (pure): empty value offers none/~/families; after ~ offers families but not none/~; after AF_INET offers another family (context-aware).
  • GrammarValueCompletionTest (fixture, flag on): AF_IN⎉AF_INET/AF_INET6; and a subsequent family in a list AF_UNIX AF_IN⎉ → same.

Full suite green; cancellation is polled (ProgressManager.checkCanceled) between split attempts.

Scope / limits

  • Completion fires on COMPLETED_VALUE leaves (existing contributor limitation); values mid-line-continuation aren't covered. Fine for the common case.
  • Only enumerable terminals suggest (literals/choices). Numbers/regex/IP terminals contribute nothing concrete (correctly) — those would need bespoke suggestion logic later.

Refs #467 #343

🤖 Generated with Claude Code

#343)

Cashes in the frontier/expected-set: at the caret, suggest the literal/choice tokens
the grammar could accept next.

- Combinator.nextTokenChoices(prefix): pure FIRST-set computation — the enumerable
  choices (LiteralChoiceTerminal / FlexibleLiteralChoiceTerminal) expected at the end
  of `prefix`, read from the Stuck values at that offset. No IntelliJ types; bounded by
  maxSteps.
- UnitFileValueCompletionContributor: when useGrammarParseEngine is on and the option is
  a GrammarOptionValue, compute completions from the value text before the caret. It
  scans split points (largest first) for the tightest word where the grammar expects an
  enumerable token matching what's typed, then uses resultSet.withPrefixMatcher(word) so
  the platform filters correctly — otherwise a partial token like "~AF_IN" would be the
  prefix and match nothing. Falls back to the original getAutoCompleteOptions path
  otherwise. Polls ProgressManager.checkCanceled between split attempts.

Tests: NextTokenChoicesTest (FIRST set incl. context — after "~" offers families not
"none"; after "AF_INET " offers another family); GrammarValueCompletionTest drives real
completion with the flag on (partial family, and a subsequent family in a list). Full
suite green.

Refs #467 #343

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Test Results

1 130 tests  +5   1 130 ✅ +5   50s ⏱️ +3s
  300 suites +2       0 💤 ±0 
  300 files   +2       0 ❌ ±0 

Results for commit dc47a98. ± Comparison against base commit b41dfdd.

The first cut used "largest split wins", so for a lenient terminal a partial token
like RootImagePolicy=h was treated as a finished partition identifier and completion
offered "=" instead of "home" (and AF_IN-style cases only worked by luck).

Rework addGrammarCompletions to prefer completing a genuine partial: the longest
non-empty trailing word for which the grammar expects an enumerable choice that
STRICTLY extends it (something left to type). Only if there's no such partial do we
fall back to advancing at a fresh boundary (empty value, or after a complete token
like "~" or "root=") with an empty prefix.

This keeps the previously-working cases (empty value, after "partition=", "AF_IN")
and fixes partial-identifier completion. Adds ImagePolicyCompletionTest covering the
empty boundary, partial-identifier completion ("r" -> root/root-verity/...), and the
post-"root=" policy-flag position.

Refs #467 #343

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SJrX added a commit that referenced this pull request Jun 26, 2026
* feat: grammar-based value completion behind the experimental flag

The frontier built for error localization answers exactly the question
completion needs — "what was expected at this offset?" is "what could come next
here?". Adds Combinator.nextTokenChoices(prefix), which reads the Stuck values at
the end of the typed prefix and collects the enumerable choices expected there
(literal / flexible-literal terminals; numbers/regexes/whitespace contribute
nothing to suggest).

Wires it into UnitFileValueCompletionContributor, gated behind
ExperimentalSettings.useGrammarParseEngine AND validator is GrammarOptionValue:
with the flag off the existing completion path is untouched. Two behaviours:
  - completing a partial token (sets the prefix matcher so "AF_IN" -> AF_INET/6)
  - chaining through forced separators on accept (e.g. accepting "home" inserts
    "home=" and re-opens completion, never auto-inserting a content token)

Bundles the stacked PRs #477 (completion) and #478 (forced-separator chaining),
re-cut against current 242.x. New behaviour, so flag-gated; correctness of
existing validators is unchanged. Tests enable the flag and reset it in tearDown
to avoid leaking into the shared light-test project.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover the flag-off gating and non-enumerable completion cases

The completion bundle tested the flag-on behaviours but not two things worth
guaranteeing: that grammar completion stays suppressed when the experimental
engine is off (the gating contract), and that a non-enumerable next token
(number/regex) offers nothing rather than crashing or suggesting junk.

- GrammarValueCompletionTest.testFlagOffOffersNoGrammarCompletions: flag off, the
  AF_IN partial yields no AF_* names (the flag-on path's suggestions are absent).
- NextTokenChoicesTest.testNonEnumerableNextTokenOffersNothing: an IntegerTerminal
  port grammar returns an empty choice set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Steve Ramage <gitcommits@sjrx.net>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant