diff --git a/package.json b/package.json index 3f736d096b4..090d88e772c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.98.0", - "distro": "b37092a45bb95e5098cefcf6809fa6973cfd2538", + "distro": "18d6e62cad16da70804e341893ae344d5cdcc6ee", "author": { "name": "Microsoft Corporation" }, diff --git a/src/vs/platform/dnd/browser/dnd.ts b/src/vs/platform/dnd/browser/dnd.ts index f83103d27a6..f00c4d08a73 100644 --- a/src/vs/platform/dnd/browser/dnd.ts +++ b/src/vs/platform/dnd/browser/dnd.ts @@ -13,7 +13,7 @@ import { ResourceMap } from '../../../base/common/map.js'; import { parse } from '../../../base/common/marshalling.js'; import { Schemas } from '../../../base/common/network.js'; import { isNative, isWeb } from '../../../base/common/platform.js'; -import { URI } from '../../../base/common/uri.js'; +import { URI, UriComponents } from '../../../base/common/uri.js'; import { localize } from '../../../nls.js'; import { IDialogService } from '../../dialogs/common/dialogs.js'; import { IBaseTextResourceEditorInput, ITextEditorSelection } from '../../editor/common/editor.js'; @@ -23,6 +23,7 @@ import { ByteSize, IFileService } from '../../files/common/files.js'; import { IInstantiationService, ServicesAccessor } from '../../instantiation/common/instantiation.js'; import { extractSelection } from '../../opener/common/opener.js'; import { Registry } from '../../registry/common/platform.js'; +import { IMarker } from '../../markers/common/markers.js'; //#region Editor / Resources DND @@ -30,7 +31,8 @@ import { Registry } from '../../registry/common/platform.js'; export const CodeDataTransfers = { EDITORS: 'CodeEditors', FILES: 'CodeFiles', - SYMBOLS: 'application/vnd.code.symbols' + SYMBOLS: 'application/vnd.code.symbols', + MARKERS: 'application/vnd.code.diagnostics', }; export interface IDraggedResourceEditorInput extends IBaseTextResourceEditorInput { @@ -414,8 +416,12 @@ export interface DocumentSymbolTransferData { kind: number; } -export function extractSymbolDropData(e: DragEvent): DocumentSymbolTransferData[] { - const rawSymbolsData = e.dataTransfer?.getData(CodeDataTransfers.SYMBOLS); +function setDataAsJSON(e: DragEvent, kind: string, data: unknown) { + e.dataTransfer?.setData(kind, JSON.stringify(data)); +} + +function getDataAsJSON(e: DragEvent, kind: string, defaultValue: T): T { + const rawSymbolsData = e.dataTransfer?.getData(kind); if (rawSymbolsData) { try { return JSON.parse(rawSymbolsData); @@ -424,11 +430,25 @@ export function extractSymbolDropData(e: DragEvent): DocumentSymbolTransferData[ } } - return []; + return defaultValue; +} + +export function extractSymbolDropData(e: DragEvent): DocumentSymbolTransferData[] { + return getDataAsJSON(e, CodeDataTransfers.SYMBOLS, []); } export function fillInSymbolsDragData(symbolsData: readonly DocumentSymbolTransferData[], e: DragEvent): void { - e.dataTransfer?.setData(CodeDataTransfers.SYMBOLS, JSON.stringify(symbolsData)); + setDataAsJSON(e, CodeDataTransfers.SYMBOLS, symbolsData); +} + +export type MarkerTransferData = IMarker | { uri: UriComponents }; + +export function extractMarkerDropData(e: DragEvent): MarkerTransferData[] | undefined { + return getDataAsJSON(e, CodeDataTransfers.MARKERS, undefined); +} + +export function fillInMarkersDragData(markerData: MarkerTransferData[], e: DragEvent): void { + setDataAsJSON(e, CodeDataTransfers.MARKERS, markerData); } /** diff --git a/src/vs/platform/extensions/common/extensionsApiProposals.ts b/src/vs/platform/extensions/common/extensionsApiProposals.ts index 96770454dac..8273d3c17d4 100644 --- a/src/vs/platform/extensions/common/extensionsApiProposals.ts +++ b/src/vs/platform/extensions/common/extensionsApiProposals.ts @@ -44,6 +44,9 @@ const _allApiProposals = { chatReferenceBinaryData: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatReferenceBinaryData.d.ts', }, + chatReferenceDiagnostic: { + proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatReferenceDiagnostic.d.ts', + }, chatTab: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatTab.d.ts', }, diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index 73cb120869a..602a67ea0d4 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -64,6 +64,15 @@ export namespace MarkerSeverity { return _displayStrings[a] || ''; } + const _displayStringsPlural: { [value: number]: string } = Object.create(null); + _displayStringsPlural[MarkerSeverity.Error] = localize('sev.errors', "Errors"); + _displayStringsPlural[MarkerSeverity.Warning] = localize('sev.warnings', "Warnings"); + _displayStringsPlural[MarkerSeverity.Info] = localize('sev.infos', "Infos"); + + export function toStringPlural(a: MarkerSeverity): string { + return _displayStringsPlural[a] || ''; + } + export function fromSeverity(severity: Severity): MarkerSeverity { switch (severity) { case Severity.Error: return MarkerSeverity.Error; diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index f926cde3ee2..3099a31228a 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -211,7 +211,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostUriOpeners = rpcProtocol.set(ExtHostContext.ExtHostUriOpeners, new ExtHostUriOpeners(rpcProtocol)); const extHostProfileContentHandlers = rpcProtocol.set(ExtHostContext.ExtHostProfileContentHandlers, new ExtHostProfileContentHandlers(rpcProtocol)); rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands, extHostLogService)); - const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostLogService, extHostCommands, extHostDocuments, extHostLanguageModels)); + const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostLogService, extHostCommands, extHostDocuments, extHostLanguageModels, extHostDiagnostics)); const extHostLanguageModelTools = rpcProtocol.set(ExtHostContext.ExtHostLanguageModelTools, new ExtHostLanguageModelTools(rpcProtocol)); const extHostAiRelatedInformation = rpcProtocol.set(ExtHostContext.ExtHostAiRelatedInformation, new ExtHostRelatedInformation(rpcProtocol)); const extHostAiEmbeddingVector = rpcProtocol.set(ExtHostContext.ExtHostAiEmbeddingVector, new ExtHostAiEmbeddingVector(rpcProtocol)); @@ -1544,6 +1544,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I ChatResultFeedbackKind: extHostTypes.ChatResultFeedbackKind, ChatVariableLevel: extHostTypes.ChatVariableLevel, ChatCompletionItem: extHostTypes.ChatCompletionItem, + ChatReferenceDiagnostic: extHostTypes.ChatReferenceDiagnostic, CallHierarchyIncomingCall: extHostTypes.CallHierarchyIncomingCall, CallHierarchyItem: extHostTypes.CallHierarchyItem, CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall, diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index d579589cc8a..d053ad5e5ea 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -32,6 +32,7 @@ import * as typeConvert from './extHostTypeConverters.js'; import * as extHostTypes from './extHostTypes.js'; import { isChatViewTitleActionContext } from '../../contrib/chat/common/chatActions.js'; import { IChatRelatedFile, IChatRequestDraft } from '../../contrib/chat/common/chatEditingService.js'; +import { ExtHostDiagnostics } from './extHostDiagnostics.js'; class ChatAgentResponseStream { @@ -324,7 +325,8 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS private readonly _logService: ILogService, private readonly _commands: ExtHostCommands, private readonly _documents: ExtHostDocuments, - private readonly _languageModels: ExtHostLanguageModels + private readonly _languageModels: ExtHostLanguageModels, + private readonly _diagnostics: ExtHostDiagnostics, ) { super(); this._proxy = mainContext.getProxy(MainContext.MainThreadChatAgents2); @@ -402,7 +404,7 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS const { request, location, history } = await this._createRequest(requestDto, context, detector.extension); const model = await this.getModelForRequest(request, detector.extension); - const extRequest = typeConvert.ChatAgentRequest.to(request, location, model, isProposedApiEnabled(detector.extension, 'chatReadonlyPromptReference')); + const extRequest = typeConvert.ChatAgentRequest.to(request, location, model, isProposedApiEnabled(detector.extension, 'chatReadonlyPromptReference'), this.getDiagnosticsWhenEnabled(detector.extension)); return detector.provider.provideParticipantDetection( extRequest, @@ -486,7 +488,7 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS stream = new ChatAgentResponseStream(agent.extension, request, this._proxy, this._commands.converter, sessionDisposables); const model = await this.getModelForRequest(request, agent.extension); - const extRequest = typeConvert.ChatAgentRequest.to(request, location, model, isProposedApiEnabled(agent.extension, 'chatReadonlyPromptReference')); + const extRequest = typeConvert.ChatAgentRequest.to(request, location, model, isProposedApiEnabled(agent.extension, 'chatReadonlyPromptReference'), this.getDiagnosticsWhenEnabled(agent.extension)); inFlightRequest = { requestId: requestDto.requestId, extRequest }; this._inFlightRequests.add(inFlightRequest); @@ -538,6 +540,13 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS } } + private getDiagnosticsWhenEnabled(extension: Readonly) { + if (!isProposedApiEnabled(extension, 'chatReferenceDiagnostic')) { + return []; + } + return this._diagnostics.getDiagnostics(); + } + private async prepareHistoryTurns(extension: Readonly, agentId: string, context: { history: IChatAgentHistoryEntryDto[] }): Promise<(vscode.ChatRequestTurn | vscode.ChatResponseTurn)[]> { const res: (vscode.ChatRequestTurn | vscode.ChatResponseTurn)[] = []; @@ -551,7 +560,7 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS const hasReadonlyProposal = isProposedApiEnabled(extension, 'chatReadonlyPromptReference'); const varsWithoutTools = h.request.variables.variables .filter(v => !v.isTool) - .map(v => typeConvert.ChatPromptReference.to(v, hasReadonlyProposal)); + .map(v => typeConvert.ChatPromptReference.to(v, hasReadonlyProposal, this.getDiagnosticsWhenEnabled(extension))); const toolReferences = h.request.variables.variables .filter(v => v.isTool) .map(typeConvert.ChatLanguageModelToolReference.to); diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 1acf66bce5e..edd8590eedd 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2761,7 +2761,7 @@ export namespace ChatResponsePart { } export namespace ChatAgentRequest { - export function to(request: IChatAgentRequest, location2: vscode.ChatRequestEditorData | vscode.ChatRequestNotebookData | undefined, model: vscode.LanguageModelChat, hasReadonlyProposal: boolean): vscode.ChatRequest { + export function to(request: IChatAgentRequest, location2: vscode.ChatRequestEditorData | vscode.ChatRequestNotebookData | undefined, model: vscode.LanguageModelChat, hasReadonlyProposal: boolean, diagnostics: readonly [vscode.Uri, readonly vscode.Diagnostic[]][]): vscode.ChatRequest { const toolReferences = request.variables.variables.filter(v => v.isTool); const variableReferences = request.variables.variables.filter(v => !v.isTool); return { @@ -2770,7 +2770,7 @@ export namespace ChatAgentRequest { attempt: request.attempt ?? 0, enableCommandDetection: request.enableCommandDetection ?? true, isParticipantDetected: request.isParticipantDetected ?? false, - references: variableReferences.map(v => ChatPromptReference.to(v, hasReadonlyProposal)), + references: variableReferences.map(v => ChatPromptReference.to(v, hasReadonlyProposal, diagnostics)), toolReferences: toolReferences.map(ChatLanguageModelToolReference.to), location: ChatLocation.to(request.location), acceptedConfirmationData: request.acceptedConfirmationData, @@ -2814,19 +2814,48 @@ export namespace ChatLocation { } export namespace ChatPromptReference { - export function to(variable: IChatRequestVariableEntry, hasReadonlyProposal: boolean): vscode.ChatPromptReference { - const value = variable.value; + export function to(variable: IChatRequestVariableEntry, hasReadonlyProposal: boolean, diagnostics: readonly [vscode.Uri, readonly vscode.Diagnostic[]][]): vscode.ChatPromptReference { + let value: vscode.ChatPromptReference['value'] = variable.value; if (!value) { throw new Error('Invalid value reference'); } + if (isUriComponents(value)) { + value = URI.revive(value); + } else if (value && typeof value === 'object' && 'uri' in value && 'range' in value && isUriComponents(value.uri)) { + value = Location.to(revive(value)); + } else if (variable.isImage) { + value = new types.ChatReferenceBinaryData( + variable.mimeType ?? 'image/png', + () => Promise.resolve(new Uint8Array(Object.values(variable.value as number[]))), + variable.references && URI.isUri(variable.references[0].reference) ? variable.references[0].reference : undefined + ); + } else if (variable.kind === 'diagnostic') { + const filterSeverity = variable.filterSeverity && DiagnosticSeverity.to(variable.filterSeverity); + const filterUri = variable.filterUri && URI.revive(variable.filterUri).toString(); + value = new types.ChatReferenceDiagnostic(diagnostics.map(([uri, d]): [vscode.Uri, vscode.Diagnostic[]] => { + if (variable.filterUri && uri.toString() !== filterUri) { + return [uri, []]; + } + + return [uri, d.filter(d => { + if (filterSeverity && d.severity > filterSeverity) { + return false; + } + if (variable.filterRange && !editorRange.Range.areIntersectingOrTouching(variable.filterRange, Range.from(d.range))) { + return false; + } + + return true; + })]; + }).filter(([, d]) => d.length > 0)); + } + return { id: variable.id, name: variable.name, range: variable.range && [variable.range.start, variable.range.endExclusive], - value: isUriComponents(value) ? URI.revive(value) : - value && typeof value === 'object' && 'uri' in value && 'range' in value && isUriComponents(value.uri) ? - Location.to(revive(value)) : variable.isImage ? new types.ChatReferenceBinaryData(variable.mimeType ?? 'image/png', () => Promise.resolve(new Uint8Array(Object.values(value))), variable.references && URI.isUri(variable.references[0].reference) ? variable.references[0].reference : undefined) : value, + value, modelDescription: variable.modelDescription, isReadonly: hasReadonlyProposal ? variable.isMarkedReadonly : undefined, }; diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index f27aac8e007..75d1061cfcc 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4716,6 +4716,10 @@ export class ChatReferenceBinaryData implements vscode.ChatReferenceBinaryData { } } +export class ChatReferenceDiagnostic implements vscode.ChatReferenceDiagnostic { + constructor(public readonly diagnostics: [vscode.Uri, vscode.Diagnostic[]][]) { } +} + export enum LanguageModelChatMessageRole { User = 1, Assistant = 2, diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 239e5bb89ac..72def8c4b99 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -646,18 +646,24 @@ export class ResourceListDnDHandler implements IListDragAndDrop { onDragStart(data: IDragAndDropData, originalEvent: DragEvent): void { const resources: URI[] = []; - for (const element of (data as ElementsDragAndDropData).elements) { + const elements = (data as ElementsDragAndDropData).elements; + for (const element of elements) { const resource = this.toResource(element); if (resource) { resources.push(resource); } } + this.onWillDragElements(elements, originalEvent); if (resources.length) { // Apply some datatransfer types to allow for dragging the element outside of the application this.instantiationService.invokeFunction(accessor => fillEditorsDragData(accessor, resources, originalEvent)); } } + protected onWillDragElements(elements: readonly T[], originalEvent: DragEvent): void { + // noop + } + onDragOver(data: IDragAndDropData, targetElement: T, targetIndex: number, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): boolean | ITreeDragOverReaction { return false; } diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index de0ad326f51..5e958cb32dd 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -49,14 +49,14 @@ import { SearchContext } from '../../../search/common/constants.js'; import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { IChatRequestVariableEntry } from '../../common/chatModel.js'; +import { IChatRequestVariableEntry, IDiagnosticVariableEntryFilterData } from '../../common/chatModel.js'; import { ChatRequestAgentPart } from '../../common/chatParserTypes.js'; import { IChatVariablesService } from '../../common/chatVariables.js'; import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; import { IChatWidget, IChatWidgetService, IQuickChatService, showChatView, showEditsView } from '../chat.js'; import { imageToHash, isImage } from '../chatPasteProviders.js'; import { isQuickChat } from '../chatWidget.js'; -import { createFolderQuickPick } from '../contrib/chatDynamicVariables.js'; +import { createFolderQuickPick, createMarkersQuickPick } from '../contrib/chatDynamicVariables.js'; import { convertBufferToScreenshotVariable, ScreenshotVariableId } from '../contrib/screenshot.js'; import { resizeImage } from '../imageUtils.js'; import { CHAT_CATEGORY } from './chatActions.js'; @@ -75,7 +75,7 @@ export function registerChatContextActions() { */ type IAttachmentQuickPickItem = ICommandVariableQuickPickItem | IQuickAccessQuickPickItem | IToolQuickPickItem | IImageQuickPickItem | IOpenEditorsQuickPickItem | ISearchResultsQuickPickItem | - IScreenShotQuickPickItem | IRelatedFilesQuickPickItem | IPromptInstructionsQuickPickItem | IFolderQuickPickItem; + IScreenShotQuickPickItem | IRelatedFilesQuickPickItem | IPromptInstructionsQuickPickItem | IFolderQuickPickItem | IDiagnosticsQuickPickItem; /** * These are the types that we can get out of the quick pick @@ -103,6 +103,12 @@ function isIFolderSearchResultQuickPickItem(obj: unknown): obj is IFolderResultQ && (obj as IFolderResultQuickPickItem).kind === 'folder-search-result'); } +function isIDiagnosticsQuickPickItemWithFilter(obj: unknown): obj is IDiagnosticsQuickPickItemWithFilter { + return ( + typeof obj === 'object' + && (obj as IDiagnosticsQuickPickItemWithFilter).kind === 'diagnostic-filter'); +} + function isIQuickPickItemWithResource(obj: unknown): obj is IQuickPickItemWithResource { return ( typeof obj === 'object' @@ -210,6 +216,19 @@ interface IScreenShotQuickPickItem extends IQuickPickItem { icon?: ThemeIcon; } +interface IDiagnosticsQuickPickItem extends IQuickPickItem { + kind: 'diagnostic'; + id: string; + icon?: ThemeIcon; +} + +interface IDiagnosticsQuickPickItemWithFilter extends IQuickPickItem { + kind: 'diagnostic-filter'; + id: string; + filter: IDiagnosticVariableEntryFilterData; + icon?: ThemeIcon; +} + /** * Quick pick item for prompt instructions attachment. */ @@ -499,6 +518,14 @@ export class AttachContextAction extends Action2 { isFile: false, isDirectory: true, }); + } else if (isIDiagnosticsQuickPickItemWithFilter(pick)) { + toAttach.push({ + id: pick.id, + name: pick.label, + value: pick.filter, + kind: 'diagnostic', + ...pick.filter, + }); } else if (isIQuickPickItemWithResource(pick) && pick.resource) { if (/\.(png|jpg|jpeg|bmp|gif|tiff)$/i.test(pick.resource.path)) { // checks if the file is an image @@ -750,6 +777,13 @@ export class AttachContextAction extends Action2 { id: 'folder', }); + quickPickItems.push({ + kind: 'diagnostic', + label: localize('chatContext.diagnstic', 'Problem...'), + iconClass: ThemeIcon.asClassName(Codicon.error), + id: 'diagnostic' + }); + if (widget.location === ChatAgentLocation.Notebook) { quickPickItems.push({ kind: 'command', @@ -824,16 +858,33 @@ export class AttachContextAction extends Action2 { }), clipboardService, editorService, labelService, viewsService, chatEditingService, hostService, fileService, textModelService, instantiationService, '', context?.placeholder); } + private async _showDiagnosticsPick(instantiationService: IInstantiationService): Promise { + const filter = await instantiationService.invokeFunction(accessor => createMarkersQuickPick(accessor)); + if (!filter) { + return undefined; + } + + return { + kind: 'diagnostic-filter', + id: IDiagnosticVariableEntryFilterData.id(filter), + label: IDiagnosticVariableEntryFilterData.label(filter), + filter, + }; + } + private _show(quickInputService: IQuickInputService, commandService: ICommandService, widget: IChatWidget, quickChatService: IQuickChatService, quickPickItems: (IChatContextQuickPickItem | QuickPickItem)[] | undefined, clipboardService: IClipboardService, editorService: IEditorService, labelService: ILabelService, viewsService: IViewsService, chatEditingService: IChatEditingService | undefined, hostService: IHostService, fileService: IFileService, textModelService: ITextModelService, instantiationService: IInstantiationService, query: string = '', placeholder?: string) { const providerOptions: AnythingQuickAccessProviderRunOptions = { - handleAccept: async (item: IChatContextQuickPickItem, isBackgroundAccept: boolean) => { + handleAccept: async (inputItem: IChatContextQuickPickItem, isBackgroundAccept: boolean) => { + let item: IChatContextQuickPickItem | undefined = inputItem; if ('kind' in item && item.kind === 'folder') { - const folderItem = await this._showFolders(instantiationService); - if (!folderItem) { - this._show(quickInputService, commandService, widget, quickChatService, quickPickItems, clipboardService, editorService, labelService, viewsService, chatEditingService, hostService, fileService, textModelService, instantiationService, '', placeholder); - return; - } - item = folderItem; + item = await this._showFolders(instantiationService); + } else if ('kind' in item && item.kind === 'diagnostic') { + item = await this._showDiagnosticsPick(instantiationService); + } + + if (!item) { + this._show(quickInputService, commandService, widget, quickChatService, quickPickItems, clipboardService, editorService, labelService, viewsService, chatEditingService, hostService, fileService, textModelService, instantiationService, '', placeholder); + return; } if ('prefix' in item) { diff --git a/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts b/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts index 522a7257756..a6f55ecebbe 100644 --- a/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts +++ b/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts @@ -11,21 +11,23 @@ import { Codicon } from '../../../../base/common/codicons.js'; import { IDisposable } from '../../../../base/common/lifecycle.js'; import { Mimes } from '../../../../base/common/mime.js'; import { basename, joinPath } from '../../../../base/common/resources.js'; +import { Mutable } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { IRange } from '../../../../editor/common/core/range.js'; import { SymbolKinds } from '../../../../editor/common/languages.js'; import { ITextModelService } from '../../../../editor/common/services/resolverService.js'; import { localize } from '../../../../nls.js'; import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; -import { CodeDataTransfers, containsDragType, DocumentSymbolTransferData, extractEditorsDropData, extractSymbolDropData, IDraggedResourceEditorInput } from '../../../../platform/dnd/browser/dnd.js'; +import { CodeDataTransfers, containsDragType, DocumentSymbolTransferData, extractEditorsDropData, extractMarkerDropData, extractSymbolDropData, IDraggedResourceEditorInput, MarkerTransferData } from '../../../../platform/dnd/browser/dnd.js'; import { FileType, IFileService, IFileSystemProvider } from '../../../../platform/files/common/files.js'; +import { MarkerSeverity } from '../../../../platform/markers/common/markers.js'; import { IThemeService, Themable } from '../../../../platform/theme/common/themeService.js'; import { isUntitledResourceEditorInput } from '../../../common/editor.js'; import { EditorInput } from '../../../common/editor/editorInput.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { IExtensionService, isProposedApiEnabled } from '../../../services/extensions/common/extensions.js'; import { UntitledTextEditorInput } from '../../../services/untitled/common/untitledTextEditorInput.js'; -import { IChatRequestVariableEntry, ISymbolVariableEntry } from '../common/chatModel.js'; +import { IChatRequestVariableEntry, IDiagnosticVariableEntry, IDiagnosticVariableEntryFilterData, ISymbolVariableEntry } from '../common/chatModel.js'; import { ChatAttachmentModel } from './chatAttachmentModel.js'; import { IChatInputStyles } from './chatInputPart.js'; import { resizeImage } from './imageUtils.js'; @@ -35,7 +37,8 @@ enum ChatDragAndDropType { FILE_EXTERNAL, FOLDER, IMAGE, - SYMBOL + SYMBOL, + MARKER, } export class ChatDragAndDrop extends Themable { @@ -169,6 +172,8 @@ export class ChatDragAndDrop extends Themable { return this.extensionService.extensions.some(ext => isProposedApiEnabled(ext, 'chatReferenceBinaryData')) ? ChatDragAndDropType.IMAGE : undefined; } else if (containsDragType(e, CodeDataTransfers.SYMBOLS)) { return ChatDragAndDropType.SYMBOL; + } else if (containsDragType(e, CodeDataTransfers.MARKERS)) { + return ChatDragAndDropType.MARKER; } else if (containsDragType(e, DataTransfers.FILES)) { return ChatDragAndDropType.FILE_EXTERNAL; } else if (containsDragType(e, DataTransfers.INTERNAL_URI_LIST)) { @@ -193,6 +198,7 @@ export class ChatDragAndDrop extends Themable { case ChatDragAndDropType.FOLDER: return localize('folder', 'Folder'); case ChatDragAndDropType.IMAGE: return localize('image', 'Image'); case ChatDragAndDropType.SYMBOL: return localize('symbol', 'Symbol'); + case ChatDragAndDropType.MARKER: return localize('problem', 'Problem'); } } @@ -224,6 +230,11 @@ export class ChatDragAndDrop extends Themable { return []; } + const markerData = extractMarkerDropData(e); + if (markerData) { + return this.resolveMarkerAttachContext(markerData); + } + if (containsDragType(e, CodeDataTransfers.SYMBOLS)) { const data = extractSymbolDropData(e); return this.resolveSymbolsAttachContext(data); @@ -304,6 +315,33 @@ export class ChatDragAndDrop extends Themable { }); } + private resolveMarkerAttachContext(markers: MarkerTransferData[]): IDiagnosticVariableEntry[] { + return markers.map((marker): IDiagnosticVariableEntry => { + const filter: Mutable = {}; + if (!('severity' in marker)) { + filter.filterUri = URI.revive(marker.uri); + filter.filterSeverity = MarkerSeverity.Warning; + } else { + filter.filterUri = URI.revive(marker.resource); + filter.filterSeverity = marker.severity; + filter.filterRange = { + startLineNumber: marker.startLineNumber, + startColumn: marker.startColumn, + endLineNumber: marker.endLineNumber, + endColumn: marker.endColumn + }; + } + + return { + kind: 'diagnostic', + id: IDiagnosticVariableEntryFilterData.id(filter), + name: IDiagnosticVariableEntryFilterData.label(filter), + value: filter, + ...filter, + }; + }); + } + private setOverlay(target: HTMLElement, type: ChatDragAndDropType | undefined): void { // Remove any previous overlay text this.overlayText?.remove(); diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts index 9c805598653..0bf919d40f0 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts @@ -4,11 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { coalesce } from '../../../../../base/common/arrays.js'; +import { CancellationToken } from '../../../../../base/common/cancellation.js'; +import { Codicon } from '../../../../../base/common/codicons.js'; import { isCancellationError } from '../../../../../base/common/errors.js'; +import * as glob from '../../../../../base/common/glob.js'; import { IMarkdownString, MarkdownString } from '../../../../../base/common/htmlContent.js'; import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js'; import { ResourceSet } from '../../../../../base/common/map.js'; import { basename, dirname, joinPath, relativePath } from '../../../../../base/common/resources.js'; +import { ThemeIcon } from '../../../../../base/common/themables.js'; import { URI } from '../../../../../base/common/uri.js'; import { IRange, Range } from '../../../../../editor/common/core/range.js'; import { IDecorationOptions } from '../../../../../editor/common/editorCommon.js'; @@ -22,20 +26,19 @@ import { FileType, IFileService } from '../../../../../platform/files/common/fil import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; import { ILogService } from '../../../../../platform/log/common/log.js'; +import { IMarkerService, MarkerSeverity } from '../../../../../platform/markers/common/markers.js'; +import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; import { IQuickAccessOptions } from '../../../../../platform/quickinput/common/quickAccess.js'; -import { IQuickInputService, IQuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js'; +import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js'; +import { IUriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentity.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; -import { getExcludes, ISearchConfiguration, IFileQuery, QueryType, ISearchComplete, ISearchService } from '../../../../services/search/common/search.js'; +import { getExcludes, IFileQuery, ISearchComplete, ISearchConfiguration, ISearchService, QueryType } from '../../../../services/search/common/search.js'; import { ISymbolQuickPickItem } from '../../../search/browser/symbolsQuickAccess.js'; +import { IDiagnosticVariableEntryFilterData } from '../../common/chatModel.js'; import { IChatRequestVariableValue, IDynamicVariable } from '../../common/chatVariables.js'; -import * as glob from '../../../../../base/common/glob.js'; import { IChatWidget } from '../chat.js'; import { ChatWidget, IChatWidgetContrib } from '../chatWidget.js'; import { ChatFileReference } from './chatDynamicVariables/chatFileReference.js'; -import { CancellationToken } from '../../../../../base/common/cancellation.js'; -import { ThemeIcon } from '../../../../../base/common/themables.js'; -import { Codicon } from '../../../../../base/common/codicons.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; export const dynamicVariableDecorationType = 'chat-dynamic-variable'; @@ -645,3 +648,57 @@ export class AddDynamicVariableAction extends Action2 { } } registerAction2(AddDynamicVariableAction); + +export async function createMarkersQuickPick(accessor: ServicesAccessor): Promise { + const markers = accessor.get(IMarkerService).read(); + if (!markers.length) { + return; + } + + const uriIdentityService = accessor.get(IUriIdentityService); + const labelService = accessor.get(ILabelService); + markers.sort((a, b) => uriIdentityService.extUri.compare(a.resource, b.resource) || b.severity - a.severity); + + const severities = new Set(); + type MarkerPickItem = IQuickPickItem & { resource?: URI; entry: IDiagnosticVariableEntryFilterData }; + const items: (MarkerPickItem | IQuickPickSeparator)[] = []; + for (const marker of markers) { + if (!uriIdentityService.extUri.isEqual(marker.resource, (items.at(-1) as MarkerPickItem)?.resource)) { + items.push({ type: 'separator', label: labelService.getUriLabel(marker.resource, { relative: true }) }); + } + + severities.add(marker.severity); + items.push({ + type: 'item', + resource: marker.resource, + label: marker.message, + description: localize('markers.panel.at.ln.col.number', "[Ln {0}, Col {1}]", '' + marker.startLineNumber, '' + marker.startColumn), + entry: { filterUri: marker.resource, filterRange: { startLineNumber: marker.startLineNumber, endLineNumber: marker.endLineNumber, startColumn: marker.startColumn, endColumn: marker.endColumn } } + }); + } + + if (items.length === 2) { // single error in a URI + return (items[1] as MarkerPickItem).entry; + } + + if (items.length > 2) { + if (severities.has(MarkerSeverity.Error)) { + items.unshift({ type: 'item', label: localize('markers.panel.allErrors', 'All Errors'), entry: { filterSeverity: MarkerSeverity.Error } }); + } + if (severities.has(MarkerSeverity.Warning)) { + items.unshift({ type: 'item', label: localize('markers.panel.allWarnings', 'All Warnings'), entry: { filterSeverity: MarkerSeverity.Warning } }); + } + if (severities.has(MarkerSeverity.Info)) { + items.unshift({ type: 'item', label: localize('markers.panel.allInfos', 'All Infos'), entry: { filterSeverity: MarkerSeverity.Info } }); + } + } + + + const quickInputService = accessor.get(IQuickInputService); + const quickPick = quickInputService.createQuickPick({ useSeparators: true }); + quickPick.placeholder = localize('pickAProblem', 'Pick a problem to attach...'); + quickPick.items = items; + + return quickInputService.pick(items, { canPickMany: false }).then(v => v?.entry); +} + diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index dec4623cd07..2eccb6163ef 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -21,6 +21,7 @@ import { IRange } from '../../../../editor/common/core/range.js'; import { Location, SymbolKind, TextEdit } from '../../../../editor/common/languages.js'; import { localize } from '../../../../nls.js'; import { ILogService } from '../../../../platform/log/common/log.js'; +import { MarkerSeverity } from '../../../../platform/markers/common/markers.js'; import { ICellEditOperation } from '../../notebook/common/notebookCommon.js'; import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, IChatWelcomeMessageContent, reviveSerializedAgent } from './chatAgents.js'; import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js'; @@ -87,7 +88,39 @@ export interface ILinkVariableEntry extends Omit, IDiagnosticVariableEntryFilterData { + readonly kind: 'diagnostic'; +} + +export type IChatRequestVariableEntry = IChatRequestImplicitVariableEntry | IChatRequestPasteVariableEntry | ISymbolVariableEntry | ICommandResultVariableEntry | ILinkVariableEntry | IBaseChatRequestVariableEntry | IDiagnosticVariableEntry; export function isImplicitVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestImplicitVariableEntry { return obj.kind === 'implicit'; @@ -101,6 +134,10 @@ export function isLinkVariableEntry(obj: IChatRequestVariableEntry): obj is ILin return obj.kind === 'link'; } +export function isDiagnosticsVariableEntry(obj: IChatRequestVariableEntry): obj is IDiagnosticVariableEntry { + return obj.kind === 'diagnostic'; +} + export function isChatRequestVariableEntry(obj: unknown): obj is IChatRequestVariableEntry { const entry = obj as IChatRequestVariableEntry; return typeof entry === 'object' && diff --git a/src/vs/workbench/contrib/markers/browser/markersView.ts b/src/vs/workbench/contrib/markers/browser/markersView.ts index 85ad02f34be..f80cfdeebaa 100644 --- a/src/vs/workbench/contrib/markers/browser/markersView.ts +++ b/src/vs/workbench/contrib/markers/browser/markersView.ts @@ -5,57 +5,59 @@ import './media/markers.css'; -import { URI } from '../../../../base/common/uri.js'; import * as dom from '../../../../base/browser/dom.js'; -import { IAction, Separator } from '../../../../base/common/actions.js'; -import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; -import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from '../../../services/editor/common/editorService.js'; -import { Marker, ResourceMarkers, RelatedInformation, MarkerChangesEvent, MarkersModel, compareMarkersByUri, MarkerElement, MarkerTableItem } from './markersModel.js'; -import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; -import { MarkersFilters, IMarkersFiltersChangeEvent } from './markersViewActions.js'; -import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; -import Messages from './messages.js'; -import { RangeHighlightDecorations } from '../../../browser/codeeditor.js'; -import { IThemeService } from '../../../../platform/theme/common/themeService.js'; -import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js'; -import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; -import { localize } from '../../../../nls.js'; -import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { Iterable } from '../../../../base/common/iterator.js'; -import { ITreeElement, ITreeNode, ITreeContextMenuEvent, ITreeRenderer, ITreeEvent } from '../../../../base/browser/ui/tree/tree.js'; -import { Relay, Event } from '../../../../base/common/event.js'; -import { WorkbenchObjectTree, IListService, IWorkbenchObjectTreeOptions, IOpenEvent } from '../../../../platform/list/browser/listService.js'; -import { FilterOptions } from './markersFilterOptions.js'; -import { IExpression } from '../../../../base/common/glob.js'; -import { deepClone } from '../../../../base/common/objects.js'; -import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; -import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, MarkersWidgetAccessibilityProvider, MarkersViewModel } from './markersTreeViewer.js'; -import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; -import { MenuId } from '../../../../platform/actions/common/actions.js'; -import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; -import { StandardKeyboardEvent, IKeyboardEvent } from '../../../../base/browser/keyboardEvent.js'; -import { ResourceLabels } from '../../../browser/labels.js'; -import { IMarkerService, MarkerSeverity } from '../../../../platform/markers/common/markers.js'; -import { MementoObject, Memento } from '../../../common/memento.js'; -import { IIdentityProvider, IListVirtualDelegate } from '../../../../base/browser/ui/list/list.js'; -import { KeyCode } from '../../../../base/common/keyCodes.js'; -import { IViewPaneOptions, FilterViewPane } from '../../../browser/parts/views/viewPane.js'; -import { IViewDescriptorService } from '../../../common/views.js'; -import { IOpenerService, withSelection } from '../../../../platform/opener/common/opener.js'; +import { IKeyboardEvent, StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js'; import { ActionViewItem } from '../../../../base/browser/ui/actionbar/actionViewItems.js'; -import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js'; -import { DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; -import { groupBy } from '../../../../base/common/arrays.js'; -import { ResourceMap } from '../../../../base/common/map.js'; -import { EditorResourceAccessor, SideBySideEditor } from '../../../common/editor.js'; -import { IMarkersView } from './markers.js'; -import { ResourceListDnDHandler } from '../../../browser/dnd.js'; +import { IIdentityProvider, IListVirtualDelegate } from '../../../../base/browser/ui/list/list.js'; import { ITableContextMenuEvent, ITableEvent } from '../../../../base/browser/ui/table/table.js'; -import { MarkersTable } from './markersTable.js'; -import { Markers, MarkersContextKeys, MarkersViewMode } from '../common/markers.js'; -import { registerNavigableContainer } from '../../../browser/actions/widgetNavigationCommands.js'; +import { ITreeContextMenuEvent, ITreeElement, ITreeEvent, ITreeNode, ITreeRenderer } from '../../../../base/browser/ui/tree/tree.js'; +import { IAction, Separator } from '../../../../base/common/actions.js'; +import { groupBy } from '../../../../base/common/arrays.js'; +import { Event, Relay } from '../../../../base/common/event.js'; +import { IExpression } from '../../../../base/common/glob.js'; +import { Iterable } from '../../../../base/common/iterator.js'; +import { KeyCode } from '../../../../base/common/keyCodes.js'; +import { DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; +import { ResourceMap } from '../../../../base/common/map.js'; +import { deepClone } from '../../../../base/common/objects.js'; +import { isDefined } from '../../../../base/common/types.js'; +import { URI } from '../../../../base/common/uri.js'; +import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js'; +import { localize } from '../../../../nls.js'; +import { MenuId } from '../../../../platform/actions/common/actions.js'; +import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; +import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; +import { fillInMarkersDragData, MarkerTransferData } from '../../../../platform/dnd/browser/dnd.js'; import { IHoverService } from '../../../../platform/hover/browser/hover.js'; +import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; +import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; import { ResultKind } from '../../../../platform/keybinding/common/keybindingResolver.js'; +import { IListService, IOpenEvent, IWorkbenchObjectTreeOptions, WorkbenchObjectTree } from '../../../../platform/list/browser/listService.js'; +import { IMarkerService, MarkerSeverity } from '../../../../platform/markers/common/markers.js'; +import { IOpenerService, withSelection } from '../../../../platform/opener/common/opener.js'; +import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; +import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; +import { IThemeService } from '../../../../platform/theme/common/themeService.js'; +import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js'; +import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; +import { registerNavigableContainer } from '../../../browser/actions/widgetNavigationCommands.js'; +import { RangeHighlightDecorations } from '../../../browser/codeeditor.js'; +import { ResourceListDnDHandler } from '../../../browser/dnd.js'; +import { ResourceLabels } from '../../../browser/labels.js'; +import { FilterViewPane, IViewPaneOptions } from '../../../browser/parts/views/viewPane.js'; +import { EditorResourceAccessor, SideBySideEditor } from '../../../common/editor.js'; +import { Memento, MementoObject } from '../../../common/memento.js'; +import { IViewDescriptorService } from '../../../common/views.js'; +import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from '../../../services/editor/common/editorService.js'; +import { Markers, MarkersContextKeys, MarkersViewMode } from '../common/markers.js'; +import { IMarkersView } from './markers.js'; +import { FilterOptions } from './markersFilterOptions.js'; +import { compareMarkersByUri, Marker, MarkerChangesEvent, MarkerElement, MarkersModel, MarkerTableItem, RelatedInformation, ResourceMarkers } from './markersModel.js'; +import { MarkersTable } from './markersTable.js'; +import { Filter, FilterData, MarkerRenderer, MarkersViewModel, MarkersWidgetAccessibilityProvider, RelatedInformationRenderer, ResourceMarkersRenderer, VirtualDelegate } from './markersTreeViewer.js'; +import { IMarkersFiltersChangeEvent, MarkersFilters } from './markersViewActions.js'; +import Messages from './messages.js'; function createResourceMarkersIterator(resourceMarkers: ResourceMarkers): Iterable> { return Iterable.map(resourceMarkers.markers, m => { @@ -495,18 +497,7 @@ export class MarkersView extends FilterViewPane implements IMarkersView { filter: this.filter, accessibilityProvider: this.widgetAccessibilityProvider, identityProvider: this.widgetIdentityProvider, - dnd: this.instantiationService.createInstance(ResourceListDnDHandler, (element) => { - if (element instanceof ResourceMarkers) { - return element.resource; - } - if (element instanceof Marker) { - return withSelection(element.resource, element.range); - } - if (element instanceof RelatedInformation) { - return withSelection(element.raw.resource, element.raw); - } - return null; - }), + dnd: this.instantiationService.createInstance(MarkersListDnDHandler), expandOnlyOnTwistieClick: (e: MarkerElement) => e instanceof Marker && e.relatedInformation.length > 0, overrideStyles: this.getLocationBasedColors().listOverrideStyles, selectionNavigation: true, @@ -1078,3 +1069,40 @@ class MarkersTree extends WorkbenchObjectTree impleme super.layout(height, width); } } + +class MarkersListDnDHandler extends ResourceListDnDHandler { + constructor( + @IInstantiationService instantiationService: IInstantiationService + ) { + super(element => { + if (element instanceof MarkerTableItem) { + return withSelection(element.resource, element.range); + } else if (element instanceof ResourceMarkers) { + return element.resource; + } else if (element instanceof Marker) { + return withSelection(element.resource, element.range); + } else if (element instanceof RelatedInformation) { + return withSelection(element.raw.resource, element.raw); + } + return null; + }, instantiationService); + } + + protected override onWillDragElements(elements: (MarkerElement | MarkerTableItem)[], originalEvent: DragEvent) { + const data = elements.map((e): MarkerTransferData | undefined => { + if (e instanceof RelatedInformation || e instanceof Marker) { + return e.marker; + } + if (e instanceof ResourceMarkers) { + return { uri: e.resource }; + } + return undefined; + }).filter(isDefined); + + if (!data.length) { + return; + } + + fillInMarkersDragData(data, originalEvent); + } +} diff --git a/src/vscode-dts/vscode.proposed.chatReferenceDiagnostic.d.ts b/src/vscode-dts/vscode.proposed.chatReferenceDiagnostic.d.ts new file mode 100644 index 00000000000..855015de891 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.chatReferenceDiagnostic.d.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + export interface ChatPromptReference { + /** + * The value of this reference. The `string | Uri | Location` types are used today, but this could expand in the future. + */ + readonly value: string | Uri | Location | ChatReferenceDiagnostic | unknown; + } + + export class ChatReferenceDiagnostic { + /** + * All attached diagnostics. An array of uri-diagnostics tuples or an empty array. + */ + readonly diagnostics: [Uri, Diagnostic[]][]; + + protected constructor(diagnostics: [Uri, Diagnostic[]][]); + } +}