Decouple Copilot CodeBlock from editor integration#3096
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a mechanism to customize markdown elements within the Copilot component by adding a registerMarkdownElements API and a markdownElements registry. The base CodeBlock component has been refactored to be more generic, removing editor-specific logic and introducing an actions slot, while a new editor-specific CodeBlock implementation is registered during initialization. Feedback suggests improving the encapsulation of the markdownElements property in the Copilot class by making it private and providing a read-only getter.
There was a problem hiding this comment.
Clean architectural split — the slot-based composition is a good fit here and the disposal pattern is consistent with the rest of the codebase. A few things worth addressing:
Notable issues
-
markdownElementsshould be private (or at least have a getter). All other registries onCopilot(customElementMap,toolMap,stateIndicatorComponentMap, etc.) are private and mediated through register/dispose methods. Leaving this field public exposes direct mutation that bypasses the disposal lifecycle, andMarkdownView.vuereading it directly creates an internal-representation coupling. -
registerMarkdownElementssilently overwrites existing keys (viaObject.assign) while every other register method emits aconsole.warnon duplicate names (seeregisterStateIndicatorComponent). In a context where LLM-rendered code blocks can trigger editor actions, silently replacing the renderer component is a meaningful trust-boundary concern worth adding a warning for. -
useSlotText()is called independently in both the editorCodeBlockwrapper and the baseCodeBlock. Vue walks the slot VNode subtree in each computed independently, so the slot content is traversed twice per render. Sincecode.valuein the editor wrapper is used only forhandleInsert, passingcodeas a prop (or emitting it from the base component) would eliminate the redundancy.
Minor
-
registerMarkdownElementshas no JSDoc comment, unlike every otherregister*method on the class. -
The disposal closure uses
Object.entries(elements).forEach(...)with an inlineas keyof MarkdownElementDefinitionscast. Ifelementshasundefinedvalues (e.g.{ codeBlock: undefined }),Object.entrieswill include them and trigger adeletethat removes a subsequently-registered component. A simple guard (if (component == null) return) would close this edge case.
Positive change
The i18n string fix in CodeBlock.vue ('Failed to copy link to clipboard' → 'Failed to copy code to clipboard') is a correct and welcome correction.
There was a problem hiding this comment.
Pull request overview
This PR decouples Copilot’s default markdown code block rendering from the SPX editor integration by making the shared CodeBlock renderer display/copy-only, while allowing integrations (like the SPX editor) to override built-in markdown element renderers (e.g., to re-add “Insert”).
Changes:
- Added a
Copilot.registerMarkdownElements(...)API and reactivemarkdownElementsregistry for overriding built-in markdown renderers. - Updated Copilot Markdown rendering to use an override code block component when provided.
- Moved the editor-specific “Insert code” action into a new SPX editor integration
CodeBlock.vueand registered it from the editor Copilot setup.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| spx-gui/src/components/editor/copilot/index.ts | Registers the editor-specific markdown code block renderer override. |
| spx-gui/src/components/editor/copilot/CodeBlock.vue | New editor-specific CodeBlock wrapper that adds “Insert” behavior on top of the shared renderer. |
| spx-gui/src/components/copilot/custom-elements/CodeBlock.vue | Makes shared CodeBlock editor-agnostic; supports optional actions slot; fixes copy messaging. |
| spx-gui/src/components/copilot/copilot.ts | Introduces markdown element override registry + registerMarkdownElements disposer. |
| spx-gui/src/components/copilot/MarkdownView.vue | Uses copilot.markdownElements.codeBlock override when present. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This PR decouples the default Copilot code block renderer from editor-specific insertion behavior.
Closes #3043
Summary
Issue coverage
CodeChange is already outside the shared Copilot module and is registered from the editor Copilot integration. This PR finishes the remaining CodeBlock part by removing editor/code-editor dependencies from the shared default CodeBlock implementation.
Checks