mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-14 16:04:09 +01:00
sessions polish
This commit is contained in:
@@ -307,7 +307,6 @@ class AccountWidgetContribution extends Disposable implements IWorkbenchContribu
|
||||
when: ContextKeyExpr.or(
|
||||
CONTEXT_UPDATE_STATE.isEqualTo(StateType.Ready),
|
||||
CONTEXT_UPDATE_STATE.isEqualTo(StateType.AvailableForDownload),
|
||||
CONTEXT_UPDATE_STATE.isEqualTo(StateType.CheckingForUpdates),
|
||||
CONTEXT_UPDATE_STATE.isEqualTo(StateType.Downloading),
|
||||
CONTEXT_UPDATE_STATE.isEqualTo(StateType.Downloaded),
|
||||
CONTEXT_UPDATE_STATE.isEqualTo(StateType.Updating),
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './agentFeedbackEditorInputContribution.js';
|
||||
import './agentFeedbackGlyphMarginContribution.js';
|
||||
import './agentFeedbackLineDecorationContribution.js';
|
||||
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
|
||||
import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../../workbench/common/contributions.js';
|
||||
import { AgentFeedbackService, IAgentFeedbackService } from './agentFeedbackService.js';
|
||||
import { AgentFeedbackAttachmentContribution } from './agentFeedbackAttachment.js';
|
||||
import { AgentFeedbackAttachmentWidget } from './agentFeedbackAttachmentWidget.js';
|
||||
import { AgentFeedbackEditorOverlay } from './agentFeedbackEditorOverlay.js';
|
||||
import { registerAgentFeedbackEditorActions } from './agentFeedbackEditorActions.js';
|
||||
import { IChatAttachmentWidgetRegistry } from '../../../../workbench/contrib/chat/browser/attachments/chatAttachmentWidgetRegistry.js';
|
||||
import { IAgentFeedbackVariableEntry } from '../../../../workbench/contrib/chat/common/attachments/chatVariableEntries.js';
|
||||
|
||||
registerWorkbenchContribution2(AgentFeedbackEditorOverlay.ID, AgentFeedbackEditorOverlay, WorkbenchPhase.AfterRestored);
|
||||
registerWorkbenchContribution2(AgentFeedbackAttachmentContribution.ID, AgentFeedbackAttachmentContribution, WorkbenchPhase.AfterRestored);
|
||||
@@ -18,3 +21,14 @@ registerWorkbenchContribution2(AgentFeedbackAttachmentContribution.ID, AgentFeed
|
||||
registerAgentFeedbackEditorActions();
|
||||
|
||||
registerSingleton(IAgentFeedbackService, AgentFeedbackService, InstantiationType.Delayed);
|
||||
|
||||
// Register the custom attachment widget for agentFeedback attachments
|
||||
class AgentFeedbackAttachmentWidgetContribution {
|
||||
static readonly ID = 'workbench.contrib.agentFeedbackAttachmentWidgetFactory';
|
||||
constructor(@IChatAttachmentWidgetRegistry registry: IChatAttachmentWidgetRegistry) {
|
||||
registry.registerFactory('agentFeedback', (instantiationService, attachment, options, container) => {
|
||||
return instantiationService.createInstance(AgentFeedbackAttachmentWidget, attachment as IAgentFeedbackVariableEntry, options, container);
|
||||
});
|
||||
}
|
||||
}
|
||||
registerWorkbenchContribution2(AgentFeedbackAttachmentWidgetContribution.ID, AgentFeedbackAttachmentWidgetContribution, WorkbenchPhase.AfterRestored);
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IAgentFeedbackService, IAgentFeedback } from './agentFeedbackService.js
|
||||
import { IChatWidgetService } from '../../../../workbench/contrib/chat/browser/chat.js';
|
||||
import { IAgentFeedbackVariableEntry } from '../../../../workbench/contrib/chat/common/attachments/chatVariableEntries.js';
|
||||
|
||||
const ATTACHMENT_ID_PREFIX = 'agentFeedback:';
|
||||
export const ATTACHMENT_ID_PREFIX = 'agentFeedback:';
|
||||
|
||||
/**
|
||||
* Keeps the "N feedback items" attachment in the chat input in sync with the
|
||||
|
||||
+9
-12
@@ -8,7 +8,7 @@ import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from '../../../../editor/browser/editorBrowser.js';
|
||||
import { IEditorContribution } from '../../../../editor/common/editorCommon.js';
|
||||
import { EditorContributionInstantiation, registerEditorContribution } from '../../../../editor/browser/editorExtensions.js';
|
||||
import { GlyphMarginLane, IModelDeltaDecoration, TrackedRangeStickiness } from '../../../../editor/common/model.js';
|
||||
import { IModelDeltaDecoration, TrackedRangeStickiness } from '../../../../editor/common/model.js';
|
||||
import { ModelDecorationOptions } from '../../../../editor/common/model/textModel.js';
|
||||
import { Range } from '../../../../editor/common/core/range.js';
|
||||
import { ThemeIcon } from '../../../../base/common/themables.js';
|
||||
@@ -20,19 +20,15 @@ import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browse
|
||||
import { getSessionForResource } from './agentFeedbackEditorUtils.js';
|
||||
import { Selection } from '../../../../editor/common/core/selection.js';
|
||||
|
||||
const GLYPH_MARGIN_LANE = GlyphMarginLane.Left;
|
||||
|
||||
const feedbackGlyphDecoration = ModelDecorationOptions.register({
|
||||
description: 'agent-feedback-glyph',
|
||||
glyphMarginClassName: `${ThemeIcon.asClassName(Codicon.comment)} agent-feedback-glyph`,
|
||||
glyphMargin: { position: GLYPH_MARGIN_LANE },
|
||||
linesDecorationsClassName: `${ThemeIcon.asClassName(Codicon.comment)} agent-feedback-glyph`,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
});
|
||||
|
||||
const addFeedbackHintDecoration = ModelDecorationOptions.register({
|
||||
description: 'agent-feedback-add-hint',
|
||||
glyphMarginClassName: `${ThemeIcon.asClassName(Codicon.add)} agent-feedback-add-hint`,
|
||||
glyphMargin: { position: GLYPH_MARGIN_LANE },
|
||||
linesDecorationsClassName: `${ThemeIcon.asClassName(Codicon.add)} agent-feedback-add-hint`,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
});
|
||||
|
||||
@@ -117,9 +113,10 @@ export class AgentFeedbackGlyphMarginContribution extends Disposable implements
|
||||
return;
|
||||
}
|
||||
|
||||
const isLineDecoration = e.target.type === MouseTargetType.GUTTER_LINE_DECORATIONS && !e.target.detail.isAfterLines;
|
||||
const isContentArea = e.target.type === MouseTargetType.CONTENT_TEXT || e.target.type === MouseTargetType.CONTENT_EMPTY;
|
||||
if (e.target.position
|
||||
&& e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN
|
||||
&& !e.target.detail.isAfterLines
|
||||
&& (isLineDecoration || isContentArea)
|
||||
&& !this._feedbackLines.has(e.target.position.lineNumber)
|
||||
) {
|
||||
this._updateHintDecoration(e.target.position.lineNumber);
|
||||
@@ -150,7 +147,7 @@ export class AgentFeedbackGlyphMarginContribution extends Disposable implements
|
||||
|
||||
private _onMouseDown(e: IEditorMouseEvent): void {
|
||||
if (!e.target.position
|
||||
|| e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN
|
||||
|| e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS
|
||||
|| e.target.detail.isAfterLines
|
||||
|| !this._sessionResource
|
||||
) {
|
||||
@@ -174,9 +171,9 @@ export class AgentFeedbackGlyphMarginContribution extends Disposable implements
|
||||
const endColumn = model.getLineLastNonWhitespaceColumn(lineNumber);
|
||||
if (startColumn === 0 || endColumn === 0) {
|
||||
// Empty line - select the whole line range
|
||||
this._editor.setSelection(new Selection(lineNumber, 1, lineNumber, model.getLineMaxColumn(lineNumber)));
|
||||
this._editor.setSelection(new Selection(lineNumber, model.getLineMaxColumn(lineNumber), lineNumber, 1));
|
||||
} else {
|
||||
this._editor.setSelection(new Selection(lineNumber, startColumn, lineNumber, endColumn));
|
||||
this._editor.setSelection(new Selection(lineNumber, endColumn, lineNumber, startColumn));
|
||||
}
|
||||
this._editor.focus();
|
||||
}
|
||||
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './media/agentFeedbackLineDecoration.css';
|
||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from '../../../../editor/browser/editorBrowser.js';
|
||||
import { IEditorContribution } from '../../../../editor/common/editorCommon.js';
|
||||
import { EditorContributionInstantiation, registerEditorContribution } from '../../../../editor/browser/editorExtensions.js';
|
||||
import { IModelDeltaDecoration, TrackedRangeStickiness } from '../../../../editor/common/model.js';
|
||||
import { ModelDecorationOptions } from '../../../../editor/common/model/textModel.js';
|
||||
import { Range } from '../../../../editor/common/core/range.js';
|
||||
import { ThemeIcon } from '../../../../base/common/themables.js';
|
||||
import { Codicon } from '../../../../base/common/codicons.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { IAgentFeedbackService } from './agentFeedbackService.js';
|
||||
import { IChatEditingService } from '../../../../workbench/contrib/chat/common/editing/chatEditingService.js';
|
||||
import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsService.js';
|
||||
import { getSessionForResource } from './agentFeedbackEditorUtils.js';
|
||||
import { Selection } from '../../../../editor/common/core/selection.js';
|
||||
|
||||
const feedbackLineDecoration = ModelDecorationOptions.register({
|
||||
description: 'agent-feedback-line-decoration',
|
||||
linesDecorationsClassName: `${ThemeIcon.asClassName(Codicon.comment)} agent-feedback-line-decoration`,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
});
|
||||
|
||||
const addFeedbackHintDecoration = ModelDecorationOptions.register({
|
||||
description: 'agent-feedback-add-hint',
|
||||
linesDecorationsClassName: `${ThemeIcon.asClassName(Codicon.add)} agent-feedback-add-hint`,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
});
|
||||
|
||||
export class AgentFeedbackLineDecorationContribution extends Disposable implements IEditorContribution {
|
||||
|
||||
static readonly ID = 'agentFeedback.lineDecorationContribution';
|
||||
|
||||
private readonly _feedbackDecorations;
|
||||
|
||||
private _hintDecorationId: string | null = null;
|
||||
private _hintLine = -1;
|
||||
private _sessionResource: URI | undefined;
|
||||
private _feedbackLines = new Set<number>();
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
@IAgentFeedbackService private readonly _agentFeedbackService: IAgentFeedbackService,
|
||||
@IChatEditingService private readonly _chatEditingService: IChatEditingService,
|
||||
@IAgentSessionsService private readonly _agentSessionsService: IAgentSessionsService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._feedbackDecorations = this._editor.createDecorationsCollection();
|
||||
|
||||
this._store.add(this._agentFeedbackService.onDidChangeFeedback(() => this._updateFeedbackDecorations()));
|
||||
this._store.add(this._editor.onDidChangeModel(() => this._onModelChanged()));
|
||||
this._store.add(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onMouseMove(e)));
|
||||
this._store.add(this._editor.onMouseLeave(() => this._updateHintDecoration(-1)));
|
||||
this._store.add(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onMouseDown(e)));
|
||||
|
||||
this._resolveSession();
|
||||
this._updateFeedbackDecorations();
|
||||
}
|
||||
|
||||
private _onModelChanged(): void {
|
||||
this._updateHintDecoration(-1);
|
||||
this._resolveSession();
|
||||
this._updateFeedbackDecorations();
|
||||
}
|
||||
|
||||
private _resolveSession(): void {
|
||||
const model = this._editor.getModel();
|
||||
if (!model) {
|
||||
this._sessionResource = undefined;
|
||||
return;
|
||||
}
|
||||
this._sessionResource = getSessionForResource(model.uri, this._chatEditingService, this._agentSessionsService);
|
||||
}
|
||||
|
||||
private _updateFeedbackDecorations(): void {
|
||||
if (!this._sessionResource) {
|
||||
this._feedbackDecorations.clear();
|
||||
this._feedbackLines.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
const feedbackItems = this._agentFeedbackService.getFeedback(this._sessionResource);
|
||||
const decorations: IModelDeltaDecoration[] = [];
|
||||
const lines = new Set<number>();
|
||||
|
||||
for (const item of feedbackItems) {
|
||||
const model = this._editor.getModel();
|
||||
if (!model || item.resourceUri.toString() !== model.uri.toString()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const line = item.range.startLineNumber;
|
||||
lines.add(line);
|
||||
decorations.push({
|
||||
range: new Range(line, 1, line, 1),
|
||||
options: feedbackLineDecoration,
|
||||
});
|
||||
}
|
||||
|
||||
this._feedbackLines = lines;
|
||||
this._feedbackDecorations.set(decorations);
|
||||
}
|
||||
|
||||
private _onMouseMove(e: IEditorMouseEvent): void {
|
||||
if (!this._sessionResource) {
|
||||
this._updateHintDecoration(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
const isLineDecoration = e.target.type === MouseTargetType.GUTTER_LINE_DECORATIONS && !e.target.detail.isAfterLines;
|
||||
const isContentArea = e.target.type === MouseTargetType.CONTENT_TEXT || e.target.type === MouseTargetType.CONTENT_EMPTY;
|
||||
if (e.target.position
|
||||
&& (isLineDecoration || isContentArea)
|
||||
&& !this._feedbackLines.has(e.target.position.lineNumber)
|
||||
) {
|
||||
this._updateHintDecoration(e.target.position.lineNumber);
|
||||
} else {
|
||||
this._updateHintDecoration(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private _updateHintDecoration(line: number): void {
|
||||
if (line === this._hintLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._hintLine = line;
|
||||
this._editor.changeDecorations(accessor => {
|
||||
if (this._hintDecorationId) {
|
||||
accessor.removeDecoration(this._hintDecorationId);
|
||||
this._hintDecorationId = null;
|
||||
}
|
||||
if (line !== -1) {
|
||||
this._hintDecorationId = accessor.addDecoration(
|
||||
new Range(line, 1, line, 1),
|
||||
addFeedbackHintDecoration,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _onMouseDown(e: IEditorMouseEvent): void {
|
||||
if (!e.target.position
|
||||
|| e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS
|
||||
|| e.target.detail.isAfterLines
|
||||
|| !this._sessionResource
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lineNumber = e.target.position.lineNumber;
|
||||
|
||||
// Lines with existing feedback - do nothing
|
||||
if (this._feedbackLines.has(lineNumber)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Select the line content and focus the editor
|
||||
const model = this._editor.getModel();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);
|
||||
const endColumn = model.getLineLastNonWhitespaceColumn(lineNumber);
|
||||
if (startColumn === 0 || endColumn === 0) {
|
||||
// Empty line - select the whole line range
|
||||
this._editor.setSelection(new Selection(lineNumber, model.getLineMaxColumn(lineNumber), lineNumber, 1));
|
||||
} else {
|
||||
this._editor.setSelection(new Selection(lineNumber, endColumn, lineNumber, startColumn));
|
||||
}
|
||||
this._editor.focus();
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
this._feedbackDecorations.clear();
|
||||
this._updateHintDecoration(-1);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorContribution(AgentFeedbackLineDecorationContribution.ID, AgentFeedbackLineDecorationContribution, EditorContributionInstantiation.Eventually);
|
||||
@@ -13,7 +13,6 @@ import { isEqual } from '../../../../base/common/resources.js';
|
||||
import { IChatEditingService } from '../../../../workbench/contrib/chat/common/editing/chatEditingService.js';
|
||||
import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsService.js';
|
||||
import { agentSessionContainsResource, editingEntriesContainResource } from '../../../../workbench/contrib/chat/browser/sessionResourceMatching.js';
|
||||
import { IChatWidget, IChatWidgetService } from '../../../../workbench/contrib/chat/browser/chat.js';
|
||||
|
||||
// --- Types --------------------------------------------------------------------
|
||||
|
||||
@@ -83,8 +82,6 @@ export interface IAgentFeedbackService {
|
||||
|
||||
// --- Implementation -----------------------------------------------------------
|
||||
|
||||
const AGENT_FEEDBACK_ATTACHMENT_ID_PREFIX = 'agentFeedback:';
|
||||
|
||||
export class AgentFeedbackService extends Disposable implements IAgentFeedbackService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
@@ -103,41 +100,8 @@ export class AgentFeedbackService extends Disposable implements IAgentFeedbackSe
|
||||
constructor(
|
||||
@IChatEditingService private readonly _chatEditingService: IChatEditingService,
|
||||
@IAgentSessionsService private readonly _agentSessionsService: IAgentSessionsService,
|
||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._registerChatWidgetListeners();
|
||||
}
|
||||
|
||||
private _registerChatWidgetListeners(): void {
|
||||
for (const widget of this._chatWidgetService.getAllWidgets()) {
|
||||
this._registerWidgetListeners(widget);
|
||||
}
|
||||
|
||||
this._store.add(this._chatWidgetService.onDidAddWidget(widget => {
|
||||
this._registerWidgetListeners(widget);
|
||||
}));
|
||||
}
|
||||
|
||||
private _registerWidgetListeners(widget: IChatWidget): void {
|
||||
this._store.add(widget.attachmentModel.onDidChange(e => {
|
||||
for (const deletedId of e.deleted) {
|
||||
if (!deletedId.startsWith(AGENT_FEEDBACK_ATTACHMENT_ID_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sessionResourceString = deletedId.slice(AGENT_FEEDBACK_ATTACHMENT_ID_PREFIX.length);
|
||||
if (!sessionResourceString) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sessionResource = URI.parse(sessionResourceString);
|
||||
if (this.getFeedback(sessionResource).length > 0) {
|
||||
this.clearFeedback(sessionResource);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
addFeedback(sessionResource: URI, resourceUri: URI, range: IRange, text: string): IAgentFeedback {
|
||||
|
||||
@@ -3,24 +3,23 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .glyph-margin-widgets .cgmr.agent-feedback-glyph,
|
||||
.monaco-editor .glyph-margin-widgets .cgmr.agent-feedback-add-hint {
|
||||
.monaco-editor .agent-feedback-glyph,
|
||||
.monaco-editor .agent-feedback-add-hint {
|
||||
border-radius: 3px;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.monaco-editor .glyph-margin-widgets .cgmr.agent-feedback-glyph {
|
||||
background-color: var(--vscode-editorGutter-commentGlyphForeground, var(--vscode-icon-foreground));
|
||||
color: var(--vscode-editor-background);
|
||||
.monaco-editor .agent-feedback-glyph {
|
||||
background-color: var(--vscode-toolbar-hoverBackground);
|
||||
}
|
||||
|
||||
.monaco-editor .glyph-margin-widgets .cgmr.agent-feedback-add-hint {
|
||||
.monaco-editor .agent-feedback-add-hint {
|
||||
background-color: var(--vscode-toolbar-hoverBackground);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.monaco-editor .glyph-margin-widgets .cgmr.agent-feedback-add-hint:hover {
|
||||
.monaco-editor .agent-feedback-add-hint:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .agent-feedback-line-decoration,
|
||||
.monaco-editor .agent-feedback-add-hint {
|
||||
border-radius: 3px;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.monaco-editor .agent-feedback-line-decoration {
|
||||
background-color: var(--vscode-toolbar-hoverBackground);
|
||||
}
|
||||
|
||||
.monaco-editor .agent-feedback-add-hint {
|
||||
background-color: var(--vscode-toolbar-hoverBackground);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.monaco-editor .agent-feedback-add-hint:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -124,10 +124,11 @@
|
||||
.ai-customization-toolbar .ai-customization-toolbar-content {
|
||||
max-height: 500px;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.2s ease-out;
|
||||
transition: max-height 0.2s ease-out, display 0s linear 0.2s;
|
||||
}
|
||||
|
||||
.ai-customization-toolbar.collapsed .ai-customization-toolbar-content {
|
||||
max-height: 0;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as event from '../../../../../base/common/event.js';
|
||||
import { IDisposable } from '../../../../../base/common/lifecycle.js';
|
||||
import { createDecorator, IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
|
||||
import { IChatRequestVariableEntry } from '../../common/attachments/chatVariableEntries.js';
|
||||
|
||||
/**
|
||||
* Interface for a contributed attachment widget instance.
|
||||
*/
|
||||
export interface IChatAttachmentWidgetInstance extends IDisposable {
|
||||
readonly element: HTMLElement;
|
||||
readonly onDidDelete: event.Event<Event>;
|
||||
readonly onDidOpen: event.Event<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function type for creating attachment widgets.
|
||||
* Receives the instantiation service so it can create DI-injected widget instances.
|
||||
*/
|
||||
export type ChatAttachmentWidgetFactory = (
|
||||
instantiationService: IInstantiationService,
|
||||
attachment: IChatRequestVariableEntry,
|
||||
options: { shouldFocusClearButton: boolean; supportsDeletion: boolean },
|
||||
container: HTMLElement,
|
||||
) => IChatAttachmentWidgetInstance;
|
||||
|
||||
export const IChatAttachmentWidgetRegistry = createDecorator<IChatAttachmentWidgetRegistry>('chatAttachmentWidgetRegistry');
|
||||
|
||||
export interface IChatAttachmentWidgetRegistry {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Register a widget factory for a specific attachment kind.
|
||||
*/
|
||||
registerFactory(kind: string, factory: ChatAttachmentWidgetFactory): IDisposable;
|
||||
|
||||
/**
|
||||
* Try to create a widget for the given attachment using a registered factory.
|
||||
* Returns undefined if no factory is registered for the attachment's kind.
|
||||
*/
|
||||
createWidget(
|
||||
instantiationService: IInstantiationService,
|
||||
attachment: IChatRequestVariableEntry,
|
||||
options: { shouldFocusClearButton: boolean; supportsDeletion: boolean },
|
||||
container: HTMLElement,
|
||||
): IChatAttachmentWidgetInstance | undefined;
|
||||
}
|
||||
|
||||
export class ChatAttachmentWidgetRegistry implements IChatAttachmentWidgetRegistry {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _factories = new Map<string, ChatAttachmentWidgetFactory>();
|
||||
|
||||
registerFactory(kind: string, factory: ChatAttachmentWidgetFactory): IDisposable {
|
||||
this._factories.set(kind, factory);
|
||||
return {
|
||||
dispose: () => {
|
||||
if (this._factories.get(kind) === factory) {
|
||||
this._factories.delete(kind);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
createWidget(
|
||||
instantiationService: IInstantiationService,
|
||||
attachment: IChatRequestVariableEntry,
|
||||
options: { shouldFocusClearButton: boolean; supportsDeletion: boolean },
|
||||
container: HTMLElement,
|
||||
): IChatAttachmentWidgetInstance | undefined {
|
||||
const factory = this._factories.get(attachment.kind);
|
||||
if (!factory) {
|
||||
return undefined;
|
||||
}
|
||||
return factory(instantiationService, attachment, options, container);
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,7 @@ import { ChatAccessibilityService } from './accessibility/chatAccessibilityServi
|
||||
import './attachments/chatAttachmentModel.js';
|
||||
import './widget/input/chatStatusWidget.js';
|
||||
import { ChatAttachmentResolveService, IChatAttachmentResolveService } from './attachments/chatAttachmentResolveService.js';
|
||||
import { ChatAttachmentWidgetRegistry, IChatAttachmentWidgetRegistry } from './attachments/chatAttachmentWidgetRegistry.js';
|
||||
import { ChatMarkdownAnchorService, IChatMarkdownAnchorService } from './widget/chatContentParts/chatMarkdownAnchorService.js';
|
||||
import { ChatContextPickService, IChatContextPickService } from './attachments/chatContextPickService.js';
|
||||
import { ChatInputBoxContentProvider } from './widget/input/editor/chatEditorInputContentProvider.js';
|
||||
@@ -1542,6 +1543,7 @@ registerSingleton(IPromptsService, PromptsService, InstantiationType.Delayed);
|
||||
registerSingleton(IChatContextPickService, ChatContextPickService, InstantiationType.Delayed);
|
||||
registerSingleton(IChatModeService, ChatModeService, InstantiationType.Delayed);
|
||||
registerSingleton(IChatAttachmentResolveService, ChatAttachmentResolveService, InstantiationType.Delayed);
|
||||
registerSingleton(IChatAttachmentWidgetRegistry, ChatAttachmentWidgetRegistry, InstantiationType.Delayed);
|
||||
registerSingleton(IChatTodoListService, ChatTodoListService, InstantiationType.Delayed);
|
||||
registerSingleton(IChatOutputRendererService, ChatOutputRendererService, InstantiationType.Delayed);
|
||||
registerSingleton(IChatLayoutService, ChatLayoutService, InstantiationType.Delayed);
|
||||
|
||||
@@ -100,6 +100,7 @@ import { ChatSessionPrimaryPickerAction, ChatSubmitAction, IChatExecuteActionCon
|
||||
import { AgentSessionProviders, getAgentSessionProvider } from '../../agentSessions/agentSessions.js';
|
||||
import { IAgentSessionsService } from '../../agentSessions/agentSessionsService.js';
|
||||
import { ChatAttachmentModel } from '../../attachments/chatAttachmentModel.js';
|
||||
import { IChatAttachmentWidgetRegistry } from '../../attachments/chatAttachmentWidgetRegistry.js';
|
||||
import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, PromptFileAttachmentWidget, PromptTextAttachmentWidget, SCMHistoryItemAttachmentWidget, SCMHistoryItemChangeAttachmentWidget, SCMHistoryItemChangeRangeAttachmentWidget, TerminalCommandAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../../attachments/chatAttachmentWidgets.js';
|
||||
import { ChatImplicitContexts } from '../../attachments/chatImplicitContext.js';
|
||||
import { ImplicitContextAttachmentWidget } from '../../attachments/implicitContextAttachment.js';
|
||||
@@ -512,6 +513,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
|
||||
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
|
||||
@IChatAttachmentWidgetRegistry private readonly _chatAttachmentWidgetRegistry: IChatAttachmentWidgetRegistry,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -2439,7 +2441,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
} else if (isSCMHistoryItemChangeRangeVariableEntry(attachment)) {
|
||||
attachmentWidget = this.instantiationService.createInstance(SCMHistoryItemChangeRangeAttachmentWidget, attachment, lm, options, container, this._contextResourceLabels);
|
||||
} else {
|
||||
attachmentWidget = this.instantiationService.createInstance(DefaultChatAttachmentWidget, resource, range, attachment, undefined, lm, options, container, this._contextResourceLabels);
|
||||
attachmentWidget = this._chatAttachmentWidgetRegistry.createWidget(this.instantiationService, attachment, options, container)
|
||||
?? this.instantiationService.createInstance(DefaultChatAttachmentWidget, resource, range, attachment, undefined, lm, options, container, this._contextResourceLabels);
|
||||
}
|
||||
|
||||
if (shouldFocusClearButton) {
|
||||
|
||||
Reference in New Issue
Block a user