feat: AI ghost text + STruC++ LSP autocomplete coexistence - #892
Conversation
The ST editor previously made AI inline completions and the LSP suggest widget mutually exclusive: when AI was on, the LSP auto-dropdown was suppressed (`quickSuggestions: false`, `inlineSuggest.suppressSuggestions: true`). The LSP completions are faster and deterministic (especially for variables and struct members), so hiding them behind the slower AI stream hurt the editing flow. Both completion sources are independent Monaco providers, so they can run at once. Now: - The LSP dropdown auto-opens in both modes (Enter / arrow-keys accept it). - The AI ghost text renders alongside it; Tab commits it — even while the suggest widget is open (Monaco's default reserves Tab for the dropdown). - While the dropdown is open with no ghost text, Tab is swallowed (reserved for AI) so it never accepts an LSP item. - When AI is off, Tab falls back to accepting the LSP dropdown as before. The Tab overrides are gated on a custom context key driven by `inlineCompletionsActive`, so toggling AI on/off takes effect without remounting the editor. Byte-identical companion change to openplc-web (shared editor surface). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
WalkthroughAdds a new ChangesAI/LSP coexistence keybinding integration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/frontend/components/_features/[workspace]/editor/monaco/index.tsx (1)
1238-1243: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winGate coexistence on the inline provider actually existing.
inlineCompletionsActivecan be true even whenaiPort?.registerInlineCompletionsis missing, but the provider effect returns early at Line 793. In that state the Tab overrides still activate and the no-ghost path swallows LSP Tab even though AI ghost text can never appear.Proposed fix
const inlineCompletionsActive = capabilities.hasAIAssistant && + Boolean(aiPort?.registerInlineCompletions) && aiState.isEnabled && aiState.hasConsented && aiState.preferences.inlineCompletionsEnabled🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/frontend/components/_features/`[workspace]/editor/monaco/index.tsx around lines 1238 - 1243, The inline-completions coexistence flag is too broad: `inlineCompletionsActive` can be true even when `aiPort?.registerInlineCompletions` is unavailable, which leaves the Tab override logic enabled without any AI ghost text provider. Update the `inlineCompletionsActive` condition in the Monaco editor component to also require the inline provider to exist, and keep the provider effect and Tab-handling branches aligned so `registerInlineCompletions`-gated behavior only activates when the AI inline provider can actually be registered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/frontend/components/_features/`[workspace]/editor/monaco/index.tsx:
- Around line 1238-1243: The inline-completions coexistence flag is too broad:
`inlineCompletionsActive` can be true even when
`aiPort?.registerInlineCompletions` is unavailable, which leaves the Tab
override logic enabled without any AI ghost text provider. Update the
`inlineCompletionsActive` condition in the Monaco editor component to also
require the inline provider to exist, and keep the provider effect and
Tab-handling branches aligned so `registerInlineCompletions`-gated behavior only
activates when the AI inline provider can actually be registered.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: fa568e4c-290d-4cfc-8a8c-dafe70ee9764
📒 Files selected for processing (2)
src/frontend/components/_features/[workspace]/editor/monaco/ai-lsp-coexistence.tssrc/frontend/components/_features/[workspace]/editor/monaco/index.tsx
Summary
The Structured Text editor previously treated AI inline completions and the STruC++ LSP suggest widget as mutually exclusive — when AI was enabled, the LSP auto-dropdown was suppressed (
quickSuggestions: false,inlineSuggest.suppressSuggestions: true). Since the LSP completions are faster and deterministic (especially for variables and struct-member access likemy_struct.value_a.point_b), hiding them behind the slower AI stream hurt the editing flow.Both completion sources are independent Monaco providers, so they can run at the same time. This PR makes them coexist, splitting acceptance by key.
Behavior
The Tab overrides are gated on a custom Monaco context key (
openplcAiLspCoexistence) driven byinlineCompletionsActive, so toggling AI on/off takes effect without remounting the editor. This mirrors the VS Code + Copilot model.Changes
monaco/ai-lsp-coexistence.ts(new): installs the two Tab keybinding overrides viaeditor.addCommand, gated on the context key.monaco/index.tsx: stop forcingquickSuggestions: false; setinlineSuggest.suppressSuggestions: false; wire the helper in the mount handler + auseEffectthat keeps the context key in sync with AI state.Note
This is the byte-identical companion to openplc-web PR autonomy-logic/openplc-web#544 — both repos share this editor surface and must stay in sync. Validated manually in the web app (LSP dropdown + AI ghost text coexisting, Tab→AI, Enter→LSP, AI-off fallback) and typechecks clean here.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes