feat(inlineChat): refactor inline chat affordance and rendering modes (#289159)

* feat(inlineChat): refactor inline chat affordance and rendering modes

- Replaced InlineChatSelectionIndicator with InlineChatAffordance for improved affordance handling.
- Introduced InlineChatGutterAffordance and InlineChatEditorAffordance for gutter and editor affordances respectively.
- Added InlineChatOverlayWidget for rendering inline chat as a hover overlay.
- Updated configuration keys to support new affordance options and rendering modes.
- Removed deprecated ShowGutterMenu configuration in favor of more flexible affordance settings.
- Enhanced inline chat behavior to support both zone and hover rendering modes.

* thanks copilot
This commit is contained in:
Johannes Rieken
2026-01-21 08:57:05 +01:00
committed by GitHub
parent 4384ba8562
commit 90bae3ca47
9 changed files with 719 additions and 480 deletions

View File

@@ -51,7 +51,7 @@ import { INotebookEditorService } from '../../notebook/browser/services/notebook
import { CellUri, ICellEditOperation } from '../../notebook/common/notebookCommon.js';
import { INotebookService } from '../../notebook/common/notebookService.js';
import { CTX_INLINE_CHAT_VISIBLE, InlineChatConfigKeys } from '../common/inlineChat.js';
import { InlineChatSelectionIndicator } from './inlineChatSelectionGutterIndicator.js';
import { InlineChatAffordance } from './inlineChatAffordance.js';
import { IInlineChatSession2, IInlineChatSessionService } from './inlineChatSessionService.js';
import { EditorBasedInlineChatWidget } from './inlineChatWidget.js';
import { InlineChatZoneWidget } from './inlineChatZoneWidget.js';
@@ -109,9 +109,9 @@ export class InlineChatController implements IEditorContribution {
private readonly _store = new DisposableStore();
private readonly _isActiveController = observableValue(this, false);
private readonly _showGutterMenu: IObservable<boolean>;
private readonly _renderMode: IObservable<'zone' | 'hover'>;
private readonly _zone: Lazy<InlineChatZoneWidget>;
private readonly _gutterIndicator: InlineChatSelectionIndicator;
private readonly _gutterIndicator: InlineChatAffordance;
private readonly _currentSession: IObservable<IInlineChatSession2 | undefined>;
@@ -141,9 +141,9 @@ export class InlineChatController implements IEditorContribution {
const ctxInlineChatVisible = CTX_INLINE_CHAT_VISIBLE.bindTo(contextKeyService);
const notebookAgentConfig = observableConfigValue(InlineChatConfigKeys.notebookAgent, false, this._configurationService);
this._showGutterMenu = observableConfigValue(InlineChatConfigKeys.ShowGutterMenu, false, this._configurationService);
this._renderMode = observableConfigValue(InlineChatConfigKeys.RenderMode, 'zone', this._configurationService);
this._gutterIndicator = this._store.add(this._instaService.createInstance(InlineChatSelectionIndicator, this._editor));
this._gutterIndicator = this._store.add(this._instaService.createInstance(InlineChatAffordance, this._editor));
this._zone = new Lazy<InlineChatZoneWidget>(() => {
@@ -285,14 +285,14 @@ export class InlineChatController implements IEditorContribution {
// HIDE/SHOW
const session = visibleSessionObs.read(r);
const showGutterMenu = this._showGutterMenu.read(r);
const renderMode = this._renderMode.read(r);
if (!session) {
this._zone.rawValue?.hide();
this._zone.rawValue?.widget.chatWidget.setModel(undefined);
_editor.focus();
ctxInlineChatVisible.reset();
} else if (showGutterMenu) {
// showGutterMenu mode: set model but don't show zone, keep focus in editor
} else if (renderMode === 'hover') {
// hover mode: set model but don't show zone, keep focus in editor
this._zone.value.widget.chatWidget.setModel(session.chatModel);
this._zone.rawValue?.hide();
ctxInlineChatVisible.set(true);
@@ -438,16 +438,10 @@ export class InlineChatController implements IEditorContribution {
existingSession.dispose();
}
// use gutter menu to ask for input
if (!arg?.message && this._configurationService.getValue<boolean>(InlineChatConfigKeys.ShowGutterMenu)) {
const position = this._editor.getPosition();
const editorDomNode = this._editor.getDomNode();
const scrolledPosition = this._editor.getScrolledVisiblePosition(position);
const editorRect = editorDomNode.getBoundingClientRect();
const x = editorRect.left + scrolledPosition.left;
const y = editorRect.top + scrolledPosition.top;
// use hover overlay to ask for input
if (!arg?.message && this._configurationService.getValue<string>(InlineChatConfigKeys.RenderMode) === 'hover') {
// show menu and RETURN because the menu is re-entrant
await this._gutterIndicator.showMenuAt(x, y, scrolledPosition.height);
await this._gutterIndicator.showMenuAtSelection();
return true;
}