diff --git a/src/vs/workbench/contrib/chat/browser/chat.ts b/src/vs/workbench/contrib/chat/browser/chat.ts index 48844b393d8..c183bc78e1d 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.ts @@ -107,8 +107,17 @@ export interface IChatWidgetViewOptions { filter?: (item: ChatTreeItem) => boolean; rendererOptions?: IChatListItemRendererOptions; menus?: { + /** + * The menu that is inside the input editor, use for send, dictation + */ executeToolbar?: MenuId; + /** + * The menu that next to the input editor, use for close, config etc + */ inputSideToolbar?: MenuId; + /** + * The telemetry source for all commands of this widget + */ telemetrySource?: string; }; defaultElementHeight?: number; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts index b7c33b6df15..df40595b8c3 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts @@ -80,7 +80,7 @@ export class StartSessionAction extends EditorAction2 { let options: InlineChatRunOptions | undefined; const arg = _args[0]; - if (arg && InlineChatRunOptions.isInteractiveEditorOptions(arg)) { + if (arg && InlineChatRunOptions.isInlineChatRunOptions(arg)) { options = arg; } InlineChatController.get(editor)?.run({ ...options }); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 7b0c50ff990..7a61dbb9054 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -82,7 +82,7 @@ export abstract class InlineChatRunOptions { position?: IPosition; withIntentDetection?: boolean; - static isInteractiveEditorOptions(options: any): options is InlineChatRunOptions { + static isInlineChatRunOptions(options: any): options is InlineChatRunOptions { const { initialSelection, initialRange, message, autoSend, position, existingSession } = options; if ( typeof message !== 'undefined' && typeof message !== 'string' @@ -106,8 +106,6 @@ export class InlineChatController implements IEditorContribution { private _isDisposed: boolean = false; private readonly _store = new DisposableStore(); - // private readonly _input: Lazy; - // private readonly _zone: Lazy; private readonly _ui: Lazy<{ content: InlineChatContentWidget; zone: InlineChatZoneWidget }>; @@ -745,11 +743,9 @@ export class InlineChatController implements IEditorContribution { store.dispose(); - // todo@jrieken we can likely remove 'trackEdit' const diff = await this._editorWorkerService.computeDiff(this._session.textModel0.uri, this._session.textModelN.uri, { computeMoves: false, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, ignoreTrimWhitespace: false }, 'advanced'); this._session.wholeRange.fixup(diff?.changes ?? []); - - await this._session.hunkData.recompute(editState); + await this._session.hunkData.recompute(editState, diff); this._ui.value.zone.widget.updateToolbar(true); this._ui.value.zone.widget.updateProgress(false); @@ -898,13 +894,6 @@ export class InlineChatController implements IEditorContribution { } else if (initialRender) { const selection = this._editor.getSelection(); widgetPosition = selection.getStartPosition(); - // TODO@jrieken we are not ready for this - // widgetPosition = selection.getEndPosition(); - // if (Range.spansMultipleLines(selection) && widgetPosition.column === 1) { - // // selection ends on "nothing" -> move up to match the - // // rendered/visible part of the selection - // widgetPosition = this._editor.getModel().validatePosition(widgetPosition.delta(-1, Number.MAX_SAFE_INTEGER)); - // } this._ui.value.content.show(widgetPosition); } else { @@ -958,7 +947,6 @@ export class InlineChatController implements IEditorContribution { }; this._inlineChatSavingService.markChanged(this._session); - this._session.wholeRange.trackEdits(editOperations); if (opts) { await this._strategy.makeProgressiveChanges(editOperations, editsObserver, opts, undoStopBefore); } else { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index 78acedb3c27..1ac39ac4b40 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -33,6 +33,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { ChatModel, IChatRequestModel, IChatResponseModel, IChatTextEditGroupState } from 'vs/workbench/contrib/chat/common/chatModel'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IChatAgent } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IDocumentDiff } from 'vs/editor/common/diff/documentDiffProvider'; export type TelemetryData = { @@ -88,15 +89,6 @@ export class SessionWholeRange { } } - trackEdits(edits: ISingleEditOperation[]): void { - const newDeco: IModelDeltaDecoration[] = []; - for (const edit of edits) { - newDeco.push({ range: edit.range, options: SessionWholeRange._options }); - } - this._decorationIds.push(...this._textModel.deltaDecorations([], newDeco)); - this._onDidChange.fire(this); - } - fixup(changes: readonly DetailedLineRangeMapping[]): void { const newDeco: IModelDeltaDecoration[] = []; @@ -555,9 +547,9 @@ export class HunkData { this._textModel0.pushEditOperations(null, edits, () => null); } - async recompute(editState: IChatTextEditGroupState) { + async recompute(editState: IChatTextEditGroupState, diff?: IDocumentDiff | null) { - const diff = await this._editorWorkerService.computeDiff(this._textModel0.uri, this._textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, computeMoves: false }, 'advanced'); + diff ??= await this._editorWorkerService.computeDiff(this._textModel0.uri, this._textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, computeMoves: false }, 'advanced'); if (!diff || diff.changes.length === 0) { // return new HunkData([], session); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index f80db1f22e4..14e6e268fc9 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -47,7 +47,7 @@ import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IHoverService } from 'vs/platform/hover/browser/hover'; -import { IChatListItemRendererOptions } from 'vs/workbench/contrib/chat/browser/chat'; +import { IChatWidgetViewOptions } from 'vs/workbench/contrib/chat/browser/chat'; export interface InlineChatWidgetViewState { @@ -57,18 +57,7 @@ export interface InlineChatWidgetViewState { } export interface IInlineChatWidgetConstructionOptions { - /** - * The telemetry source for all commands of this widget - */ - telemetrySource: string; - /** - * The menu that is inside the input editor, use for send, dictation - */ - inputMenuId: MenuId; - /** - * The menu that next to the input editor, use for close, config etc - */ - widgetMenuId: MenuId; + /** * The menu that rendered as button bar, use for accept, discard etc */ @@ -78,9 +67,10 @@ export interface IInlineChatWidgetConstructionOptions { */ feedbackMenuId?: MenuId; - editorOverflowWidgetsDomNode?: HTMLElement; - - rendererOptions?: IChatListItemRendererOptions; + /** + * The options for the chat widget + */ + chatWidgetViewOptions?: IChatWidgetViewOptions; } export interface IInlineChatMessage { @@ -170,13 +160,7 @@ export class InlineChatWidget { renderInputOnTop: true, renderFollowups: true, supportsFileReferences: true, - editorOverflowWidgetsDomNode: options.editorOverflowWidgetsDomNode, - rendererOptions: options.rendererOptions, - menus: { - executeToolbar: options.inputMenuId, - inputSideToolbar: options.widgetMenuId, - telemetrySource: options.telemetrySource - }, + // editorOverflowWidgetsDomNode: options.editorOverflowWidgetsDomNode, filter: item => { if (isWelcomeVM(item)) { return false; @@ -186,6 +170,7 @@ export class InlineChatWidget { } return true; }, + ...options.chatWidgetViewOptions }, { listForeground: editorForeground, @@ -464,9 +449,6 @@ export class InlineChatWidget { return tail(requests)?.response?.response.asString(); } - get usesDefaultChatModel(): boolean { - return this.getChatModel() === this._defaultChatModel; - } getChatModel(): IChatModel { return this._chatWidget.viewModel?.model ?? this._defaultChatModel; @@ -608,7 +590,7 @@ export class EditorBasedInlineChatWidget extends InlineChatWidget { @IChatService chatService: IChatService, @IHoverService hoverService: IHoverService, ) { - super(location, { ...options, editorOverflowWidgetsDomNode: _parentEditor.getOverflowWidgetsDomNode() }, instantiationService, contextKeyService, keybindingService, accessibilityService, configurationService, accessibleViewService, textModelResolverService, chatService, hoverService); + super(location, { ...options, chatWidgetViewOptions: { editorOverflowWidgetsDomNode: _parentEditor.getOverflowWidgetsDomNode() } }, instantiationService, contextKeyService, keybindingService, accessibilityService, configurationService, accessibleViewService, textModelResolverService, chatService, hoverService); } // --- layout diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts index 88c16b8070d..c7d2e164177 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts @@ -16,7 +16,6 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, EditMode, InlineChatConfigKeys, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { EditorBasedInlineChatWidget } from './inlineChatWidget'; -import { MenuId } from 'vs/platform/actions/common/actions'; import { isEqual } from 'vs/base/common/resources'; import { StableEditorBottomScrollState } from 'vs/editor/browser/stableEditorScroll'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -47,9 +46,6 @@ export class InlineChatZoneWidget extends ZoneWidget { })); this.widget = this._instaService.createInstance(EditorBasedInlineChatWidget, location, this.editor, { - telemetrySource: 'interactiveEditorWidget-toolbar', - inputMenuId: MenuId.ChatExecute, - widgetMenuId: MENU_INLINE_CHAT_WIDGET, statusMenuId: { menu: MENU_INLINE_CHAT_WIDGET_STATUS, options: { @@ -64,13 +60,19 @@ export class InlineChatZoneWidget extends ZoneWidget { } } }, - rendererOptions: { - renderTextEditsAsSummary: (uri) => { - // render edits as summary only when using Live mode and when - // dealing with the current file in the editor - return isEqual(uri, editor.getModel()?.uri) - && configurationService.getValue(InlineChatConfigKeys.Mode) === EditMode.Live; + chatWidgetViewOptions: { + menus: { + inputSideToolbar: MENU_INLINE_CHAT_WIDGET, + telemetrySource: 'interactiveEditorWidget-toolbar', }, + rendererOptions: { + renderTextEditsAsSummary: (uri) => { + // render edits as summary only when using Live mode and when + // dealing with the current file in the editor + return isEqual(uri, editor.getModel()?.uri) + && configurationService.getValue(InlineChatConfigKeys.Mode) === EditMode.Live; + }, + } } }); this._disposables.add(this.widget.onDidChangeHeight(() => { diff --git a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts index 4662ab11501..a8441f86c2d 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts @@ -26,7 +26,6 @@ import { ICursorStateComputer, ITextModel } from 'vs/editor/common/model'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { IModelService } from 'vs/editor/common/services/model'; import { localize } from 'vs/nls'; -import { MenuId } from 'vs/platform/actions/common/actions'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -415,14 +414,17 @@ export class NotebookChatController extends Disposable implements INotebookEdito InlineChatWidget, ChatAgentLocation.Notebook, { - telemetrySource: 'notebook-generate-cell', - inputMenuId: MenuId.ChatExecute, - widgetMenuId: MENU_INLINE_CHAT_WIDGET, statusMenuId: MENU_CELL_CHAT_WIDGET_STATUS, - rendererOptions: { - renderTextEditsAsSummary: (uri) => { - return isEqual(uri, this._widget?.parentEditor.getModel()?.uri) - || isEqual(uri, this._notebookEditor.textModel?.uri); + chatWidgetViewOptions: { + rendererOptions: { + renderTextEditsAsSummary: (uri) => { + return isEqual(uri, this._widget?.parentEditor.getModel()?.uri) + || isEqual(uri, this._notebookEditor.textModel?.uri); + } + }, + menus: { + telemetrySource: 'notebook-generate-cell', + inputSideToolbar: MENU_INLINE_CHAT_WIDGET, } } } diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts index b27463b8232..bfeed279ee2 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts @@ -58,8 +58,6 @@ export class TerminalChatWidget extends Disposable { InlineChatWidget, ChatAgentLocation.Terminal, { - inputMenuId: MENU_TERMINAL_CHAT_INPUT, - widgetMenuId: MENU_TERMINAL_CHAT_WIDGET, statusMenuId: { menu: MENU_TERMINAL_CHAT_WIDGET_STATUS, options: { @@ -72,8 +70,14 @@ export class TerminalChatWidget extends Disposable { } } }, - telemetrySource: 'terminal-inline-chat', - rendererOptions: { editableCodeBlock: true } + chatWidgetViewOptions: { + rendererOptions: { editableCodeBlock: true }, + menus: { + telemetrySource: 'terminal-inline-chat', + executeToolbar: MENU_TERMINAL_CHAT_INPUT, + inputSideToolbar: MENU_TERMINAL_CHAT_WIDGET, + } + } } ); this._register(Event.any(