From e43413a838c1b470fc234d8361a09501c9d6c3a6 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Mon, 4 Dec 2023 23:08:41 +0800 Subject: [PATCH 001/236] Apply `font-variation-settings` to `suggestWidgetRenderer` --- src/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.ts b/src/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.ts index 0a6faccef30..3ae939c32f8 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.ts @@ -131,6 +131,7 @@ export class ItemRenderer implements IListRenderer Date: Thu, 29 May 2025 18:37:31 -0400 Subject: [PATCH 002/236] fix patternIndices typo --- src/vs/workbench/services/search/common/getFileResults.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/services/search/common/getFileResults.ts b/src/vs/workbench/services/search/common/getFileResults.ts index 88b24b6568b..d228b748575 100644 --- a/src/vs/workbench/services/search/common/getFileResults.ts +++ b/src/vs/workbench/services/search/common/getFileResults.ts @@ -30,16 +30,16 @@ export const getFileResults = ( const results: ITextSearchResult[] = []; - const patternIndecies: { matchStartIndex: number; matchedText: string }[] = []; + const patternIndices: { matchStartIndex: number; matchedText: string }[] = []; let patternMatch: RegExpExecArray | null = null; let remainingResultQuota = options.remainingResultQuota; while (remainingResultQuota >= 0 && (patternMatch = pattern.exec(text))) { - patternIndecies.push({ matchStartIndex: patternMatch.index, matchedText: patternMatch[0] }); + patternIndices.push({ matchStartIndex: patternMatch.index, matchedText: patternMatch[0] }); remainingResultQuota--; } - if (patternIndecies.length) { + if (patternIndices.length) { const contextLinesNeeded = new Set(); const resultLines = new Set(); @@ -56,7 +56,7 @@ export const getFileResults = ( if (prevLineEnd < text.length) { lineRanges.push({ start: prevLineEnd, end: text.length }); } let startLine = 0; - for (const { matchStartIndex, matchedText } of patternIndecies) { + for (const { matchStartIndex, matchedText } of patternIndices) { if (remainingResultQuota < 0) { break; } From 5aa62531fef042fdab8e2082784a1d94a84007db Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 2 Jun 2025 08:27:53 -0700 Subject: [PATCH 003/236] Import type from xterm/headless Fixes #248589 --- .../common/capabilities/capabilities.ts | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/capabilities.ts b/src/vs/platform/terminal/common/capabilities/capabilities.ts index 505e1f8ce46..812f0730e29 100644 --- a/src/vs/platform/terminal/common/capabilities/capabilities.ts +++ b/src/vs/platform/terminal/common/capabilities/capabilities.ts @@ -4,41 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from '../../../../base/common/event.js'; -import { IDisposable } from '../../../../base/common/lifecycle.js'; import type { IPromptInputModel, ISerializedPromptInputModel } from './commandDetection/promptInputModel.js'; import { ICurrentPartialCommand } from './commandDetection/terminalCommand.js'; import { ITerminalOutputMatch, ITerminalOutputMatcher } from '../terminal.js'; import { ReplayEntry } from '../terminalProcess.js'; - -interface IEvent { - (listener: (arg1: T, arg2: U) => any): IDisposable; -} - -export interface IMarker extends IDisposable { - /** - * A unique identifier for this marker. - */ - readonly id: number; - - /** - * Whether this marker is disposed. - */ - readonly isDisposed: boolean; - - /** - * The actual line index in the buffer at this point in time. This is set to - * -1 if the marker has been disposed. - */ - readonly line: number; - - /** - * Event listener to get notified when the marker gets disposed. Automatic disposal - * might happen for a marker, that got invalidated by scrolling out or removal of - * a line from the buffer. - */ - onDispose: IEvent; -} - +import type { IMarker } from '@xterm/headless'; /** * Primarily driven by the shell integration feature, a terminal capability is the mechanism for From 83a51c46f8b416284c21a80baf9014ae9e505756 Mon Sep 17 00:00:00 2001 From: Elijah King Date: Mon, 2 Jun 2025 17:17:28 -0700 Subject: [PATCH 004/236] Commented out settings slide --- .../welcomeGettingStarted/common/gettingStartedContent.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts index 13892022e6c..12665b12f37 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts @@ -735,7 +735,9 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ type: 'svg', altText: 'Language extensions', path: 'languages.svg' }, }, - { + + // Removed settings slide from new welcome experience due to poor responses in user testing + /*{ id: 'newSettingsAndSync', title: localize('newgettingStarted.settings.title', "Customize every aspect of VS Code"), description: localize('newgettingStarted.settingsAndSync.description.interpolated', "[Back up and sync](command:workbench.userDataSync.actions.turnOn) settings across all your devices.\n{0}", Button(localize('tweakSettings', "Open Settings"), 'command:toSide:workbench.action.openSettings')), @@ -744,7 +746,8 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ media: { type: 'svg', altText: 'VS Code Settings', path: 'settings.svg' }, - }, + },*/ + ] } } From 208651076da378389d63c8cde25a60aa7de020b6 Mon Sep 17 00:00:00 2001 From: Elijah King Date: Mon, 2 Jun 2025 17:28:20 -0700 Subject: [PATCH 005/236] Progress button on last step now says 'Start coding' instead of 'Next' --- .../browser/gettingStarted.ts | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts index 8d728275a51..8526dc2df50 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts @@ -158,6 +158,7 @@ export class GettingStartedPage extends EditorPane { private categoriesSlide!: HTMLElement; private stepsContent!: HTMLElement; private stepMediaComponent!: HTMLElement; + private nextButton!: HTMLButtonElement; private webview!: IWebviewElement; private layoutMarkdown: (() => void) | undefined; @@ -1504,6 +1505,24 @@ export class GettingStartedPage extends EditorPane { prevButton.removeAttribute('tabindex'); } } + + // Update next button text for final slide + if (this.nextButton) { + const isLastSlide = newIndex === steps.length - 1; + if (isLastSlide) { + // Clear the existing content and add new text using DOM functions + clearNode(this.nextButton); + this.nextButton.appendChild(document.createTextNode(localize('startCoding', "Start coding"))); + this.nextButton.appendChild($('span.codicon.codicon-arrow-right')); + this.nextButton.setAttribute('aria-label', localize('startCodingStep', "Start coding")); + } else { + // Reset to default "Next" text using DOM functions + clearNode(this.nextButton); + this.nextButton.appendChild(document.createTextNode(localize('next', "Next"))); + this.nextButton.appendChild($('span.codicon.codicon-arrow-right')); + this.nextButton.setAttribute('aria-label', localize('nextStep', "Next")); + } + } } private buildNewCategorySlide(categoryID: string, selectedStep?: string) { @@ -1653,11 +1672,11 @@ export class GettingStartedPage extends EditorPane { }); // Add next button - const nextButton = $('button.button-link.navigation.next', { + this.nextButton = $('button.button-link.navigation.next', { 'aria-label': localize('nextStep', "Next"), }, localize('next', "Next"), $('span.codicon.codicon-arrow-right')); - navigationContainer.appendChild(nextButton); + navigationContainer.appendChild(this.nextButton); this.detailsPageDisposables.add(addDisposableListener(prevButton, 'click', () => { const currentIndex = this.getCurrentSlideIndex(allSlides); if (currentIndex > 0) { @@ -1665,7 +1684,7 @@ export class GettingStartedPage extends EditorPane { } })); - this.detailsPageDisposables.add(addDisposableListener(nextButton, 'click', () => { + this.detailsPageDisposables.add(addDisposableListener(this.nextButton, 'click', () => { const currentIndex = this.getCurrentSlideIndex(allSlides); if (currentIndex < allSlides.length - 1) { this.selectStepByIndex(currentIndex + 1, allSlides.map(s => s.steps[0]), 1); From 52f8c251940ce98c3ea83e9f3ba24dd7be61d0d0 Mon Sep 17 00:00:00 2001 From: Elijah King Date: Mon, 2 Jun 2025 17:36:26 -0700 Subject: [PATCH 006/236] Update VS Code intro walkthrough final button labels --- .../browser/gettingStarted.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts index 8526dc2df50..1dbd4068bea 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts @@ -1509,19 +1509,15 @@ export class GettingStartedPage extends EditorPane { // Update next button text for final slide if (this.nextButton) { const isLastSlide = newIndex === steps.length - 1; - if (isLastSlide) { - // Clear the existing content and add new text using DOM functions - clearNode(this.nextButton); - this.nextButton.appendChild(document.createTextNode(localize('startCoding', "Start coding"))); - this.nextButton.appendChild($('span.codicon.codicon-arrow-right')); - this.nextButton.setAttribute('aria-label', localize('startCodingStep', "Start coding")); - } else { - // Reset to default "Next" text using DOM functions - clearNode(this.nextButton); - this.nextButton.appendChild(document.createTextNode(localize('next', "Next"))); - this.nextButton.appendChild($('span.codicon.codicon-arrow-right')); - this.nextButton.setAttribute('aria-label', localize('nextStep', "Next")); + const textNode = this.nextButton.firstChild as Text; + if (textNode && textNode.nodeType === Node.TEXT_NODE) { + textNode.textContent = isLastSlide + ? localize('last', "Start coding") + : localize('next', "Next"); } + this.nextButton.setAttribute('aria-label', isLastSlide + ? localize('lastStep', "Start coding") + : localize('nextStep', "Next")); } } From 1092d26f099d1ff36cf433c27cd21367cbb88f11 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 3 Jun 2025 09:18:17 -0700 Subject: [PATCH 007/236] Update other references --- .../common/capabilities/capabilities.ts | 28 +++++++++---------- .../commandDetection/terminalCommand.ts | 16 +++++------ .../commandDetectionCapability.ts | 4 +-- .../tasks/browser/taskTerminalStatus.ts | 2 +- .../test/browser/terminalLinkOpeners.test.ts | 9 +++--- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/capabilities.ts b/src/vs/platform/terminal/common/capabilities/capabilities.ts index 812f0730e29..bb62e2ee8f0 100644 --- a/src/vs/platform/terminal/common/capabilities/capabilities.ts +++ b/src/vs/platform/terminal/common/capabilities/capabilities.ts @@ -253,8 +253,8 @@ export interface INaiveCwdDetectionCapability { export interface IPartialCommandDetectionCapability { readonly type: TerminalCapability.PartialCommandDetection; - readonly commands: readonly IXtermMarker[]; - readonly onCommandFinished: Event; + readonly commands: readonly IMarker[]; + readonly onCommandFinished: Event; } interface IBaseTerminalCommand { @@ -277,9 +277,9 @@ interface IBaseTerminalCommand { export interface ITerminalCommand extends IBaseTerminalCommand { // Optional non-serializable readonly promptStartMarker?: IMarker; - readonly marker?: IXtermMarker; - endMarker?: IXtermMarker; - readonly executedMarker?: IXtermMarker; + readonly marker?: IMarker; + endMarker?: IMarker; + readonly executedMarker?: IMarker; readonly aliases?: string[][]; readonly wasReplayed?: boolean; @@ -302,15 +302,15 @@ export interface ISerializedTerminalCommand extends IBaseTerminalCommand { /** * A clone of the IMarker from xterm which cannot be imported from common */ -export interface IXtermMarker { - readonly id: number; - readonly isDisposed: boolean; - readonly line: number; - dispose(): void; - onDispose: { - (listener: () => any): { dispose(): void }; - }; -} +// export interface IMarker { +// readonly id: number; +// readonly isDisposed: boolean; +// readonly line: number; +// dispose(): void; +// onDispose: { +// (listener: () => any): { dispose(): void }; +// }; +// } export interface IMarkProperties { hoverMessage?: string; diff --git a/src/vs/platform/terminal/common/capabilities/commandDetection/terminalCommand.ts b/src/vs/platform/terminal/common/capabilities/commandDetection/terminalCommand.ts index fc8c7655d5e..ecc7f984d5c 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetection/terminalCommand.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetection/terminalCommand.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IMarkProperties, IMarker, ISerializedTerminalCommand, ITerminalCommand, IXtermMarker } from '../capabilities.js'; +import { IMarkProperties, ISerializedTerminalCommand, ITerminalCommand } from '../capabilities.js'; import { ITerminalOutputMatcher, ITerminalOutputMatch } from '../../terminal.js'; -import type { IBuffer, IBufferLine, Terminal } from '@xterm/headless'; +import type { IBuffer, IBufferLine, IMarker, Terminal } from '@xterm/headless'; export interface ITerminalCommandProperties { command: string; @@ -13,7 +13,7 @@ export interface ITerminalCommandProperties { isTrusted: boolean; timestamp: number; duration: number; - marker: IXtermMarker | undefined; + marker: IMarker | undefined; cwd: string | undefined; exitCode: number | undefined; commandStartLineContent: string | undefined; @@ -22,8 +22,8 @@ export interface ITerminalCommandProperties { startX: number | undefined; promptStartMarker?: IMarker | undefined; - endMarker?: IXtermMarker | undefined; - executedMarker?: IXtermMarker | undefined; + endMarker?: IMarker | undefined; + executedMarker?: IMarker | undefined; aliases?: string[][] | undefined; wasReplayed?: boolean | undefined; } @@ -38,7 +38,7 @@ export class TerminalCommand implements ITerminalCommand { get promptStartMarker() { return this._properties.promptStartMarker; } get marker() { return this._properties.marker; } get endMarker() { return this._properties.endMarker; } - set endMarker(value: IXtermMarker | undefined) { this._properties.endMarker = value; } + set endMarker(value: IMarker | undefined) { this._properties.endMarker = value; } get executedMarker() { return this._properties.executedMarker; } get aliases() { return this._properties.aliases; } get wasReplayed() { return this._properties.wasReplayed; } @@ -361,9 +361,9 @@ export class PartialTerminalCommand implements ICurrentPartialCommand { function extractCommandLine( buffer: IBuffer, cols: number, - commandStartMarker: IXtermMarker | undefined, + commandStartMarker: IMarker | undefined, commandStartX: number | undefined, - commandExecutedMarker: IXtermMarker | undefined, + commandExecutedMarker: IMarker | undefined, commandExecutedX: number | undefined ): string { if (!commandStartMarker || !commandExecutedMarker || commandStartX === undefined || commandExecutedX === undefined) { diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 02415e9a3c3..a68f0487ebe 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -8,7 +8,7 @@ import { debounce } from '../../../../base/common/decorators.js'; import { Emitter } from '../../../../base/common/event.js'; import { Disposable, MandatoryMutableDisposable, MutableDisposable } from '../../../../base/common/lifecycle.js'; import { ILogService } from '../../../log/common/log.js'; -import { CommandInvalidationReason, ICommandDetectionCapability, ICommandInvalidationRequest, IHandleCommandOptions, ISerializedCommandDetectionCapability, ISerializedTerminalCommand, ITerminalCommand, IXtermMarker, TerminalCapability } from './capabilities.js'; +import { CommandInvalidationReason, ICommandDetectionCapability, ICommandInvalidationRequest, IHandleCommandOptions, ISerializedCommandDetectionCapability, ISerializedTerminalCommand, ITerminalCommand, TerminalCapability } from './capabilities.js'; import { ITerminalOutputMatcher } from '../terminal.js'; import { ICurrentPartialCommand, PartialTerminalCommand, TerminalCommand } from './commandDetection/terminalCommand.js'; import { PromptInputModel, type IPromptInputModel } from './commandDetection/promptInputModel.js'; @@ -1047,6 +1047,6 @@ function getXtermLineContent(buffer: IBuffer, lineStart: number, lineEnd: number return content; } -function cloneMarker(xterm: Terminal, marker: IXtermMarker, offset: number = 0): IXtermMarker | undefined { +function cloneMarker(xterm: Terminal, marker: IMarker, offset: number = 0): IMarker | undefined { return xterm.registerMarker(marker.line - (xterm.buffer.active.baseY + xterm.buffer.active.cursorY) + offset); } diff --git a/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts b/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts index 4e8404b1a55..528341bae74 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts @@ -13,7 +13,7 @@ import { ITaskService, Task } from '../common/taskService.js'; import { ITerminalInstance } from '../../terminal/browser/terminal.js'; import { MarkerSeverity } from '../../../../platform/markers/common/markers.js'; import { spinningLoading } from '../../../../platform/theme/common/iconRegistry.js'; -import { IMarker } from '../../../../platform/terminal/common/capabilities/capabilities.js'; +import type { IMarker } from '@xterm/xterm'; import { AccessibilitySignal, IAccessibilitySignalService } from '../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js'; import { ITerminalStatus } from '../../terminal/common/terminal.js'; diff --git a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts index d2e7a0ee776..4305d050846 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts @@ -17,7 +17,7 @@ import { IWorkspaceContextService } from '../../../../../../platform/workspace/c import { CommandDetectionCapability } from '../../../../../../platform/terminal/common/capabilities/commandDetectionCapability.js'; import { TerminalBuiltinLinkType } from '../../browser/links.js'; import { TerminalLocalFileLinkOpener, TerminalLocalFolderInWorkspaceLinkOpener, TerminalSearchLinkOpener } from '../../browser/terminalLinkOpeners.js'; -import { TerminalCapability, IXtermMarker } from '../../../../../../platform/terminal/common/capabilities/capabilities.js'; +import { TerminalCapability } from '../../../../../../platform/terminal/common/capabilities/capabilities.js'; import { TerminalCapabilityStore } from '../../../../../../platform/terminal/common/capabilities/terminalCapabilityStore.js'; import { IEditorService } from '../../../../../services/editor/common/editorService.js'; import { IWorkbenchEnvironmentService } from '../../../../../services/environment/common/environmentService.js'; @@ -29,6 +29,7 @@ import { ITerminalLogService } from '../../../../../../platform/terminal/common/ import { importAMDNodeModule } from '../../../../../../amdX.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; import { TerminalCommand } from '../../../../../../platform/terminal/common/capabilities/commandDetection/terminalCommand.js'; +import type { IMarker } from '@xterm/headless'; interface ITerminalLinkActivationResult { source: 'editor' | 'search'; @@ -148,7 +149,7 @@ suite('Workbench - TerminalLinkOpeners', () => { startX: undefined, marker: { line: 0 - } as Partial as any, + } as Partial as any, })]); fileService.setFiles([ URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo/bar.txt' }), @@ -287,7 +288,7 @@ suite('Workbench - TerminalLinkOpeners', () => { startX: undefined, marker: { line: 0 - } as Partial as any, + } as Partial as any, exitCode: 0, commandStartLineContent: '', markProperties: {} @@ -549,7 +550,7 @@ suite('Workbench - TerminalLinkOpeners', () => { duration: 0, marker: { line: 0 - } as Partial as any, + } as Partial as any, })]); await opener.open({ text: 'file.txt', From d3cd9007770d6b3f0c1f814fed92f24f49296150 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 19:55:40 +0000 Subject: [PATCH 008/236] Initial plan for issue From caeaf6f10018a1f185d1ac0d0c5ed25052e3907c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 19:56:52 +0000 Subject: [PATCH 009/236] Initial plan for issue From 340c1bbd2471bb6ea9272dbe01481bc255aa710e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 20:05:04 +0000 Subject: [PATCH 010/236] Enhance SendSequence command to support manual input and escape sequences Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../terminal/browser/terminalActions.ts | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ff14b2b4af7..15810e8fbd4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -121,20 +121,48 @@ export async function getCwdForSplit( } export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { - const instance = accessor.get(ITerminalService).activeInstance; - if (instance) { - const text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; + const terminalService = accessor.get(ITerminalService); + const instance = terminalService.activeInstance || await terminalService.getActiveOrCreateInstance(); + if (!instance) { + return; + } + + let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; + + // If no text provided, prompt user for input + if (!text) { + const quickInputService = accessor.get(IQuickInputService); + text = await quickInputService.input({ + value: '', + placeHolder: 'Enter sequence to send (supports \\n, \\r, \\x escape sequences)', + prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), + }); if (!text) { return; } - const configurationResolverService = accessor.get(IConfigurationResolverService); - const workspaceContextService = accessor.get(IWorkspaceContextService); - const historyService = accessor.get(IHistoryService); - const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); - const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; - const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); - instance.sendText(resolvedText, false); } + + // Process escape sequences similar to WriteDataToTerminal + let processedText = text + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r'); + + // Process hex escape sequences (\xNN) + while (true) { + const match = processedText.match(/\\x([0-9a-fA-F]{2})/); + if (match === null || match.index === undefined || match.length < 2) { + break; + } + processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); + } + + const configurationResolverService = accessor.get(IConfigurationResolverService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const historyService = accessor.get(IHistoryService); + const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); + const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; + const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, processedText); + instance.sendText(resolvedText, false); }; export class TerminalLaunchHelpAction extends Action { @@ -957,14 +985,13 @@ export function registerTerminalActions() { registerTerminalAction({ id: TerminalCommandId.SendSequence, title: terminalStrings.sendSequence, - f1: false, + f1: true, metadata: { description: terminalStrings.sendSequence.value, args: [{ name: 'args', schema: { type: 'object', - required: ['text'], properties: { text: { description: localize('sendSequence', "The sequence of text to send to the terminal"), From ecad1e37cdf48221e957e2f15e2db41d83e8c116 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 20:18:39 +0000 Subject: [PATCH 011/236] Implement workbench.action.terminal.sendSignal command Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- src/vs/platform/terminal/common/terminal.ts | 2 ++ src/vs/platform/terminal/node/ptyService.ts | 4 +++ .../platform/terminal/node/terminalProcess.ts | 7 ++++ src/vs/server/node/remoteTerminalChannel.ts | 1 + .../api/common/extHostTerminalService.ts | 5 +++ .../contrib/terminal/browser/terminal.ts | 7 ++++ .../terminal/browser/terminalActions.ts | 34 +++++++++++++++++++ .../terminal/browser/terminalInstance.ts | 5 +++ .../browser/terminalProcessManager.ts | 7 ++++ .../common/remote/remoteTerminalChannel.ts | 3 ++ .../terminal/common/remote/terminal.ts | 1 + .../contrib/terminal/common/terminal.ts | 2 ++ .../terminal/common/terminalStrings.ts | 1 + .../test/browser/terminalInstance.test.ts | 1 + .../browser/terminalProcessManager.test.ts | 1 + 15 files changed, 81 insertions(+) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 6fe56bbae05..d68d8ccd967 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -331,6 +331,7 @@ export interface IPtyService { start(id: number): Promise; shutdown(id: number, immediate: boolean): Promise; input(id: number, data: string): Promise; + sendSignal(id: number, signal: string): Promise; resize(id: number, cols: number, rows: number): Promise; clearBuffer(id: number): Promise; getInitialCwd(id: number): Promise; @@ -791,6 +792,7 @@ export interface ITerminalChildProcess { */ shutdown(immediate: boolean): void; input(data: string): void; + sendSignal(signal: string): void; processBinary(data: string): Promise; resize(cols: number, rows: number): void; clearBuffer(): void | Promise; diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 37daa894dff..6cfe6e5a376 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -422,6 +422,10 @@ export class PtyService extends Disposable implements IPtyService { } } @traceRpc + async sendSignal(id: number, signal: string): Promise { + return this._throwIfNoPty(id).sendSignal(signal); + } + @traceRpc async processBinary(id: number, data: string): Promise { return this._throwIfNoPty(id).writeBinary(data); } diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index e662ddbf8af..d152108e265 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -481,6 +481,13 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess this._startWrite(); } + sendSignal(signal: string): void { + if (this._store.isDisposed || !this._ptyProcess) { + return; + } + this._ptyProcess.kill(signal); + } + async processBinary(data: string): Promise { this.input(data, true); } diff --git a/src/vs/server/node/remoteTerminalChannel.ts b/src/vs/server/node/remoteTerminalChannel.ts index 325e8db1c51..1cb1e36c5f0 100644 --- a/src/vs/server/node/remoteTerminalChannel.ts +++ b/src/vs/server/node/remoteTerminalChannel.ts @@ -128,6 +128,7 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel< case RemoteTerminalChannelRequest.Start: return this._ptyHostService.start.apply(this._ptyHostService, args); case RemoteTerminalChannelRequest.Input: return this._ptyHostService.input.apply(this._ptyHostService, args); + case RemoteTerminalChannelRequest.SendSignal: return this._ptyHostService.sendSignal.apply(this._ptyHostService, args); case RemoteTerminalChannelRequest.AcknowledgeDataEvent: return this._ptyHostService.acknowledgeDataEvent.apply(this._ptyHostService, args); case RemoteTerminalChannelRequest.Shutdown: return this._ptyHostService.shutdown.apply(this._ptyHostService, args); case RemoteTerminalChannelRequest.Resize: return this._ptyHostService.resize.apply(this._ptyHostService, args); diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 693cb1728a4..ab06ab814df 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -334,6 +334,11 @@ class ExtHostPseudoterminal implements ITerminalChildProcess { this._pty.handleInput?.(data); } + sendSignal(signal: string): void { + // Extension owned terminals don't support sending signals directly to processes + // This could be extended in the future if the pseudoterminal API is enhanced + } + resize(cols: number, rows: number): void { this._pty.setDimensions?.({ columns: cols, rows }); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 2059d0d68b1..1e49bb74ca9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -899,6 +899,13 @@ export interface ITerminalInstance extends IBaseTerminalInstance { */ sendText(text: string, shouldExecute: boolean, bracketedPasteMode?: boolean): Promise; + /** + * Sends a signal to the terminal instance's process. + * + * @param signal The signal to send (e.g., 'SIGTERM', 'SIGINT', 'SIGKILL'). + */ + sendSignal(signal: string): Promise; + /** * Sends a path to the terminal instance, preparing it as needed based on the detected shell * running within the terminal. The text is written to the stdin of the underlying pty process diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ff14b2b4af7..270749e69ec 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -137,6 +137,17 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar } }; +export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => { + const instance = accessor.get(ITerminalService).activeInstance; + if (instance) { + const signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; + if (!signal) { + return; + } + instance.sendSignal(signal); + } +}; + export class TerminalLaunchHelpAction extends Action { constructor( @@ -977,6 +988,29 @@ export function registerTerminalActions() { run: (c, accessor, args) => terminalSendSequenceCommand(accessor, args) }); + registerTerminalAction({ + id: TerminalCommandId.SendSignal, + title: terminalStrings.sendSignal, + f1: false, + metadata: { + description: terminalStrings.sendSignal.value, + args: [{ + name: 'args', + schema: { + type: 'object', + required: ['signal'], + properties: { + signal: { + description: localize('sendSignal', "The signal to send to the terminal process (e.g., 'SIGTERM', 'SIGINT', 'SIGKILL')"), + type: 'string' + } + }, + } + }] + }, + run: (c, accessor, args) => terminalSendSignalCommand(accessor, args) + }); + registerTerminalAction({ id: TerminalCommandId.NewWithCwd, title: terminalStrings.newWithCwd, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 1604e60b785..71c26874ab3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1321,6 +1321,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } + async sendSignal(signal: string): Promise { + this._logService.debug('sending signal (vscode)', signal); + await this._processManager.sendSignal(signal); + } + async sendPath(originalPath: string | URI, shouldExecute: boolean): Promise { return this.sendText(await this.preparePathForShell(originalPath), shouldExecute); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 535c7ad5562..8bba0827b1f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -609,6 +609,13 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce } } + async sendSignal(signal: string): Promise { + await this.ptyProcessReady; + if (this._process) { + this._process.sendSignal(signal); + } + } + async processBinary(data: string): Promise { await this.ptyProcessReady; this._dataFilter.disableSeamlessRelaunch(); diff --git a/src/vs/workbench/contrib/terminal/common/remote/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remote/remoteTerminalChannel.ts index 5aeedf779f7..532d9f1c1ce 100644 --- a/src/vs/workbench/contrib/terminal/common/remote/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remote/remoteTerminalChannel.ts @@ -216,6 +216,9 @@ export class RemoteTerminalChannelClient implements IPtyHostController { input(id: number, data: string): Promise { return this._channel.call(RemoteTerminalChannelRequest.Input, [id, data]); } + sendSignal(id: number, signal: string): Promise { + return this._channel.call(RemoteTerminalChannelRequest.SendSignal, [id, signal]); + } acknowledgeDataEvent(id: number, charCount: number): Promise { return this._channel.call(RemoteTerminalChannelRequest.AcknowledgeDataEvent, [id, charCount]); } diff --git a/src/vs/workbench/contrib/terminal/common/remote/terminal.ts b/src/vs/workbench/contrib/terminal/common/remote/terminal.ts index 5e649e86a51..16af3dcf8b8 100644 --- a/src/vs/workbench/contrib/terminal/common/remote/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/remote/terminal.ts @@ -69,6 +69,7 @@ export const enum RemoteTerminalChannelRequest { AcceptPtyHostResolvedVariables = '$acceptPtyHostResolvedVariables', Start = '$start', Input = '$input', + SendSignal = '$sendSignal', AcknowledgeDataEvent = '$acknowledgeDataEvent', Shutdown = '$shutdown', Resize = '$resize', diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 3683a60a46b..6951d80a2bd 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -296,6 +296,7 @@ export interface ITerminalProcessManager extends IDisposable, ITerminalProcessIn createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): Promise; relaunch(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number, reset: boolean): Promise; write(data: string): Promise; + sendSignal(signal: string): Promise; setDimensions(cols: number, rows: number): Promise; setDimensions(cols: number, rows: number, sync: false): Promise; setDimensions(cols: number, rows: number, sync: true): void; @@ -473,6 +474,7 @@ export const enum TerminalCommandId { SelectToPreviousLine = 'workbench.action.terminal.selectToPreviousLine', SelectToNextLine = 'workbench.action.terminal.selectToNextLine', SendSequence = 'workbench.action.terminal.sendSequence', + SendSignal = 'workbench.action.terminal.sendSignal', AttachToSession = 'workbench.action.terminal.attachToSession', DetachSession = 'workbench.action.terminal.detachSession', MoveToEditor = 'workbench.action.terminal.moveToEditor', diff --git a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts index ed00de1f363..523610339f9 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts @@ -37,6 +37,7 @@ export const terminalStrings = { toggleSizeToContentWidth: localize2('workbench.action.terminal.sizeToContentWidthInstance', "Toggle Size to Content Width"), focusHover: localize2('workbench.action.terminal.focusHover', "Focus Hover"), sendSequence: localize2('workbench.action.terminal.sendSequence', "Send Custom Sequence to Terminal"), + sendSignal: localize2('workbench.action.terminal.sendSignal', "Send Signal to Terminal"), newWithCwd: localize2('workbench.action.terminal.newWithCwd', "Create New Terminal Starting in a Custom Working Directory"), renameWithArgs: localize2('workbench.action.terminal.renameWithArg', "Rename the Currently Active Terminal"), scrollToPreviousCommand: localize2('workbench.action.terminal.scrollToPreviousCommand', "Scroll to Previous Command"), diff --git a/src/vs/workbench/contrib/terminal/test/browser/terminalInstance.test.ts b/src/vs/workbench/contrib/terminal/test/browser/terminalInstance.test.ts index 5a8f8cddbdc..11a0f0cec68 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/terminalInstance.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/terminalInstance.test.ts @@ -83,6 +83,7 @@ class TestTerminalChildProcess extends Disposable implements ITerminalChildProce async start(): Promise { return undefined; } shutdown(immediate: boolean): void { } input(data: string): void { } + sendSignal(signal: string): void { } resize(cols: number, rows: number): void { } clearBuffer(): void { } acknowledgeDataEvent(charCount: number): void { } diff --git a/src/vs/workbench/contrib/terminal/test/browser/terminalProcessManager.test.ts b/src/vs/workbench/contrib/terminal/test/browser/terminalProcessManager.test.ts index 85af56a0c6e..ec63876cd46 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/terminalProcessManager.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/terminalProcessManager.test.ts @@ -39,6 +39,7 @@ class TestTerminalChildProcess implements ITerminalChildProcess { async start(): Promise { return undefined; } shutdown(immediate: boolean): void { } input(data: string): void { } + sendSignal(signal: string): void { } resize(cols: number, rows: number): void { } clearBuffer(): void { } acknowledgeDataEvent(charCount: number): void { } From 00fabee4de8c10e1145338b6af59d857ce8d258e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 20:26:44 +0000 Subject: [PATCH 012/236] Remove redundant writeDataToTerminal command Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../terminal.developer.contribution.ts | 35 ------------------- .../developer/common/terminal.developer.ts | 1 - 2 files changed, 36 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts index 067736bd947..51cc3da5222 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts @@ -61,41 +61,6 @@ registerTerminalAction({ } }); -registerTerminalAction({ - id: TerminalDeveloperCommandId.WriteDataToTerminal, - title: localize2('workbench.action.terminal.writeDataToTerminal', 'Write Data to Terminal'), - category: Categories.Developer, - run: async (c, accessor) => { - const quickInputService = accessor.get(IQuickInputService); - const instance = await c.service.getActiveOrCreateInstance(); - await c.service.revealActiveTerminal(); - await instance.processReady; - if (!instance.xterm) { - throw new Error('Cannot write data to terminal if xterm isn\'t initialized'); - } - const data = await quickInputService.input({ - value: '', - placeHolder: 'Enter data, use \\x to escape', - prompt: localize('workbench.action.terminal.writeDataToTerminal.prompt', "Enter data to write directly to the terminal, bypassing the pty"), - }); - if (!data) { - return; - } - let escapedData = data - .replace(/\\n/g, '\n') - .replace(/\\r/g, '\r'); - while (true) { - const match = escapedData.match(/\\x([0-9a-fA-F]{2})/); - if (match === null || match.index === undefined || match.length < 2) { - break; - } - escapedData = escapedData.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + escapedData.slice(match.index + 4); - } - const xterm = instance.xterm as any as IInternalXtermTerminal; - xterm._writeText(escapedData); - } -}); - registerTerminalAction({ id: TerminalDeveloperCommandId.RecordSession, title: localize2('workbench.action.terminal.recordSession', 'Record Terminal Session'), diff --git a/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts b/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts index a502cc23d9e..62afd2f42ed 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ export const enum TerminalDeveloperCommandId { - WriteDataToTerminal = 'workbench.action.terminal.writeDataToTerminal', RecordSession = 'workbench.action.terminal.recordSession', ShowTextureAtlas = 'workbench.action.terminal.showTextureAtlas', RestartPtyHost = 'workbench.action.terminal.restartPtyHost', From 2ffd5935783a11d58a243b647e62df6854fe9936 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 23:01:02 +0000 Subject: [PATCH 013/236] Initial plan for issue From 2e9cf53c612da09fb3b1cd81fdc8c3ba0d64c886 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 23:09:53 +0000 Subject: [PATCH 014/236] Boost main and master branches in terminal suggest completions Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../src/completions/upstream/git.ts | 6 +- .../completions/upstream/git-branches.test.ts | 78 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts diff --git a/extensions/terminal-suggest/src/completions/upstream/git.ts b/extensions/terminal-suggest/src/completions/upstream/git.ts index 56468610acc..aab9300e186 100644 --- a/extensions/terminal-suggest/src/completions/upstream/git.ts +++ b/extensions/terminal-suggest/src/completions/upstream/git.ts @@ -100,11 +100,15 @@ const postProcessBranches = name = name.slice(0, space); } + // Boost main and master branches to the top + const isMainOrMaster = name === "main" || name === "master"; + const priority = isMainOrMaster ? 76 : 75; + return { name, description, icon: "fig://icon?type=git", - priority: 75, + priority, }; }) .filter((suggestion) => { diff --git a/extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts b/extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts new file mode 100644 index 00000000000..335efe43b52 --- /dev/null +++ b/extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'mocha'; +import * as assert from 'assert'; +import { gitGenerators } from '../../../completions/upstream/git'; + +suite('Git Branch Priority Tests', () => { + test('postProcessBranches should boost main and master branches', () => { + const mockBranchOutput = ` feature-branch + main + master + development + another-feature`; + + const result = gitGenerators.remoteLocalBranches.postProcess!(mockBranchOutput, []); + + // Find main and master branches + const mainBranch = result.find((suggestion: any) => suggestion.name === 'main'); + const masterBranch = result.find((suggestion: any) => suggestion.name === 'master'); + const otherBranches = result.filter((suggestion: any) => + suggestion.name !== 'main' && suggestion.name !== 'master' + ); + + // Verify main and master have higher priority (76) + assert.strictEqual(mainBranch?.priority, 76, 'main branch should have priority 76'); + assert.strictEqual(masterBranch?.priority, 76, 'master branch should have priority 76'); + + // Verify other branches have default priority (75) + otherBranches.forEach((branch: any) => { + assert.strictEqual(branch.priority, 75, `${branch.name} should have priority 75`); + }); + }); + + test('postProcessBranches should handle remote branches with main/master', () => { + const mockRemoteBranchOutput = ` remotes/origin/feature-branch + remotes/origin/main + remotes/origin/master + remotes/origin/development`; + + const result = gitGenerators.remoteLocalBranches.postProcess!(mockRemoteBranchOutput, []); + + // Find main and master branches (names should be stripped of remotes/ prefix) + const mainBranch = result.find((suggestion: any) => suggestion.name === 'main'); + const masterBranch = result.find((suggestion: any) => suggestion.name === 'master'); + + // Verify main and master have higher priority (76) + assert.strictEqual(mainBranch?.priority, 76, 'remote main branch should have priority 76'); + assert.strictEqual(masterBranch?.priority, 76, 'remote master branch should have priority 76'); + + // Verify they have remote branch description + assert.strictEqual(mainBranch?.description, 'Remote branch', 'main should be marked as remote branch'); + assert.strictEqual(masterBranch?.description, 'Remote branch', 'master should be marked as remote branch'); + }); + + test('postProcessBranches should still prioritize current branch above main/master', () => { + const mockBranchOutputWithCurrent = `* current-branch + main + master + feature-branch`; + + const result = gitGenerators.remoteLocalBranches.postProcess!(mockBranchOutputWithCurrent, []); + + // Find current, main and master branches + const currentBranch = result.find((suggestion: any) => suggestion.name === 'current-branch'); + const mainBranch = result.find((suggestion: any) => suggestion.name === 'main'); + const masterBranch = result.find((suggestion: any) => suggestion.name === 'master'); + + // Verify current branch has highest priority (100) + assert.strictEqual(currentBranch?.priority, 100, 'current branch should have priority 100'); + + // Verify main and master have medium priority (76) + assert.strictEqual(mainBranch?.priority, 76, 'main branch should have priority 76'); + assert.strictEqual(masterBranch?.priority, 76, 'master branch should have priority 76'); + }); +}); \ No newline at end of file From 98439099adf121d5583466f1f07128b3e46726eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Jun 2025 23:23:25 +0000 Subject: [PATCH 015/236] Implement git branch prioritization in compareCompletionsFn - Revert changes to upstream/git.ts per feedback - Add git branch boosting logic to terminalCompletionModel.ts compareCompletionsFn - Boost main and master branches for git commands from terminal-suggest provider - Add comprehensive test suite for git branch priority sorting - Follows same pattern as existing LSP provider boost logic Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../src/completions/upstream/git.ts | 6 +- .../completions/upstream/git-branches.test.ts | 78 ------------------- .../browser/terminalCompletionModel.ts | 17 ++++ .../browser/terminalCompletionModel.test.ts | 68 ++++++++++++++++ 4 files changed, 86 insertions(+), 83 deletions(-) delete mode 100644 extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts diff --git a/extensions/terminal-suggest/src/completions/upstream/git.ts b/extensions/terminal-suggest/src/completions/upstream/git.ts index aab9300e186..56468610acc 100644 --- a/extensions/terminal-suggest/src/completions/upstream/git.ts +++ b/extensions/terminal-suggest/src/completions/upstream/git.ts @@ -100,15 +100,11 @@ const postProcessBranches = name = name.slice(0, space); } - // Boost main and master branches to the top - const isMainOrMaster = name === "main" || name === "master"; - const priority = isMainOrMaster ? 76 : 75; - return { name, description, icon: "fig://icon?type=git", - priority, + priority: 75, }; }) .filter((suggestion) => { diff --git a/extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts b/extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts deleted file mode 100644 index 335efe43b52..00000000000 --- a/extensions/terminal-suggest/src/test/completions/upstream/git-branches.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import 'mocha'; -import * as assert from 'assert'; -import { gitGenerators } from '../../../completions/upstream/git'; - -suite('Git Branch Priority Tests', () => { - test('postProcessBranches should boost main and master branches', () => { - const mockBranchOutput = ` feature-branch - main - master - development - another-feature`; - - const result = gitGenerators.remoteLocalBranches.postProcess!(mockBranchOutput, []); - - // Find main and master branches - const mainBranch = result.find((suggestion: any) => suggestion.name === 'main'); - const masterBranch = result.find((suggestion: any) => suggestion.name === 'master'); - const otherBranches = result.filter((suggestion: any) => - suggestion.name !== 'main' && suggestion.name !== 'master' - ); - - // Verify main and master have higher priority (76) - assert.strictEqual(mainBranch?.priority, 76, 'main branch should have priority 76'); - assert.strictEqual(masterBranch?.priority, 76, 'master branch should have priority 76'); - - // Verify other branches have default priority (75) - otherBranches.forEach((branch: any) => { - assert.strictEqual(branch.priority, 75, `${branch.name} should have priority 75`); - }); - }); - - test('postProcessBranches should handle remote branches with main/master', () => { - const mockRemoteBranchOutput = ` remotes/origin/feature-branch - remotes/origin/main - remotes/origin/master - remotes/origin/development`; - - const result = gitGenerators.remoteLocalBranches.postProcess!(mockRemoteBranchOutput, []); - - // Find main and master branches (names should be stripped of remotes/ prefix) - const mainBranch = result.find((suggestion: any) => suggestion.name === 'main'); - const masterBranch = result.find((suggestion: any) => suggestion.name === 'master'); - - // Verify main and master have higher priority (76) - assert.strictEqual(mainBranch?.priority, 76, 'remote main branch should have priority 76'); - assert.strictEqual(masterBranch?.priority, 76, 'remote master branch should have priority 76'); - - // Verify they have remote branch description - assert.strictEqual(mainBranch?.description, 'Remote branch', 'main should be marked as remote branch'); - assert.strictEqual(masterBranch?.description, 'Remote branch', 'master should be marked as remote branch'); - }); - - test('postProcessBranches should still prioritize current branch above main/master', () => { - const mockBranchOutputWithCurrent = `* current-branch - main - master - feature-branch`; - - const result = gitGenerators.remoteLocalBranches.postProcess!(mockBranchOutputWithCurrent, []); - - // Find current, main and master branches - const currentBranch = result.find((suggestion: any) => suggestion.name === 'current-branch'); - const mainBranch = result.find((suggestion: any) => suggestion.name === 'main'); - const masterBranch = result.find((suggestion: any) => suggestion.name === 'master'); - - // Verify current branch has highest priority (100) - assert.strictEqual(currentBranch?.priority, 100, 'current branch should have priority 100'); - - // Verify main and master have medium priority (76) - assert.strictEqual(mainBranch?.priority, 76, 'main branch should have priority 76'); - assert.strictEqual(masterBranch?.priority, 76, 'master branch should have priority 76'); - }); -}); \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index 82c086f4e82..6a0e7709fbb 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -38,6 +38,23 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI return 1; } + // Boost main and master branches for git commands + const terminalSuggestProviderId = 'terminal-suggest'; + const isGitCommand = /^\s*git\b/.test(leadingLineContent); + if (isGitCommand && a.completion.provider === terminalSuggestProviderId && b.completion.provider === terminalSuggestProviderId) { + const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; + const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; + const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; + const bIsMainOrMaster = bLabel === 'main' || bLabel === 'master'; + + if (aIsMainOrMaster && !bIsMainOrMaster) { + return -1; + } + if (bIsMainOrMaster && !aIsMainOrMaster) { + return 1; + } + } + // Sort by the score let score = b.score[0] - a.score[0]; if (score !== 0) { diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts index 3a46093bb72..2bb8187ca7e 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts @@ -296,4 +296,72 @@ suite('TerminalCompletionModel', function () { }); + + suite('git branch priority sorting', () => { + test('should prioritize main and master branches for git commands', () => { + const items = [ + createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), + createItem({ label: 'master', provider: 'terminal-suggest' }), + createItem({ label: 'development', provider: 'terminal-suggest' }), + createItem({ label: 'main', provider: 'terminal-suggest' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); + assertItems(model, ['main', 'master', 'development', 'feature-branch']); + }); + + test('should prioritize main and master branches for git switch command', () => { + const items = [ + createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), + createItem({ label: 'main', provider: 'terminal-suggest' }), + createItem({ label: 'another-feature', provider: 'terminal-suggest' }), + createItem({ label: 'master', provider: 'terminal-suggest' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext('git switch ', 0)); + assertItems(model, ['main', 'master', 'another-feature', 'feature-branch']); + }); + + test('should not prioritize main and master for non-git commands', () => { + const items = [ + createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), + createItem({ label: 'master', provider: 'terminal-suggest' }), + createItem({ label: 'main', provider: 'terminal-suggest' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext('ls ', 0)); + assertItems(model, ['feature-branch', 'main', 'master']); + }); + + test('should only apply to terminal-suggest provider', () => { + const items = [ + createItem({ label: 'feature-branch', provider: 'other-provider' }), + createItem({ label: 'master', provider: 'other-provider' }), + createItem({ label: 'main', provider: 'other-provider' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); + assertItems(model, ['feature-branch', 'main', 'master']); + }); + + test('should handle git commands with leading whitespace', () => { + const items = [ + createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), + createItem({ label: 'master', provider: 'terminal-suggest' }), + createItem({ label: 'main', provider: 'terminal-suggest' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext(' git checkout ', 0)); + assertItems(model, ['main', 'master', 'feature-branch']); + }); + + test('should work with complex label objects', () => { + const items = [ + createItem({ label: { label: 'feature-branch', description: 'Feature branch' }, provider: 'terminal-suggest' }), + createItem({ label: { label: 'master', description: 'Master branch' }, provider: 'terminal-suggest' }), + createItem({ label: { label: 'main', description: 'Main branch' }, provider: 'terminal-suggest' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); + assertItems(model, [ + { label: 'main', description: 'Main branch' }, + { label: 'master', description: 'Master branch' }, + { label: 'feature-branch', description: 'Feature branch' } + ]); + }); + }); }); From 0ad9e22f5538f5159a83d382f1fa1effe7f855f3 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 5 Jun 2025 11:51:41 +0200 Subject: [PATCH 016/236] polsih fileLocator.createFilesUpdatedEvent --- .../promptSyntax/service/promptsService.ts | 2 +- .../promptSyntax/utils/promptFilesLocator.ts | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 1983df48d2d..43725ac6e07 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -106,7 +106,7 @@ export class PromptsService extends Disposable implements IPromptsService { */ public get onDidChangeCustomChatModes(): Event { if (!this.onDidChangeCustomChatModesEvent) { - this.onDidChangeCustomChatModesEvent = this.fileLocator.getFilesUpdatedEvent(PromptsType.mode); + this.onDidChangeCustomChatModesEvent = this._register(this.fileLocator.createFilesUpdatedEvent(PromptsType.mode)).event; } return this.onDidChangeCustomChatModesEvent; } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts index 5b7fd6f431c..e319d2dce02 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts @@ -21,7 +21,7 @@ import { isCancellationError } from '../../../../../../base/common/errors.js'; import { TPromptsStorage } from '../service/types.js'; import { IUserDataProfileService } from '../../../../../services/userDataProfile/common/userDataProfile.js'; import { Emitter, Event } from '../../../../../../base/common/event.js'; -import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore } from '../../../../../../base/common/lifecycle.js'; /** * Utility class to locate prompt files. @@ -57,18 +57,21 @@ export class PromptFilesLocator extends Disposable { return files.filter(file => getPromptFileType(file) === type); } - public getFilesUpdatedEvent(type: PromptsType): Event { - const eventEmitter = this._register(new Emitter()); + public createFilesUpdatedEvent(type: PromptsType): { readonly event: Event; dispose: () => void } { + const disoposables = new DisposableStore(); + const eventEmitter = disoposables.add(new Emitter()); const key = getPromptFileLocationsConfigKey(type); + const userDataFolder = this.userDataService.currentProfile.promptsHome; + let parentFolders = this.getLocalParentFolders(type).map(folder => folder.parent); - this._register(this.configService.onDidChangeConfiguration(e => { + disoposables.add(this.configService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(key)) { parentFolders = this.getLocalParentFolders(type).map(folder => folder.parent); eventEmitter.fire(); } })); - this._register(this.fileService.onDidFilesChange(e => { - if (e.affects(this.userDataService.currentProfile.promptsHome)) { + disoposables.add(this.fileService.onDidFilesChange(e => { + if (e.contains(userDataFolder)) { eventEmitter.fire(); return; } @@ -77,7 +80,8 @@ export class PromptFilesLocator extends Disposable { return; } })); - return eventEmitter.event; + disoposables.add(this.fileService.watch(userDataFolder)); + return { event: eventEmitter.event, dispose: () => disoposables.dispose() }; } /** From 9ea637c9a8520239dd7af68df31404ceb5ce292e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:30:02 +0000 Subject: [PATCH 017/236] Initial plan for issue From 1843a3cc16fe5333bad8ad09969dbbd786ff4399 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:32:57 +0000 Subject: [PATCH 018/236] Optimize compareCompletionsFn for better JIT performance Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../suggest/browser/terminalCompletionModel.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index 6a0e7709fbb..5da566f2740 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -39,9 +39,7 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI } // Boost main and master branches for git commands - const terminalSuggestProviderId = 'terminal-suggest'; - const isGitCommand = /^\s*git\b/.test(leadingLineContent); - if (isGitCommand && a.completion.provider === terminalSuggestProviderId && b.completion.provider === terminalSuggestProviderId) { + if (/^\s*git\b/.test(leadingLineContent) && a.completion.provider === 'terminal-suggest' && b.completion.provider === 'terminal-suggest') { const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; From be221a5eac3c25a5748b49f2c60697b7019b74b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:37:07 +0000 Subject: [PATCH 019/236] Fix race condition in terminal quick fix provider registration Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../browser/terminalQuickFixService.ts | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts index 55ff138f7ff..b86e90ab9e4 100644 --- a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts +++ b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts @@ -20,6 +20,8 @@ export class TerminalQuickFixService implements ITerminalQuickFixService { private _providers: Map = new Map(); get providers(): Map { return this._providers; } + private _pendingProviders: Map = new Map(); + private readonly _onDidRegisterProvider = new Emitter(); readonly onDidRegisterProvider = this._onDidRegisterProvider.event; private readonly _onDidRegisterCommandSelector = new Emitter(); @@ -50,6 +52,14 @@ export class TerminalQuickFixService implements ITerminalQuickFixService { registerCommandSelector(selector: ITerminalCommandSelector): void { this._selectors.set(selector.id, selector); this._onDidRegisterCommandSelector.fire(selector); + + // Check if there's a pending provider for this selector + const pendingProvider = this._pendingProviders.get(selector.id); + if (pendingProvider) { + this._pendingProviders.delete(selector.id); + this._providers.set(selector.id, pendingProvider); + this._onDidRegisterProvider.fire({ selector, provider: pendingProvider }); + } } registerQuickFixProvider(id: string, provider: ITerminalQuickFixProvider): IDisposable { @@ -61,17 +71,20 @@ export class TerminalQuickFixService implements ITerminalQuickFixService { if (disposed) { return; } - this._providers.set(id, provider); const selector = this._selectors.get(id); - if (!selector) { - this._logService.error(`No registered selector for ID: ${id}`); - return; + if (selector) { + // Selector is already available, register immediately + this._providers.set(id, provider); + this._onDidRegisterProvider.fire({ selector, provider }); + } else { + // Selector not yet available, store provider as pending + this._pendingProviders.set(id, provider); } - this._onDidRegisterProvider.fire({ selector, provider }); }); return toDisposable(() => { disposed = true; this._providers.delete(id); + this._pendingProviders.delete(id); const selector = this._selectors.get(id); if (selector) { this._selectors.delete(id); From 717d3ac2d1b1eb37be5ee32a5a0a344a060e7128 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:51:06 +0000 Subject: [PATCH 020/236] Fix test format errors and improve main/master branch ordering Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../suggest/browser/terminalCompletionModel.ts | 10 ++++++++++ .../test/browser/terminalCompletionModel.test.ts | 6 +----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index 5da566f2740..4065388d44a 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -51,6 +51,16 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI if (bIsMainOrMaster && !aIsMainOrMaster) { return 1; } + + // When both are main/master, prioritize main over master + if (aIsMainOrMaster && bIsMainOrMaster) { + if (aLabel === 'main' && bLabel === 'master') { + return -1; + } + if (aLabel === 'master' && bLabel === 'main') { + return 1; + } + } } // Sort by the score diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts index 2bb8187ca7e..70e45031c58 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts @@ -357,11 +357,7 @@ suite('TerminalCompletionModel', function () { createItem({ label: { label: 'main', description: 'Main branch' }, provider: 'terminal-suggest' }) ]; const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); - assertItems(model, [ - { label: 'main', description: 'Main branch' }, - { label: 'master', description: 'Master branch' }, - { label: 'feature-branch', description: 'Feature branch' } - ]); + assertItems(model, ['main', 'master', 'feature-branch']); }); }); }); From 670d678f26f0f9e14156cf3b5283a5595cc92d31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:52:26 +0000 Subject: [PATCH 021/236] Update test files to use SendSequence instead of WriteDataToTerminal Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../terminal/browser/terminalActions.ts | 2 +- test/automation/src/terminal.ts | 8 +++---- .../terminal-shellIntegration.test.ts | 22 +++++++++---------- .../terminal/terminal-stickyScroll.test.ts | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 15810e8fbd4..598bb27dbc7 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -142,7 +142,7 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar } } - // Process escape sequences similar to WriteDataToTerminal + // Process escape sequences let processedText = text .replace(/\\n/g, '\n') .replace(/\\r/g, '\r'); diff --git a/test/automation/src/terminal.ts b/test/automation/src/terminal.ts index 214ca824f7c..d43089b2dda 100644 --- a/test/automation/src/terminal.ts +++ b/test/automation/src/terminal.ts @@ -40,7 +40,7 @@ export enum TerminalCommandIdWithValue { NewWithProfile = 'workbench.action.terminal.newWithProfile', SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell', AttachToSession = 'workbench.action.terminal.attachToSession', - WriteDataToTerminal = 'workbench.action.terminal.writeDataToTerminal' + SendSequence = 'workbench.action.terminal.sendSequence' } /** @@ -155,7 +155,7 @@ export class Terminal { /** * Creates an empty terminal by opening a regular terminal and resetting its state such that it * essentially acts like an Pseudoterminal extension API-based terminal. This can then be paired - * with `TerminalCommandIdWithValue.WriteDataToTerminal` to make more reliable tests. + * with `TerminalCommandIdWithValue.SendSequence` to make more reliable tests. */ async createEmptyTerminal(expectedLocation?: 'editor' | 'panel'): Promise { await this.createTerminal(expectedLocation); @@ -166,11 +166,11 @@ export class Terminal { await this.waitForTerminalText(buffer => buffer.some(line => line.startsWith('initialized'))); // Erase all content and reset cursor to top - await this.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${csi('2J')}${csi('H')}`); + await this.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${csi('2J')}${csi('H')}`); // Force windows pty mode off; assume all sequences are rendered in correct position if (process.platform === 'win32') { - await this.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('P;IsWindows=False')}`); + await this.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('P;IsWindows=False')}`); } } diff --git a/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts b/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts index b0d0db48bf3..f89b59c4a5c 100644 --- a/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts +++ b/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts @@ -98,33 +98,33 @@ export function setup(options?: { skipSuite: boolean }) { // Use the simplest profile to get as little process interaction as possible await terminal.createEmptyTerminal(); // Erase all content and reset cursor to top - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${csi('2J')}${csi('H')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${csi('2J')}${csi('H')}`); }); describe('VS Code sequences', () => { it('should handle the simple case', async () => { - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 0`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}exitcode 0`); await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Success\\r\\n${vsc('D;0')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${vsc('C')}Success\\r\\n${vsc('D;0')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 1`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}exitcode 1`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Failure\\r\\n${vsc('D;1')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${vsc('C')}Failure\\r\\n${vsc('D;1')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }); }); }); describe('Final Term sequences', () => { it('should handle the simple case', async () => { - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 0`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 0`); await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Success\\r\\n${ft('D;0')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${ft('C')}Success\\r\\n${ft('D;0')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Failure\\r\\n${ft('D;1')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${ft('C')}Failure\\r\\n${ft('D;1')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }); }); }); diff --git a/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts b/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts index 495a3bf033f..b079abd3e68 100644 --- a/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts +++ b/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts @@ -35,7 +35,7 @@ export function setup(options?: { skipSuite: boolean }) { expectedLineCount: number = 1 ): Promise { const data = generateCommandAndOutput(prompt, command, exitCode); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, data); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, data); // Verify line count await app.code.waitForElements('.terminal-sticky-scroll .xterm-rows > *', true, e => e.length === expectedLineCount); // Verify content From d7cc9b31ce15881ef1ff548422746a967d8f4447 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:55:53 +0000 Subject: [PATCH 022/236] Fix compilation errors by implementing sendSignal method in missing classes Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- src/vs/platform/terminal/node/ptyHostService.ts | 3 +++ src/vs/platform/terminal/node/ptyService.ts | 6 ++++++ src/vs/workbench/contrib/terminal/browser/remotePty.ts | 10 ++++++++++ .../terminal/browser/terminalProcessExtHostProxy.ts | 4 ++++ .../contrib/terminal/electron-sandbox/localPty.ts | 7 +++++++ .../terminal/common/embedderTerminalService.ts | 3 +++ 6 files changed, 33 insertions(+) diff --git a/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts index 621c9ef3220..86e0e53b6e9 100644 --- a/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -248,6 +248,9 @@ export class PtyHostService extends Disposable implements IPtyHostService { input(id: number, data: string): Promise { return this._proxy.input(id, data); } + sendSignal(id: number, signal: string): Promise { + return this._proxy.sendSignal(id, signal); + } processBinary(id: number, data: string): Promise { return this._proxy.processBinary(id, data); } diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 6cfe6e5a376..01e98822f2f 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -860,6 +860,12 @@ class PersistentTerminalProcess extends Disposable { } return this._terminalProcess.input(data); } + sendSignal(signal: string): void { + if (this._inReplay) { + return; + } + return this._terminalProcess.sendSignal(signal); + } writeBinary(data: string): Promise { return this._terminalProcess.processBinary(data); } diff --git a/src/vs/workbench/contrib/terminal/browser/remotePty.ts b/src/vs/workbench/contrib/terminal/browser/remotePty.ts index 6dcda309192..fd55edd7aba 100644 --- a/src/vs/workbench/contrib/terminal/browser/remotePty.ts +++ b/src/vs/workbench/contrib/terminal/browser/remotePty.ts @@ -65,6 +65,16 @@ export class RemotePty extends BasePty implements ITerminalChildProcess { }); } + sendSignal(signal: string): void { + if (this._inReplay) { + return; + } + + this._startBarrier.wait().then(_ => { + this._remoteTerminalChannel.sendSignal(this.id, signal); + }); + } + processBinary(e: string): Promise { return this._remoteTerminalChannel.processBinary(this.id, e); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts index ade719bd981..cd71fa1cd39 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts @@ -120,6 +120,10 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal this._onInput.fire(data); } + sendSignal(signal: string): void { + // No-op - Extension terminals don't have direct process access + } + resize(cols: number, rows: number): void { this._onResize.fire({ cols, rows }); } diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts index ed397a35984..5375e636116 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts @@ -45,6 +45,13 @@ export class LocalPty extends BasePty implements ITerminalChildProcess { this._proxy.input(this.id, data); } + sendSignal(signal: string): void { + if (this._inReplay) { + return; + } + this._proxy.sendSignal(this.id, signal); + } + resize(cols: number, rows: number): void { if (this._inReplay || this._lastDimensions.cols === cols && this._lastDimensions.rows === rows) { return; diff --git a/src/vs/workbench/services/terminal/common/embedderTerminalService.ts b/src/vs/workbench/services/terminal/common/embedderTerminalService.ts index e976a8617ca..f1001facbc1 100644 --- a/src/vs/workbench/services/terminal/common/embedderTerminalService.ts +++ b/src/vs/workbench/services/terminal/common/embedderTerminalService.ts @@ -118,6 +118,9 @@ class EmbedderTerminalProcess extends Disposable implements ITerminalChildProces input(): void { // not supported } + sendSignal(): void { + // not supported + } async processBinary(): Promise { // not supported } From b47337d9a5059d1cbae5696bc777fa52123b6e06 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 04:23:34 -0700 Subject: [PATCH 023/236] Format terminalActions.ts --- src/vs/workbench/contrib/terminal/browser/terminalActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 598bb27dbc7..bf957a75494 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -128,7 +128,7 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar } let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; - + // If no text provided, prompt user for input if (!text) { const quickInputService = accessor.get(IQuickInputService); @@ -146,7 +146,7 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar let processedText = text .replace(/\\n/g, '\n') .replace(/\\r/g, '\r'); - + // Process hex escape sequences (\xNN) while (true) { const match = processedText.match(/\\x([0-9a-fA-F]{2})/); From a19a9937852440351dbafb813733541801a00986 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 04:23:58 -0700 Subject: [PATCH 024/236] Remove unused imports --- .../developer/browser/terminal.developer.contribution.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts index 51cc3da5222..d2fc5dda4ca 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts @@ -17,12 +17,11 @@ import { IConfigurationService } from '../../../../../platform/configuration/com import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; import { IFileService } from '../../../../../platform/files/common/files.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; -import { IQuickInputService } from '../../../../../platform/quickinput/common/quickInput.js'; import { ITerminalCommand, TerminalCapability } from '../../../../../platform/terminal/common/capabilities/capabilities.js'; import { ITerminalLogService, TerminalSettingId } from '../../../../../platform/terminal/common/terminal.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { IStatusbarService, StatusbarAlignment, type IStatusbarEntry } from '../../../../services/statusbar/browser/statusbar.js'; -import { IInternalXtermTerminal, ITerminalContribution, ITerminalInstance, IXtermTerminal } from '../../../terminal/browser/terminal.js'; +import { ITerminalContribution, ITerminalInstance, IXtermTerminal } from '../../../terminal/browser/terminal.js'; import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js'; import { registerTerminalContribution, type ITerminalContributionContext } from '../../../terminal/browser/terminalExtensions.js'; import { TerminalContextKeys } from '../../../terminal/common/terminalContextKey.js'; From 8a6551bb6eacc4d567e979398abbf4dd2b152ad8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:27:42 +0000 Subject: [PATCH 025/236] Remove special main/master ordering, use regular completion sorting Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../suggest/browser/terminalCompletionModel.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index 4065388d44a..5da566f2740 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -51,16 +51,6 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI if (bIsMainOrMaster && !aIsMainOrMaster) { return 1; } - - // When both are main/master, prioritize main over master - if (aIsMainOrMaster && bIsMainOrMaster) { - if (aLabel === 'main' && bLabel === 'master') { - return -1; - } - if (aLabel === 'master' && bLabel === 'main') { - return 1; - } - } } // Sort by the score From ea74aa6d5a9d1c910aa37d1a15d60dc3e2ca133b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 04:31:53 -0700 Subject: [PATCH 026/236] Avoid using accessor after await --- .../contrib/terminal/browser/terminalActions.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index bf957a75494..5dd7204629c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -121,7 +121,12 @@ export async function getCwdForSplit( } export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { + const configurationResolverService = accessor.get(IConfigurationResolverService); + const historyService = accessor.get(IHistoryService); + const quickInputService = accessor.get(IQuickInputService); const terminalService = accessor.get(ITerminalService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const instance = terminalService.activeInstance || await terminalService.getActiveOrCreateInstance(); if (!instance) { return; @@ -131,7 +136,6 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar // If no text provided, prompt user for input if (!text) { - const quickInputService = accessor.get(IQuickInputService); text = await quickInputService.input({ value: '', placeHolder: 'Enter sequence to send (supports \\n, \\r, \\x escape sequences)', @@ -156,9 +160,6 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); } - const configurationResolverService = accessor.get(IConfigurationResolverService); - const workspaceContextService = accessor.get(IWorkspaceContextService); - const historyService = accessor.get(IHistoryService); const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, processedText); From 46b0380e09e1b519b7c1b12a9c45e0b4d87d0c13 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 04:40:20 -0700 Subject: [PATCH 027/236] Add hack note, improve condition --- .../suggest/browser/terminalCompletionModel.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index 5da566f2740..0beb1d2307f 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -39,7 +39,9 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI } // Boost main and master branches for git commands - if (/^\s*git\b/.test(leadingLineContent) && a.completion.provider === 'terminal-suggest' && b.completion.provider === 'terminal-suggest') { + // HACK: Currently this just matches leading line content, it should eventually check the + // completion type is a branch + if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; From 9268d889f10c2fd057481c5c7ed6c0856fc4b004 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 04:42:36 -0700 Subject: [PATCH 028/236] Move git branch boost below main score check --- .../browser/terminalCompletionModel.ts | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index 0beb1d2307f..bbcd8f55701 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -38,23 +38,6 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI return 1; } - // Boost main and master branches for git commands - // HACK: Currently this just matches leading line content, it should eventually check the - // completion type is a branch - if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { - const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; - const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; - const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; - const bIsMainOrMaster = bLabel === 'main' || bLabel === 'master'; - - if (aIsMainOrMaster && !bIsMainOrMaster) { - return -1; - } - if (bIsMainOrMaster && !aIsMainOrMaster) { - return 1; - } - } - // Sort by the score let score = b.score[0] - a.score[0]; if (score !== 0) { @@ -98,6 +81,23 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI } } + // Boost main and master branches for git commands + // HACK: Currently this just matches leading line content, it should eventually check the + // completion type is a branch + if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { + const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; + const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; + const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; + const bIsMainOrMaster = bLabel === 'main' || bLabel === 'master'; + + if (aIsMainOrMaster && !bIsMainOrMaster) { + return -1; + } + if (bIsMainOrMaster && !aIsMainOrMaster) { + return 1; + } + } + // Sort by more detailed completions if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method) { if (typeof a.completion.label !== 'string' && a.completion.label.description && typeof b.completion.label !== 'string' && b.completion.label.description) { From eb0eb3c57903986589bbf9396eb4c89259e729e0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 05:02:46 -0700 Subject: [PATCH 029/236] Tweak tests --- .../browser/terminalCompletionModel.test.ts | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts index 70e45031c58..873ba7b74c0 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts @@ -7,6 +7,7 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/ import { TerminalCompletionModel } from '../../browser/terminalCompletionModel.js'; import { LineContext } from '../../../../../services/suggest/browser/simpleCompletionModel.js'; import { TerminalCompletionItem, TerminalCompletionItemKind, type ITerminalCompletion } from '../../browser/terminalCompletionItem.js'; +import type { CompletionItemLabel } from '../../../../../services/suggest/browser/simpleCompletionItem.js'; function createItem(options: Partial): TerminalCompletionItem { return new TerminalCompletionItem({ @@ -41,7 +42,7 @@ function createFolderItemsModel(...labels: string[]): TerminalCompletionModel { ); } -function assertItems(model: TerminalCompletionModel, labels: string[]): void { +function assertItems(model: TerminalCompletionModel, labels: (string | CompletionItemLabel)[]): void { assert.deepStrictEqual(model.items.map(i => i.completion.label), labels); assert.strictEqual(model.items.length, labels.length); // sanity check } @@ -300,10 +301,10 @@ suite('TerminalCompletionModel', function () { suite('git branch priority sorting', () => { test('should prioritize main and master branches for git commands', () => { const items = [ - createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), - createItem({ label: 'master', provider: 'terminal-suggest' }), - createItem({ label: 'development', provider: 'terminal-suggest' }), - createItem({ label: 'main', provider: 'terminal-suggest' }) + createItem({ label: 'feature-branch' }), + createItem({ label: 'master' }), + createItem({ label: 'development' }), + createItem({ label: 'main' }) ]; const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); assertItems(model, ['main', 'master', 'development', 'feature-branch']); @@ -311,10 +312,10 @@ suite('TerminalCompletionModel', function () { test('should prioritize main and master branches for git switch command', () => { const items = [ - createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), - createItem({ label: 'main', provider: 'terminal-suggest' }), - createItem({ label: 'another-feature', provider: 'terminal-suggest' }), - createItem({ label: 'master', provider: 'terminal-suggest' }) + createItem({ label: 'feature-branch' }), + createItem({ label: 'main' }), + createItem({ label: 'another-feature' }), + createItem({ label: 'master' }) ]; const model = new TerminalCompletionModel(items, new LineContext('git switch ', 0)); assertItems(model, ['main', 'master', 'another-feature', 'feature-branch']); @@ -322,29 +323,19 @@ suite('TerminalCompletionModel', function () { test('should not prioritize main and master for non-git commands', () => { const items = [ - createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), - createItem({ label: 'master', provider: 'terminal-suggest' }), - createItem({ label: 'main', provider: 'terminal-suggest' }) + createItem({ label: 'feature-branch' }), + createItem({ label: 'master' }), + createItem({ label: 'main' }) ]; const model = new TerminalCompletionModel(items, new LineContext('ls ', 0)); assertItems(model, ['feature-branch', 'main', 'master']); }); - test('should only apply to terminal-suggest provider', () => { - const items = [ - createItem({ label: 'feature-branch', provider: 'other-provider' }), - createItem({ label: 'master', provider: 'other-provider' }), - createItem({ label: 'main', provider: 'other-provider' }) - ]; - const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); - assertItems(model, ['feature-branch', 'main', 'master']); - }); - test('should handle git commands with leading whitespace', () => { const items = [ - createItem({ label: 'feature-branch', provider: 'terminal-suggest' }), - createItem({ label: 'master', provider: 'terminal-suggest' }), - createItem({ label: 'main', provider: 'terminal-suggest' }) + createItem({ label: 'feature-branch' }), + createItem({ label: 'master' }), + createItem({ label: 'main' }) ]; const model = new TerminalCompletionModel(items, new LineContext(' git checkout ', 0)); assertItems(model, ['main', 'master', 'feature-branch']); @@ -352,12 +343,16 @@ suite('TerminalCompletionModel', function () { test('should work with complex label objects', () => { const items = [ - createItem({ label: { label: 'feature-branch', description: 'Feature branch' }, provider: 'terminal-suggest' }), - createItem({ label: { label: 'master', description: 'Master branch' }, provider: 'terminal-suggest' }), - createItem({ label: { label: 'main', description: 'Main branch' }, provider: 'terminal-suggest' }) + createItem({ label: { label: 'feature-branch', description: 'Feature branch' } }), + createItem({ label: { label: 'master', description: 'Master branch' } }), + createItem({ label: { label: 'main', description: 'Main branch' } }) ]; const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); - assertItems(model, ['main', 'master', 'feature-branch']); + assertItems(model, [ + { label: "main", description: "Main branch" }, + { label: "master", description: "Master branch" }, + { label: "feature-branch", description: "Feature branch" }, + ]); }); }); }); From b3275ed4b0629f21f37162b1ba826d8123947443 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:10:44 +0000 Subject: [PATCH 030/236] Move git branch boost after score comparison to avoid global prioritization Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../browser/terminalCompletionModel.ts | 34 +++++++++---------- .../browser/terminalCompletionModel.test.ts | 6 +--- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index bbcd8f55701..13033b1e2b2 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -44,6 +44,23 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI return score; } + // Boost main and master branches for git commands (only when scores are equal) + // HACK: Currently this just matches leading line content, it should eventually check the + // completion type is a branch + if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { + const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; + const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; + const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; + const bIsMainOrMaster = bLabel === 'main' || bLabel === 'master'; + + if (aIsMainOrMaster && !bIsMainOrMaster) { + return -1; + } + if (bIsMainOrMaster && !aIsMainOrMaster) { + return 1; + } + } + // Boost inline completions if (a.completion.kind === TerminalCompletionItemKind.InlineSuggestion && a.completion.kind !== b.completion.kind) { return -1; @@ -81,23 +98,6 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI } } - // Boost main and master branches for git commands - // HACK: Currently this just matches leading line content, it should eventually check the - // completion type is a branch - if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { - const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; - const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; - const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; - const bIsMainOrMaster = bLabel === 'main' || bLabel === 'master'; - - if (aIsMainOrMaster && !bIsMainOrMaster) { - return -1; - } - if (bIsMainOrMaster && !aIsMainOrMaster) { - return 1; - } - } - // Sort by more detailed completions if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method) { if (typeof a.completion.label !== 'string' && a.completion.label.description && typeof b.completion.label !== 'string' && b.completion.label.description) { diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts index 873ba7b74c0..26c9992a103 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts @@ -348,11 +348,7 @@ suite('TerminalCompletionModel', function () { createItem({ label: { label: 'main', description: 'Main branch' } }) ]; const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); - assertItems(model, [ - { label: "main", description: "Main branch" }, - { label: "master", description: "Master branch" }, - { label: "feature-branch", description: "Feature branch" }, - ]); + assertItems(model, ['main', 'master', 'feature-branch']); }); }); }); From 00211cb9a93219e81fad63d897d54f62a9c5ad59 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 05:11:48 -0700 Subject: [PATCH 031/236] Revert "Move git branch boost after score comparison to avoid global prioritization" This reverts commit b3275ed4b0629f21f37162b1ba826d8123947443. --- .../browser/terminalCompletionModel.ts | 34 +++++++++---------- .../browser/terminalCompletionModel.test.ts | 6 +++- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index 13033b1e2b2..bbcd8f55701 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -44,23 +44,6 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI return score; } - // Boost main and master branches for git commands (only when scores are equal) - // HACK: Currently this just matches leading line content, it should eventually check the - // completion type is a branch - if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { - const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; - const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; - const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; - const bIsMainOrMaster = bLabel === 'main' || bLabel === 'master'; - - if (aIsMainOrMaster && !bIsMainOrMaster) { - return -1; - } - if (bIsMainOrMaster && !aIsMainOrMaster) { - return 1; - } - } - // Boost inline completions if (a.completion.kind === TerminalCompletionItemKind.InlineSuggestion && a.completion.kind !== b.completion.kind) { return -1; @@ -98,6 +81,23 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI } } + // Boost main and master branches for git commands + // HACK: Currently this just matches leading line content, it should eventually check the + // completion type is a branch + if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { + const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; + const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; + const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; + const bIsMainOrMaster = bLabel === 'main' || bLabel === 'master'; + + if (aIsMainOrMaster && !bIsMainOrMaster) { + return -1; + } + if (bIsMainOrMaster && !aIsMainOrMaster) { + return 1; + } + } + // Sort by more detailed completions if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method) { if (typeof a.completion.label !== 'string' && a.completion.label.description && typeof b.completion.label !== 'string' && b.completion.label.description) { diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts index 26c9992a103..873ba7b74c0 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts @@ -348,7 +348,11 @@ suite('TerminalCompletionModel', function () { createItem({ label: { label: 'main', description: 'Main branch' } }) ]; const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); - assertItems(model, ['main', 'master', 'feature-branch']); + assertItems(model, [ + { label: "main", description: "Main branch" }, + { label: "master", description: "Master branch" }, + { label: "feature-branch", description: "Feature branch" }, + ]); }); }); }); From 0c348ec58c2494c2fae44ad7933cb64f891bff3b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 05:27:30 -0700 Subject: [PATCH 032/236] Show signal command in command palette --- src/vs/workbench/contrib/terminal/browser/terminalActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 270749e69ec..a078914c3d8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -991,7 +991,7 @@ export function registerTerminalActions() { registerTerminalAction({ id: TerminalCommandId.SendSignal, title: terminalStrings.sendSignal, - f1: false, + f1: true, metadata: { description: terminalStrings.sendSignal.value, args: [{ From c6aca76e14041d66a6b065bdd057b84933af9bf7 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 05:34:19 -0700 Subject: [PATCH 033/236] hygiene, remove unused --- .../quickFix/browser/terminalQuickFixService.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts index b86e90ab9e4..4a095d55e76 100644 --- a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts +++ b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts @@ -6,7 +6,6 @@ import { Emitter } from '../../../../../base/common/event.js'; import { IDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; import { localize } from '../../../../../nls.js'; -import { ILogService } from '../../../../../platform/log/common/log.js'; import { ITerminalCommandSelector } from '../../../../../platform/terminal/common/terminal.js'; import { ITerminalQuickFixService, ITerminalQuickFixProvider, ITerminalQuickFixProviderSelector } from './quickFix.js'; import { isProposedApiEnabled } from '../../../../services/extensions/common/extensions.js'; @@ -31,9 +30,7 @@ export class TerminalQuickFixService implements ITerminalQuickFixService { readonly extensionQuickFixes: Promise>; - constructor( - @ILogService private readonly _logService: ILogService, - ) { + constructor() { this.extensionQuickFixes = new Promise((r) => quickFixExtensionPoint.setHandler(fixes => { r(fixes.filter(c => isProposedApiEnabled(c.description, 'terminalQuickFixProvider')).map(c => { if (!c.value) { @@ -52,7 +49,7 @@ export class TerminalQuickFixService implements ITerminalQuickFixService { registerCommandSelector(selector: ITerminalCommandSelector): void { this._selectors.set(selector.id, selector); this._onDidRegisterCommandSelector.fire(selector); - + // Check if there's a pending provider for this selector const pendingProvider = this._pendingProviders.get(selector.id); if (pendingProvider) { From 31db9c41e5d76d2f426a1b4d8319fecd1870af7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:34:37 +0000 Subject: [PATCH 034/236] Add signal picker when no args provided to sendSignal command Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../terminal/browser/terminalActions.ts | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index a078914c3d8..4986f2261f1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -139,13 +139,39 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => { const instance = accessor.get(ITerminalService).activeInstance; - if (instance) { - const signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; - if (!signal) { + if (!instance) { + return; + } + + let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; + + if (!signal) { + const quickInputService = accessor.get(IQuickInputService); + + const signalOptions: IQuickPickItem[] = [ + { label: 'SIGINT', description: 'Interrupt process (Ctrl+C)' }, + { label: 'SIGTERM', description: 'Terminate process gracefully' }, + { label: 'SIGKILL', description: 'Force kill process' }, + { label: 'SIGSTOP', description: 'Stop process' }, + { label: 'SIGCONT', description: 'Continue process' }, + { label: 'SIGHUP', description: 'Hangup' }, + { label: 'SIGQUIT', description: 'Quit process' }, + { label: 'SIGUSR1', description: 'User-defined signal 1' }, + { label: 'SIGUSR2', description: 'User-defined signal 2' } + ]; + + const selected = await quickInputService.pick(signalOptions, { + placeHolder: localize('selectSignal', 'Select signal to send to terminal process') + }); + + if (!selected) { return; } - instance.sendSignal(signal); + + signal = selected.label; } + + instance.sendSignal(signal); }; export class TerminalLaunchHelpAction extends Action { From f2b19d24f090a42a3e8111ba6070ab0625e4a82b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 05:39:18 -0700 Subject: [PATCH 035/236] Remove to terminal as it's the category --- src/vs/workbench/contrib/terminal/common/terminalStrings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts index 523610339f9..28cd7adacaa 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts @@ -37,7 +37,7 @@ export const terminalStrings = { toggleSizeToContentWidth: localize2('workbench.action.terminal.sizeToContentWidthInstance', "Toggle Size to Content Width"), focusHover: localize2('workbench.action.terminal.focusHover', "Focus Hover"), sendSequence: localize2('workbench.action.terminal.sendSequence', "Send Custom Sequence to Terminal"), - sendSignal: localize2('workbench.action.terminal.sendSignal', "Send Signal to Terminal"), + sendSignal: localize2('workbench.action.terminal.sendSignal', "Send Signal"), newWithCwd: localize2('workbench.action.terminal.newWithCwd', "Create New Terminal Starting in a Custom Working Directory"), renameWithArgs: localize2('workbench.action.terminal.renameWithArg', "Rename the Currently Active Terminal"), scrollToPreviousCommand: localize2('workbench.action.terminal.scrollToPreviousCommand', "Scroll to Previous Command"), From b9db1ff07632929712110f8bd5e6a967847bd9fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:50:44 +0000 Subject: [PATCH 036/236] Add manual signal input option to sendSignal command Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- .../terminal/browser/terminalActions.ts | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 4986f2261f1..ecccdd8e364 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -25,7 +25,7 @@ import { ILabelService } from '../../../../platform/label/common/label.js'; import { IListService } from '../../../../platform/list/browser/listService.js'; import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; -import { IPickOptions, IQuickInputService, IQuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; +import { IPickOptions, IQuickInputService, IQuickPickItem, IQuickPickSeparator, QuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; import { ITerminalProfile, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalSettingId } from '../../../../platform/terminal/common/terminal.js'; import { IWorkspaceContextService, IWorkspaceFolder } from '../../../../platform/workspace/common/workspace.js'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from '../../../browser/actions/workspaceCommands.js'; @@ -148,7 +148,7 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args if (!signal) { const quickInputService = accessor.get(IQuickInputService); - const signalOptions: IQuickPickItem[] = [ + const signalOptions: QuickPickItem[] = [ { label: 'SIGINT', description: 'Interrupt process (Ctrl+C)' }, { label: 'SIGTERM', description: 'Terminate process gracefully' }, { label: 'SIGKILL', description: 'Force kill process' }, @@ -157,7 +157,9 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args { label: 'SIGHUP', description: 'Hangup' }, { label: 'SIGQUIT', description: 'Quit process' }, { label: 'SIGUSR1', description: 'User-defined signal 1' }, - { label: 'SIGUSR2', description: 'User-defined signal 2' } + { label: 'SIGUSR2', description: 'User-defined signal 2' }, + { type: 'separator' }, + { label: localize('manualSignal', 'Manually enter signal'), description: 'Enter custom signal name' } ]; const selected = await quickInputService.pick(signalOptions, { @@ -168,7 +170,20 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args return; } - signal = selected.label; + if (selected.label === localize('manualSignal', 'Manually enter signal')) { + const inputSignal = await quickInputService.input({ + prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), + placeHolder: 'SIGTERM' + }); + + if (!inputSignal) { + return; + } + + signal = inputSignal; + } else { + signal = selected.label; + } } instance.sendSignal(signal); From 12410ba3196e20b3259b288ac3c64a2348c502db Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 05:53:18 -0700 Subject: [PATCH 037/236] Only show send signal command when no Windows --- .../contrib/terminal/browser/terminalActions.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ecccdd8e364..cc0c1c0769a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -144,10 +144,10 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args } let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; - + if (!signal) { const quickInputService = accessor.get(IQuickInputService); - + const signalOptions: QuickPickItem[] = [ { label: 'SIGINT', description: 'Interrupt process (Ctrl+C)' }, { label: 'SIGTERM', description: 'Terminate process gracefully' }, @@ -165,27 +165,26 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args const selected = await quickInputService.pick(signalOptions, { placeHolder: localize('selectSignal', 'Select signal to send to terminal process') }); - + if (!selected) { return; } - + if (selected.label === localize('manualSignal', 'Manually enter signal')) { const inputSignal = await quickInputService.input({ prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), - placeHolder: 'SIGTERM' }); - + if (!inputSignal) { return; } - + signal = inputSignal; } else { signal = selected.label; } } - + instance.sendSignal(signal); }; @@ -1032,7 +1031,7 @@ export function registerTerminalActions() { registerTerminalAction({ id: TerminalCommandId.SendSignal, title: terminalStrings.sendSignal, - f1: true, + f1: !isWindows, metadata: { description: terminalStrings.sendSignal.value, args: [{ From c9d1764d42508f350f173c831fd1157f28bac321 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 05:58:49 -0700 Subject: [PATCH 038/236] Move accessor use to top, await ipc --- src/vs/workbench/contrib/terminal/browser/terminalActions.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index cc0c1c0769a..2fdf2038679 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -138,6 +138,7 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar }; export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => { + const quickInputService = accessor.get(IQuickInputService); const instance = accessor.get(ITerminalService).activeInstance; if (!instance) { return; @@ -146,8 +147,6 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; if (!signal) { - const quickInputService = accessor.get(IQuickInputService); - const signalOptions: QuickPickItem[] = [ { label: 'SIGINT', description: 'Interrupt process (Ctrl+C)' }, { label: 'SIGTERM', description: 'Terminate process gracefully' }, @@ -185,7 +184,7 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args } } - instance.sendSignal(signal); + await instance.sendSignal(signal); }; export class TerminalLaunchHelpAction extends Action { From abc0765f84a52b07863bb9c044acd793ad498b4a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 06:24:14 -0700 Subject: [PATCH 039/236] Localize --- .../terminal/browser/terminalActions.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 2fdf2038679..320e96d86b5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -25,7 +25,7 @@ import { ILabelService } from '../../../../platform/label/common/label.js'; import { IListService } from '../../../../platform/list/browser/listService.js'; import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; -import { IPickOptions, IQuickInputService, IQuickPickItem, IQuickPickSeparator, QuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; +import { IPickOptions, IQuickInputService, IQuickPickItem, QuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; import { ITerminalProfile, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalSettingId } from '../../../../platform/terminal/common/terminal.js'; import { IWorkspaceContextService, IWorkspaceFolder } from '../../../../platform/workspace/common/workspace.js'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from '../../../browser/actions/workspaceCommands.js'; @@ -148,17 +148,17 @@ export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args if (!signal) { const signalOptions: QuickPickItem[] = [ - { label: 'SIGINT', description: 'Interrupt process (Ctrl+C)' }, - { label: 'SIGTERM', description: 'Terminate process gracefully' }, - { label: 'SIGKILL', description: 'Force kill process' }, - { label: 'SIGSTOP', description: 'Stop process' }, - { label: 'SIGCONT', description: 'Continue process' }, - { label: 'SIGHUP', description: 'Hangup' }, - { label: 'SIGQUIT', description: 'Quit process' }, - { label: 'SIGUSR1', description: 'User-defined signal 1' }, - { label: 'SIGUSR2', description: 'User-defined signal 2' }, + { label: 'SIGINT', description: localize('SIGINT', 'Interrupt process (Ctrl+C)') }, + { label: 'SIGTERM', description: localize('SIGTERM', 'Terminate process gracefully') }, + { label: 'SIGKILL', description: localize('SIGKILL', 'Force kill process') }, + { label: 'SIGSTOP', description: localize('SIGSTOP', 'Stop process') }, + { label: 'SIGCONT', description: localize('SIGCONT', 'Continue process') }, + { label: 'SIGHUP', description: localize('SIGHUP', 'Hangup') }, + { label: 'SIGQUIT', description: localize('SIGQUIT', 'Quit process') }, + { label: 'SIGUSR1', description: localize('SIGUSR1', 'User-defined signal 1') }, + { label: 'SIGUSR2', description: localize('SIGUSR2', 'User-defined signal 2') }, { type: 'separator' }, - { label: localize('manualSignal', 'Manually enter signal'), description: 'Enter custom signal name' } + { label: localize('manualSignal', 'Manually enter signal') } ]; const selected = await quickInputService.pick(signalOptions, { From a011812c7d8cb92f31a829948e95b3c5b16d4e38 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:16:59 -0700 Subject: [PATCH 040/236] Correct completion kind --- .../terminalContrib/suggest/browser/terminalCompletionModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts index bbcd8f55701..5caddc89357 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionModel.ts @@ -84,7 +84,7 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI // Boost main and master branches for git commands // HACK: Currently this just matches leading line content, it should eventually check the // completion type is a branch - if (a.completion.kind === TerminalCompletionItemKind.Method && b.completion.kind === TerminalCompletionItemKind.Method && /^\s*git\b/.test(leadingLineContent)) { + if (a.completion.kind === TerminalCompletionItemKind.Argument && b.completion.kind === TerminalCompletionItemKind.Argument && /^\s*git\b/.test(leadingLineContent)) { const aLabel = typeof a.completion.label === 'string' ? a.completion.label : a.completion.label.label; const bLabel = typeof b.completion.label === 'string' ? b.completion.label : b.completion.label.label; const aIsMainOrMaster = aLabel === 'main' || aLabel === 'master'; From 0264176af12df64d7449558cca4c8e5b1fb34d8a Mon Sep 17 00:00:00 2001 From: Josh Spicer <23246594+joshspicer@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:47:54 -0700 Subject: [PATCH 041/236] Bulk query marketplace check for missingFromMarketplace (#250775) * bulk query marketplace, add telemetry * send telemetry on non-zero missingcount * more useful telemetry * telemetry for queriedIds and missingIds * no need for an extra loop --- .../browser/extensionsWorkbenchService.ts | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 830d9fe5280..752dcc3196f 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -680,25 +680,56 @@ class Extensions extends Disposable { } } // Detect extensions that do not have a corresponding gallery entry. - // This indicates that it was likely removed from the gallery if (flagExtensionsMissingFromGallery) { + const extensionsToQuery = []; for (const extension of this.local) { + // Extension is already paired with a gallery object + if (extension.gallery) { + continue; + } + // Already flagged as missing from gallery + if (extension.missingFromGallery) { + continue; + } + // A UUID indicates extension originated from gallery if (!extension.identifier.uuid) { continue; } + // Extension is not present in the set we are concerned about if (!flagExtensionsMissingFromGallery.some(f => areSameExtensions(f, extension.identifier))) { continue; } - if (galleryExtensions.find(g => areSameExtensions(g.identifier, extension.identifier))) { - continue; + extensionsToQuery.push(extension); + } + if (extensionsToQuery.length) { + const queryResult = await this.galleryService.getExtensions(extensionsToQuery.map(e => ({ ...e.identifier, version: e.version })), CancellationToken.None); + const queriedIds: string[] = []; + const missingIds: string[] = []; + for (const extension of extensionsToQuery) { + queriedIds.push(extension.identifier.id); + const gallery = queryResult.find(g => areSameExtensions(g.identifier, extension.identifier)); + if (gallery) { + extension.gallery = gallery; + } else { + extension.missingFromGallery = true; + missingIds.push(extension.identifier.id); + } + this._onChange.fire({ extension }); } - const [gallery] = await this.galleryService.getExtensions([{ ...extension.identifier, version: extension.version }], CancellationToken.None); - if (gallery) { - extension.gallery = gallery; - } else { - extension.missingFromGallery = true; - } - this._onChange.fire({ extension }); + type MissingFromGalleryClassification = { + owner: 'joshspicer'; + comment: 'Report when installed extensions are no longer available in the gallery'; + queriedIds: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Extensions queried as potentially missing from gallery' }; + missingIds: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Extensions determined missing from gallery' }; + }; + type MissingFromGalleryEvent = { + readonly queriedIds: TelemetryTrustedValue; + readonly missingIds: TelemetryTrustedValue; + }; + this.telemetryService.publicLog2('extensions:missingFromGallery', { + queriedIds: new TelemetryTrustedValue(queriedIds.join(';')), + missingIds: new TelemetryTrustedValue(missingIds.join(';')) + }); } } } From 43f7e60f627f65b02aacd8a1c9c630df1c2923fc Mon Sep 17 00:00:00 2001 From: Justin Chen <54879025+justschen@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:12:07 -0700 Subject: [PATCH 042/236] force no border on request monaco list row (#250777) --- src/vs/workbench/contrib/chat/browser/media/chat.css | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 2c215b12237..f7ecdffb5f5 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1947,7 +1947,8 @@ have to be updated for changes to the rules above, or to support more deeply nes box-shadow: none; } - .interactive-request .header.header-disabled { + .interactive-request .header.header-disabled, + .request-hover.has-no-actions { display: none !important; } .request-hover { @@ -1973,14 +1974,14 @@ have to be updated for changes to the rules above, or to support more deeply nes padding: 3px 3px; } - .request-hover.has-no-actions { - display: none !important; - } - .interactive-list > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { overflow: visible !important; } + .interactive-list > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.monaco-list-row.focused.request { + outline: none !important; + } + div[data-index="0"] .monaco-tl-contents { .interactive-item-container.interactive-request { padding-top: 19px; @@ -1991,7 +1992,6 @@ have to be updated for changes to the rules above, or to support more deeply nes } } - .interactive-list > .monaco-list:focus > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused.request { outline: none !important; From 669d397ee8c28b22b5806352f8a097db1b062f9d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:21:06 -0700 Subject: [PATCH 043/236] Fix cell reveal when followCellExecution enabled and notebook tab not active (#250646) * Initial plan for issue * Fix cell reveal when followCellExecution enabled and notebook tab not active - Add ensureNotebookEditorVisible function to bring notebook tab into view before revealing cells - Modify runCell function to ensure notebook editor is visible when autoReveal is enabled - Update all runCell calls to pass editorService for finding and opening notebook editor - Fixes issue where cells were not revealed when notebook tab was not currently active Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * whitespace * rm obvious comment + revealIfOpened * the actual correct solution --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> Co-authored-by: Michael Lively --- .../browser/controller/executeActions.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts index 92fc827c408..533d7e8869e 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts @@ -71,7 +71,7 @@ function renderAllMarkdownCells(context: INotebookActionContext): void { } } -async function runCell(editorGroupsService: IEditorGroupsService, context: INotebookActionContext): Promise { +async function runCell(editorGroupsService: IEditorGroupsService, context: INotebookActionContext, editorService?: IEditorService): Promise { const group = editorGroupsService.activeGroup; if (group) { @@ -80,6 +80,11 @@ async function runCell(editorGroupsService: IEditorGroupsService, context: INote } } + // If auto-reveal is enabled, ensure the notebook editor is visible before revealing cells + if (context.autoReveal && (context.cell || context.selectedCells?.length) && editorService) { + editorService.openEditor({ resource: context.notebookEditor.textModel.uri, options: { revealIfOpened: true } }); + } + if (context.ui && context.cell) { if (context.autoReveal) { handleAutoReveal(context.cell, context.notebookEditor); @@ -284,6 +289,7 @@ registerAction2(class ExecuteCell extends NotebookMultiCellAction { async runWithContext(accessor: ServicesAccessor, context: INotebookCommandContext | INotebookCellToolbarActionContext): Promise { const editorGroupsService = accessor.get(IEditorGroupsService); + const editorService = accessor.get(IEditorService); if (context.ui) { await context.notebookEditor.focusNotebookCell(context.cell, 'container', { skipReveal: true }); @@ -304,7 +310,7 @@ registerAction2(class ExecuteCell extends NotebookMultiCellAction { return; } - await runCell(editorGroupsService, context); + await runCell(editorGroupsService, context, editorService); } }); @@ -422,6 +428,7 @@ registerAction2(class ExecuteCellFocusContainer extends NotebookMultiCellAction async runWithContext(accessor: ServicesAccessor, context: INotebookCommandContext | INotebookCellToolbarActionContext): Promise { const editorGroupsService = accessor.get(IEditorGroupsService); + const editorService = accessor.get(IEditorService); if (context.ui) { await context.notebookEditor.focusNotebookCell(context.cell, 'container', { skipReveal: true }); @@ -433,7 +440,7 @@ registerAction2(class ExecuteCellFocusContainer extends NotebookMultiCellAction } } - await runCell(editorGroupsService, context); + await runCell(editorGroupsService, context, editorService); } }); @@ -526,6 +533,7 @@ registerAction2(class ExecuteCellSelectBelow extends NotebookCellAction { async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { const editorGroupsService = accessor.get(IEditorGroupsService); + const editorService = accessor.get(IEditorService); const idx = context.notebookEditor.getCellIndex(context.cell); if (typeof idx !== 'number') { return; @@ -568,7 +576,7 @@ registerAction2(class ExecuteCellSelectBelow extends NotebookCellAction { } } - return runCell(editorGroupsService, context); + return runCell(editorGroupsService, context, editorService); } } }); @@ -589,6 +597,7 @@ registerAction2(class ExecuteCellInsertBelow extends NotebookCellAction { async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { const editorGroupsService = accessor.get(IEditorGroupsService); + const editorService = accessor.get(IEditorService); const idx = context.notebookEditor.getCellIndex(context.cell); const languageService = accessor.get(ILanguageService); const newFocusMode = context.cell.focusMode === CellFocusMode.Editor ? 'editor' : 'container'; @@ -601,7 +610,7 @@ registerAction2(class ExecuteCellInsertBelow extends NotebookCellAction { if (context.cell.cellKind === CellKind.Markup) { context.cell.updateEditState(CellEditState.Preview, EXECUTE_CELL_INSERT_BELOW); } else { - runCell(editorGroupsService, context); + runCell(editorGroupsService, context, editorService); } } }); From 921786be45c46b54e727aa4f210819bbc6430a6d Mon Sep 17 00:00:00 2001 From: Kaitlin Brooks <47866467+kkbrooks@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:17:46 -0700 Subject: [PATCH 044/236] Chat code block pill token updates (#250531) * update colors for icon labels to meet accessibility color contrast requirements * - update colors for added and removed labels to pass color contrast requirements - added the used tokens to vscode-known-variables * fixing margin-left * update editor gutter colors for added and deleted resources, removed the previously added gitDecoration tokens from known variables * update editor gutter colors for added and deleted lines in dark_modern and updated the fallback colors for editorGutterDeletedBackground * undoing changes to editorGutterAddedBackground and editorGutterDeletedBackground * add foreground colors for added and deleted lines in chat code blocks in chatColors.ts * add chat foreground colors for added and deleted lines in vscode-known-variables.json * rename chat color variables for added and removed lines in chat code block pill --------- Co-authored-by: Justin Chen <54879025+justschen@users.noreply.github.com> --- build/lib/stylelint/vscode-known-variables.json | 4 +++- src/vs/base/browser/ui/iconLabel/iconlabel.css | 4 ++-- .../contrib/chat/browser/media/chatCodeBlockPill.css | 4 ++-- src/vs/workbench/contrib/chat/common/chatColors.ts | 10 ++++++++++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index d032969d9d3..c2725753ec2 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -59,6 +59,8 @@ "--vscode-chat-requestCodeBorder", "--vscode-chat-slashCommandBackground", "--vscode-chat-slashCommandForeground", + "--vscode-chat-linesAddedForeground", + "--vscode-chat-linesRemovedForeground", "--vscode-checkbox-background", "--vscode-checkbox-border", "--vscode-checkbox-disabled-background", @@ -957,4 +959,4 @@ "--animation-opacity", "--chat-setup-dialog-glow-angle" ] -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index ed9278d7087..9bf56cc9eb4 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -60,12 +60,12 @@ } .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-suffix-container > .label-suffix { - opacity: .7; + color: var(--vscode-peekViewTitleDescription-foreground); white-space: pre; } .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-description-container > .label-description { - opacity: .7; + color: var(--vscode-peekViewTitleDescription-foreground); margin-left: 0.5em; font-size: 0.9em; white-space: pre; /* enable to show labels that include multiple whitespaces */ diff --git a/src/vs/workbench/contrib/chat/browser/media/chatCodeBlockPill.css b/src/vs/workbench/contrib/chat/browser/media/chatCodeBlockPill.css index d7d5ac7f77b..8e489f04bc6 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatCodeBlockPill.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatCodeBlockPill.css @@ -58,11 +58,11 @@ span.label-detail { span.label-added { font-weight: bold; padding-left: 4px; - color: var(--vscode-editorGutter-addedBackground); + color: var(--vscode-chat-linesAddedForeground); } span.label-removed { font-weight: bold; padding-left: 4px; - color: var(--vscode-editorGutter-deletedBackground); + color: var(--vscode-chat-linesRemovedForeground); } diff --git a/src/vs/workbench/contrib/chat/common/chatColors.ts b/src/vs/workbench/contrib/chat/common/chatColors.ts index b4159ed6c77..f6e2036e57f 100644 --- a/src/vs/workbench/contrib/chat/common/chatColors.ts +++ b/src/vs/workbench/contrib/chat/common/chatColors.ts @@ -57,3 +57,13 @@ export const chatEditedFileForeground = registerColor( export const chatRequestCodeBorder = registerColor('chat.requestCodeBorder', { dark: '#004972B8', light: '#0e639c40', hcDark: null, hcLight: null }, localize('chat.requestCodeBorder', 'Border color of code blocks within the chat request bubble.'), true); export const chatRequestBubbleBackground = registerColor('chat.requestBubbleBackground', { light: transparent(editorSelectionBackground, 0.3), dark: transparent(editorSelectionBackground, 0.3), hcDark: null, hcLight: null }, localize('chat.requestBubbleBackground', "Background color of the chat request bubble."), true); + +export const chatLinesAddedForeground = registerColor( + 'chat.linesAddedForeground', + { dark: '#54B054', light: '#107C10', hcDark: '#54B054', hcLight: '#107C10' }, + localize('chat.linesAddedForeground', 'Foreground color of lines added in chat code block pill.'), true); + +export const chatLinesRemovedForeground = registerColor( + 'chat.linesRemovedForeground', + { dark: '#FC6A6A', light: '#BC2F32', hcDark: '#F48771', hcLight: '#B5200D' }, + localize('chat.linesRemovedForeground', 'Foreground color of lines removed in chat code block pill.'), true); From 998fb692680cc20d70a805df8fa59cb1443bc897 Mon Sep 17 00:00:00 2001 From: Josh Spicer <23246594+joshspicer@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:28:18 -0700 Subject: [PATCH 045/236] hello 1.102.0 (#250791) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 95b349d56e0..50c4dec4b82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "code-oss-dev", - "version": "1.101.0", + "version": "1.102.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "code-oss-dev", - "version": "1.101.0", + "version": "1.102.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index f7c34e248f0..50a6e24cddc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.101.0", + "version": "1.102.0", "distro": "0110618df4664082ca0cb597c5f9bf66aeed2e35", "author": { "name": "Microsoft Corporation" From 857482f99a9d4f30e193cf84356ce27268e1eb8f Mon Sep 17 00:00:00 2001 From: Sublimeful Date: Fri, 6 Jun 2025 00:03:10 -0500 Subject: [PATCH 046/236] Implements Terminal: Run Recent Command when there are no terminals --- .../browser/terminal.history.contribution.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts b/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts index f0707160e52..d53e447bfd7 100644 --- a/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts @@ -129,7 +129,7 @@ registerActiveInstanceAction({ } }); -registerActiveInstanceAction({ +registerTerminalAction({ id: TerminalHistoryCommandId.RunRecentCommand, title: localize2('workbench.action.terminal.runRecentCommand', 'Run Recent Command...'), precondition, @@ -146,7 +146,22 @@ registerActiveInstanceAction({ weight: KeybindingWeight.WorkbenchContrib } ], - run: async (activeInstance, c) => { + run: async (c, accessor) => { + const activeInstance = await c.service.getActiveOrCreateInstance(); + if (!activeInstance.shellType) { + await c.service.revealActiveTerminal(); + const wasDisposedPrematurely = await new Promise(resolve => { + activeInstance.onDidChangeShellType(() => { + resolve(false); + }); + activeInstance.onDisposed(() => { + resolve(true); + }); + }); + if (wasDisposedPrematurely) { + return; + } + } const history = TerminalHistoryContribution.get(activeInstance); if (!history) { return; From 11308ef574211615f199ea8e6b5fb2cb5793ab8c Mon Sep 17 00:00:00 2001 From: Sublimeful Date: Fri, 6 Jun 2025 00:26:55 -0500 Subject: [PATCH 047/236] Add comments --- .../history/browser/terminal.history.contribution.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts b/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts index d53e447bfd7..c69662c95d4 100644 --- a/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts @@ -147,7 +147,10 @@ registerTerminalAction({ } ], run: async (c, accessor) => { + // If there are no active instances, then create a new terminal instance const activeInstance = await c.service.getActiveOrCreateInstance(); + // Newly created instances will not have a shell type set yet + // This will result in the command picker not showing up, so wait for it to be set if (!activeInstance.shellType) { await c.service.revealActiveTerminal(); const wasDisposedPrematurely = await new Promise(resolve => { @@ -158,6 +161,7 @@ registerTerminalAction({ resolve(true); }); }); + // If the instance was disposed before the shell type was set, then exit if (wasDisposedPrematurely) { return; } From dcf7b7c2cdae9de0eab66894693e8606b08ccea6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 6 Jun 2025 08:44:39 +0200 Subject: [PATCH 048/236] debt - adopt `findEditors` in more places (#250712) --- src/vs/workbench/browser/parts/editor/editorGroupView.ts | 2 +- src/vs/workbench/common/editor.ts | 5 +++++ .../interactive/browser/interactive.contribution.ts | 6 +++++- .../contrib/mcp/browser/mcpCommandsAddConfiguration.ts | 4 +--- .../contrib/notebook/browser/controller/executeActions.ts | 8 +++++--- src/vs/workbench/services/editor/browser/editorService.ts | 2 +- src/vs/workbench/services/editor/common/editorService.ts | 4 ++-- 7 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index db36961d502..1e8b15256e5 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1036,7 +1036,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { findEditors(resource: URI, options?: IFindEditorOptions): EditorInput[] { const canonicalResource = this.uriIdentityService.asCanonicalUri(resource); - return this.getEditors(EditorsOrder.SEQUENTIAL).filter(editor => { + return this.getEditors(options?.order ?? EditorsOrder.SEQUENTIAL).filter(editor => { if (editor.resource && isEqual(editor.resource, canonicalResource)) { return true; } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 3db16dd0d94..0e01088e1e2 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -1290,6 +1290,11 @@ export interface IFindEditorOptions { * as matching, even if the editor is opened in one of the sides. */ supportSideBySide?: SideBySideEditor.PRIMARY | SideBySideEditor.SECONDARY | SideBySideEditor.ANY; + + /** + * The order in which to consider editors for finding. + */ + order?: EditorsOrder; } export interface IMatchEditorOptions { diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index 47fb9d3d0d2..c6dd6f89ab4 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -113,7 +113,11 @@ export class InteractiveDocumentContribution extends Disposable implements IWork }, { createEditorInput: ({ resource }) => { - const editorInput = editorService.getEditors(EditorsOrder.SEQUENTIAL).find(editor => editor.editor instanceof InteractiveEditorInput && editor.editor.inputResource.toString() === resource.toString()); + const editorInput = editorService.findEditors({ + resource, + editorId: 'interactive', + typeId: InteractiveEditorInput.ID + }, { order: EditorsOrder.SEQUENTIAL }).at(0); return editorInput!; } } diff --git a/src/vs/workbench/contrib/mcp/browser/mcpCommandsAddConfiguration.ts b/src/vs/workbench/contrib/mcp/browser/mcpCommandsAddConfiguration.ts index 781802ec8c3..9e09d86f0a2 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpCommandsAddConfiguration.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpCommandsAddConfiguration.ts @@ -24,7 +24,6 @@ import { INotificationService } from '../../../../platform/notification/common/n import { IQuickInputService, IQuickPickItem, QuickPickInput } from '../../../../platform/quickinput/common/quickInput.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; -import { EditorsOrder } from '../../../common/editor.js'; import { IJSONEditingService } from '../../../services/configuration/common/jsonEditing.js'; import { ConfiguredInput } from '../../../services/configurationResolver/common/configurationResolver.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; @@ -489,8 +488,7 @@ export class McpAddConfigurationCommand { } const pick = await this._quickInputService.pick(items, { placeHolder, ignoreFocusLost: true }); - const getEditors = () => this._editorService.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE) - .filter(e => e.editor.resource?.toString() === resource.toString()); + const getEditors = () => this._editorService.findEditors(resource); switch (pick?.id) { case 'show': diff --git a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts index 533d7e8869e..f52fbf3c8d4 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts @@ -15,7 +15,6 @@ import { MenuId, MenuRegistry, registerAction2 } from '../../../../../platform/a import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; -import { EditorsOrder } from '../../../../common/editor.js'; import { IDebugService } from '../../../debug/common/debug.js'; import { CTX_INLINE_CHAT_FOCUSED } from '../../../inlineChat/common/inlineChat.js'; import { insertCell } from './cellOperations.js'; @@ -243,8 +242,11 @@ registerAction2(class ExecuteNotebookAction extends NotebookAction { renderAllMarkdownCells(context); const editorService = accessor.get(IEditorService); - const editor = editorService.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE).find( - editor => editor.editor instanceof NotebookEditorInput && editor.editor.viewType === context.notebookEditor.textModel.viewType && editor.editor.resource.toString() === context.notebookEditor.textModel.uri.toString()); + const editor = editorService.findEditors({ + resource: context.notebookEditor.textModel.uri, + typeId: NotebookEditorInput.ID, + editorId: context.notebookEditor.textModel.viewType + }).at(0); const editorGroupService = accessor.get(IEditorGroupsService); if (editor) { diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 18b79251200..57ae575b1be 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -861,7 +861,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { else { const result: IEditorIdentifier[] = []; - for (const group of this.editorGroupsContainer.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) { + for (const group of this.editorGroupsContainer.getGroups(options?.order === EditorsOrder.SEQUENTIAL ? GroupsOrder.GRID_APPEARANCE : GroupsOrder.MOST_RECENTLY_ACTIVE)) { const editors: EditorInput[] = []; // Resource provided: result is an array diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 0bed762abec..767a8628adc 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -341,7 +341,7 @@ export interface IEditorService { /** * Save the provided list of editors. */ - save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise; + save(editors: IEditorIdentifier | readonly IEditorIdentifier[], options?: ISaveEditorsOptions): Promise; /** * Save all editors. @@ -353,7 +353,7 @@ export interface IEditorService { * * @returns `true` if all editors reverted and `false` otherwise. */ - revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise; + revert(editors: IEditorIdentifier | readonly IEditorIdentifier[], options?: IRevertOptions): Promise; /** * Reverts all editors. From 7774f735cda6b94eae59dd5df3eead3a6dcf476f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 08:56:45 +0200 Subject: [PATCH 049/236] fix https://github.com/microsoft/vscode/issues/247849 (#250803) --- src/vs/base/common/arrays.ts | 30 +--------- src/vs/base/test/common/arrays.test.ts | 57 ------------------- src/vs/editor/common/codecs/baseToken.ts | 3 +- .../codecs/simpleCodec/simpleDecoder.ts | 3 +- .../chatPromptAttachmentModel.ts | 3 +- .../promptSyntax/service/promptsService.ts | 3 +- .../service/promptsService.test.ts | 5 +- 7 files changed, 7 insertions(+), 97 deletions(-) diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index 0305b5c4524..2f16dbccda4 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -624,35 +624,7 @@ function getActualStartIndex(array: T[], start: number): number { return start < 0 ? Math.max(start + array.length, 0) : Math.min(start, array.length); } -/** - * Utility that helps to pick a property from an object. - * - * ## Examples - * - * ```typescript - * interface IObject = { - * a: number, - * b: string, - * }; - * - * const list: IObject[] = [ - * { a: 1, b: 'foo' }, - * { a: 2, b: 'bar' }, - * ]; - * - * assert.deepStrictEqual( - * list.map(pick('a')), - * [1, 2], - * ); - * ``` - */ -export const pick = ( - key: TKeyName, -) => { - return (obj: TObject): TObject[TKeyName] => { - return obj[key]; - }; -}; + /** * When comparing two values, diff --git a/src/vs/base/test/common/arrays.test.ts b/src/vs/base/test/common/arrays.test.ts index b9a18cffdf2..89d4ab02a1d 100644 --- a/src/vs/base/test/common/arrays.test.ts +++ b/src/vs/base/test/common/arrays.test.ts @@ -6,7 +6,6 @@ import assert from 'assert'; import * as arrays from '../../common/arrays.js'; import * as arraysFind from '../../common/arraysFind.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js'; -import { pick } from '../../common/arrays.js'; suite('Arrays', () => { @@ -400,63 +399,7 @@ suite('Arrays', () => { ); }); - suite('pick', () => { - suite('object', () => { - test('numbers', () => { - const array = [{ v: 3, foo: 'a' }, { v: 5, foo: 'b' }, { v: 2, foo: 'c' }, { v: 2, foo: 'd' }, { v: 17, bar: '1' }, { v: -100, baz: '10' }]; - assert.deepStrictEqual( - array.map(pick('v')), - [3, 5, 2, 2, 17, -100], - ); - }); - - test('strings', () => { - const array = [{ v: 3, foo: 'a' }, { v: 5, foo: 'b' }, { v: 2, foo: 'c' }, { v: 2, foo: 'd' }, { v: 17, bar: '1' }, { v: -100, baz: '10' }, { foo: '12' }]; - - assert.deepStrictEqual( - array.map(pick('foo')), - ['a', 'b', 'c', 'd', undefined, undefined, '12'], - ); - }); - - test('booleans', () => { - const array = [{ v: 3, foo: 'a' }, { v: 5, foo: 'b' }, { v: 2, foo: 'c' }, { v: 2, foo: 'd' }, { v: 17, bar: true }, { v: -100, bar: false }, { bar: false }]; - - assert.deepStrictEqual( - array.map(pick('bar')), - [undefined, undefined, undefined, undefined, true, false, false], - ); - }); - - test('objects', () => { - const array = [{ v: { test: 12 } }, { v: { test: 24 } }, {}, { v: { test: 17892 } }]; - - assert.deepStrictEqual( - array.map(pick('v')), - [{ test: 12 }, { test: 24 }, undefined, { test: 17892 }], - ); - }); - - test('mixed', () => { - const array = [{ v: { test: 104 } }, { v: 2 }, {}, { v: '24' }, { v: null }]; - - assert.deepStrictEqual( - array.map(pick('v')), - [{ test: 104 }, 2, undefined, '24', null], - ); - }); - }); - - test('string', () => { - const array = ['haallo', 'there', ':wave:', '!']; - - assert.deepStrictEqual( - array.map(pick('length')), - [6, 5, 6, 1], - ); - }); - }); suite('ArrayQueue', () => { suite('takeWhile/takeFromEndWhile', () => { diff --git a/src/vs/editor/common/codecs/baseToken.ts b/src/vs/editor/common/codecs/baseToken.ts index 72f1d491458..7f4e138bb36 100644 --- a/src/vs/editor/common/codecs/baseToken.ts +++ b/src/vs/editor/common/codecs/baseToken.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { pick } from '../../../base/common/arrays.js'; import { assert } from '../../../base/common/assert.js'; import { IRange, Range } from '../../../editor/common/core/range.js'; @@ -90,7 +89,7 @@ export abstract class BaseToken { tokens: readonly BaseToken[], delimiter: string = '', ): string { - return tokens.map(pick('text')).join(delimiter); + return tokens.map(token => token.text).join(delimiter); } /** diff --git a/src/vs/editor/common/codecs/simpleCodec/simpleDecoder.ts b/src/vs/editor/common/codecs/simpleCodec/simpleDecoder.ts index 0624095fa74..aad7e03586f 100644 --- a/src/vs/editor/common/codecs/simpleCodec/simpleDecoder.ts +++ b/src/vs/editor/common/codecs/simpleCodec/simpleDecoder.ts @@ -38,7 +38,6 @@ import { LeftAngleBracket, RightAngleBracket, } from './tokens/index.js'; -import { pick } from '../../../../base/common/arrays.js'; import { ISimpleTokenClass, SimpleToken } from './tokens/simpleToken.js'; /** @@ -71,7 +70,7 @@ export const WELL_KNOWN_TOKENS: readonly ISimpleTokenClass[] = Obj * the {@link LinesDecoder} which emits {@link Line} tokens without them. */ const WORD_STOP_CHARACTERS: readonly string[] = Object.freeze( - WELL_KNOWN_TOKENS.map(pick('symbol')), + WELL_KNOWN_TOKENS.map(token => token.symbol), ); /** diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts index c56f404de0f..28b4f61e623 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from '../../../../../base/common/uri.js'; -import { pick } from '../../../../../base/common/arrays.js'; import { Emitter } from '../../../../../base/common/event.js'; import { PromptParser } from '../../common/promptSyntax/parsers/promptParser.js'; import { BasePromptParser } from '../../common/promptSyntax/parsers/basePromptParser.js'; @@ -51,7 +50,7 @@ export class ChatPromptAttachmentModel extends ObservableDisposable { // otherwise return `URI` for the main reference and // all valid child `URI` references it may contain return [ - ...reference.allValidReferences.map(pick('uri')), + ...reference.allValidReferences.map(ref => ref.uri), reference.uri, ]; } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 75baed4e1eb..6ceecda1415 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -8,7 +8,6 @@ import { localize } from '../../../../../../nls.js'; import { PROMPT_LANGUAGE_ID } from '../constants.js'; import { PromptParser } from '../parsers/promptParser.js'; import { match, splitGlobAware } from '../../../../../../base/common/glob.js'; -import { pick } from '../../../../../../base/common/arrays.js'; import { type URI } from '../../../../../../base/common/uri.js'; import { type IPromptFileReference } from '../parsers/types.js'; import { assert } from '../../../../../../base/common/assert.js'; @@ -252,7 +251,7 @@ export class PromptsService extends Disposable implements IPromptsService { } const instructions = await this.getAllMetadata( - instructionFiles.map(pick('uri')), + instructionFiles.map(file => file.uri), ); const foundFiles = new ResourceSet(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts index 4e8eb7333f6..b2d3a409e9d 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts @@ -7,7 +7,6 @@ import assert from 'assert'; import * as sinon from 'sinon'; import { URI } from '../../../../../../../base/common/uri.js'; import { MockFilesystem } from '../testUtils/mockFilesystem.js'; -import { pick } from '../../../../../../../base/common/arrays.js'; import { Schemas } from '../../../../../../../base/common/network.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; import { assertDefined } from '../../../../../../../base/common/types.js'; @@ -874,7 +873,7 @@ suite('PromptsService', () => { ]); assert.deepStrictEqual( - instructions.map(pick('path')), + instructions.map(i => i.path), [ // local instructions URI.joinPath(rootFolderUri, '.github/prompts/file1.instructions.md').path, @@ -1055,7 +1054,7 @@ suite('PromptsService', () => { ]); assert.deepStrictEqual( - instructions.map(pick('path')), + instructions.map(i => i.path), [ // local instructions URI.joinPath(rootFolderUri, '.github/prompts/file1.instructions.md').path, From 5535b4579f8258e8aa8d412cf9ed8e331766b0bd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 6 Jun 2025 08:56:50 +0200 Subject: [PATCH 050/236] debt - more powerful layer checker with TS support (#250752) --- build/{lib => checker}/layersChecker.js | 4 +-- build/{lib => checker}/layersChecker.ts | 4 +-- build/checker/tsconfig.desktop.json | 21 ++++++++++++++ build/checker/tsconfig.server.json | 26 +++++++++++++++++ build/checker/tsconfig.web.json | 28 +++++++++++++++++++ build/filters.js | 1 + package.json | 2 +- src/typings/base-common.d.ts | 9 ++++++ .../files/browser/webFileSystemAccess.ts | 1 - .../api/common/extHostExtensionService.ts | 3 +- .../api/node/extensionHostProcess.ts | 6 ++-- 11 files changed, 94 insertions(+), 11 deletions(-) rename build/{lib => checker}/layersChecker.js (95%) rename build/{lib => checker}/layersChecker.ts (93%) create mode 100644 build/checker/tsconfig.desktop.json create mode 100644 build/checker/tsconfig.server.json create mode 100644 build/checker/tsconfig.web.json diff --git a/build/lib/layersChecker.js b/build/checker/layersChecker.js similarity index 95% rename from build/lib/layersChecker.js rename to build/checker/layersChecker.js index f916e9bf5b2..3d149c5248b 100644 --- a/build/lib/layersChecker.js +++ b/build/checker/layersChecker.js @@ -279,7 +279,7 @@ function checkFile(program, sourceFile, rule) { } if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); + console.log(`[build/checker/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; } @@ -303,7 +303,7 @@ function checkFile(program, sourceFile, rule) { for (const disallowedDefinition of rule.disallowedDefinitions) { if (definitionFileName.indexOf(disallowedDefinition) >= 0) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); + console.log(`[build/checker/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; } diff --git a/build/lib/layersChecker.ts b/build/checker/layersChecker.ts similarity index 93% rename from build/lib/layersChecker.ts rename to build/checker/layersChecker.ts index df3a3ef0e63..ea70cd91443 100644 --- a/build/lib/layersChecker.ts +++ b/build/checker/layersChecker.ts @@ -318,7 +318,7 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); + console.log(`[build/checker/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; @@ -345,7 +345,7 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) if (definitionFileName.indexOf(disallowedDefinition) >= 0) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); + console.log(`[build/checker/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; diff --git a/build/checker/tsconfig.desktop.json b/build/checker/tsconfig.desktop.json new file mode 100644 index 00000000000..8135902d99e --- /dev/null +++ b/build/checker/tsconfig.desktop.json @@ -0,0 +1,21 @@ +{ + "extends": "./tsconfig.web.json", + "include": [ + "../../src/**/common/**/*.ts", + "../../src/**/browser/**/*.ts", + "../../src/**/electron-sandbox/**/*.ts", + "../../src/typings/*.d.ts", + "../../src/vs/monaco.d.ts", + "../../src/vscode-dts/vscode.proposed.*.d.ts", + "../../src/vscode-dts/vscode.d.ts", + "../../node_modules/@webgpu/types/dist/index.d.ts", + "../../node_modules/@types/trusted-types/index.d.ts", + "../../node_modules/@types/wicg-file-system-access/index.d.ts" + ], + "exclude": [ + "../../src/**/test/**", + "../../src/**/fixtures/**", + "../../src/vs/base/parts/sandbox/electron-sandbox/preload.ts", // Preload scripts for Electron sandbox + "../../src/vs/base/parts/sandbox/electron-sandbox/preload-aux.ts" // have limited access to node.js APIs + ] +} diff --git a/build/checker/tsconfig.server.json b/build/checker/tsconfig.server.json new file mode 100644 index 00000000000..0b2a09b83f6 --- /dev/null +++ b/build/checker/tsconfig.server.json @@ -0,0 +1,26 @@ +{ + "extends": "../../src/tsconfig.base.json", + "compilerOptions": { + "lib": [ + "ES2022" + ], + "types": [ + "node" + ], + "noEmit": true, + "skipLibCheck": true + }, + "include": [ + "../../src/**/common/**/*.ts", + "../../src/**/node/**/*.ts", + "../../src/typings/*.d.ts", + "../../src/vs/monaco.d.ts", + "../../src/vscode-dts/vscode.proposed.*.d.ts", + "../../src/vscode-dts/vscode.d.ts", + "../../node_modules/@types/trusted-types/index.d.ts", + ], + "exclude": [ + "../../src/**/test/**", + "../../src/**/fixtures/**" + ] +} diff --git a/build/checker/tsconfig.web.json b/build/checker/tsconfig.web.json new file mode 100644 index 00000000000..098a4ffbb1e --- /dev/null +++ b/build/checker/tsconfig.web.json @@ -0,0 +1,28 @@ +{ + "extends": "../../src/tsconfig.base.json", + "compilerOptions": { + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "types": [], + "noEmit": true, + "skipLibCheck": true + }, + "include": [ + "../../src/**/common/**/*.ts", + "../../src/**/browser/**/*.ts", + "../../src/typings/*.d.ts", + "../../src/vs/monaco.d.ts", + "../../src/vscode-dts/vscode.proposed.*.d.ts", + "../../src/vscode-dts/vscode.d.ts", + "../../node_modules/@webgpu/types/dist/index.d.ts", + "../../node_modules/@types/trusted-types/index.d.ts", + "../../node_modules/@types/wicg-file-system-access/index.d.ts" + ], + "exclude": [ + "../../src/**/test/**", + "../../src/**/fixtures/**" + ] +} diff --git a/build/filters.js b/build/filters.js index 4f18bf6607a..035bd3ddb91 100644 --- a/build/filters.js +++ b/build/filters.js @@ -103,6 +103,7 @@ module.exports.indentationFilter = [ '!extensions/vscode-api-tests/testWorkspace2/**', '!build/monaco/**', '!build/win32/**', + '!build/checker/**', // except multiple specific files '!**/package.json', diff --git a/package.json b/package.json index 50a6e24cddc..6594dc35c71 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", "tsec-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.tsec.json", "vscode-dts-compile-check": "tsc -p src/tsconfig.vscode-dts.json && tsc -p src/tsconfig.vscode-proposed-dts.json", - "valid-layers-check": "node build/lib/layersChecker.js", + "valid-layers-check": "node build/checker/layersChecker.js && tsc -p build/checker/tsconfig.web.json && tsc -p build/checker/tsconfig.desktop.json && tsc -p build/checker/tsconfig.server.json", "define-class-fields-check": "node build/lib/propertyInitOrderChecker.js && tsc -p src/tsconfig.defineClassFields.json", "update-distro": "node build/npm/update-distro.mjs", "web": "echo 'npm run web' is replaced by './scripts/code-server' or './scripts/code-web'", diff --git a/src/typings/base-common.d.ts b/src/typings/base-common.d.ts index 189c1149567..9f0035b43b9 100644 --- a/src/typings/base-common.d.ts +++ b/src/typings/base-common.d.ts @@ -17,6 +17,7 @@ declare global { function requestIdleCallback(callback: (args: IdleDeadline) => void, options?: { timeout: number }): number; function cancelIdleCallback(handle: number): void; + // --- timeout / interval (available in all contexts, but different signatures in node.js vs web) interface TimeoutHandle {readonly _: never; /* this is a trick that seems needed to prevent direct number assignment */} @@ -26,6 +27,14 @@ declare global { function setInterval(callback: (...args: any[]) => void, delay?: number, ...args: any[]): Timeout; function clearInterval(timeout: Timeout | undefined): void; + + + // --- error + + interface ErrorConstructor { + captureStackTrace(targetObject: object, constructorOpt?: Function): void; + stackTraceLimit: number; + } } export { } diff --git a/src/vs/platform/files/browser/webFileSystemAccess.ts b/src/vs/platform/files/browser/webFileSystemAccess.ts index 24a91eb795f..f5e90b78a00 100644 --- a/src/vs/platform/files/browser/webFileSystemAccess.ts +++ b/src/vs/platform/files/browser/webFileSystemAccess.ts @@ -36,7 +36,6 @@ export namespace WebFileSystemAccess { } } -// TODO@bpasero adopt official types of FileSystemObserver export namespace WebFileSystemObserver { export function supported(obj: any & Window): boolean { diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index dbaf5bbb595..a439fdc055a 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -593,8 +593,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme try { activationTimesBuilder.activateCallStart(); logService.trace(`ExtensionService#_callActivateOptional ${extensionId.value}`); - const scope = typeof global === 'object' ? global : self; // `global` is nodejs while `self` is for workers - const activateResult: Promise = extensionModule.activate.apply(scope, [context]); + const activateResult: Promise = extensionModule.activate.apply(globalThis, [context]); activationTimesBuilder.activateCallStop(); activationTimesBuilder.activateResolveStart(); diff --git a/src/vs/workbench/api/node/extensionHostProcess.ts b/src/vs/workbench/api/node/extensionHostProcess.ts index 38239ddfb62..079bc9989a4 100644 --- a/src/vs/workbench/api/node/extensionHostProcess.ts +++ b/src/vs/workbench/api/node/extensionHostProcess.ts @@ -17,7 +17,7 @@ import { Promises } from '../../../base/node/pfs.js'; import { IMessagePassingProtocol } from '../../../base/parts/ipc/common/ipc.js'; import { BufferedEmitter, PersistentProtocol, ProtocolConstants } from '../../../base/parts/ipc/common/ipc.net.js'; import { NodeSocket, WebSocketNodeSocket } from '../../../base/parts/ipc/node/ipc.net.js'; -import type { MessagePortMain } from '../../../base/parts/sandbox/node/electronTypes.js'; +import type { MessagePortMain, MessageEvent as UtilityMessageEvent } from '../../../base/parts/sandbox/node/electronTypes.js'; import { boolean } from '../../../editor/common/config/editorOptions.js'; import product from '../../../platform/product/common/product.js'; import { ExtensionHostMain, IExitFn } from '../common/extensionHostMain.js'; @@ -92,7 +92,7 @@ function patchProcess(allowExit: boolean) { } as (code?: number) => never; // override Electron's process.crash() method - process.crash = function () { + (process as any /* bypass layer checker */).crash = function () { const err = new Error('An extension called process.crash() and this was prevented.'); console.warn(err.stack); }; @@ -167,7 +167,7 @@ function _createExtHostProtocol(): Promise { }); }; - process.parentPort.on('message', (e: Electron.MessageEvent) => withPorts(e.ports)); + (process as unknown as { parentPort: { on: (event: 'message', listener: (messageEvent: UtilityMessageEvent) => void) => void } }).parentPort.on('message', (e: UtilityMessageEvent) => withPorts(e.ports)); }); } else if (extHostConnection.type === ExtHostConnectionType.Socket) { From 1e0fceced0c6edd1c3ccb803ed21cc240c950027 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 6 Jun 2025 09:02:54 +0200 Subject: [PATCH 051/236] SCM - disable variable line height in the input field (#250802) --- src/vs/workbench/contrib/scm/browser/scmViewPane.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index 1b4c2a31c44..56a5397e985 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -1561,6 +1561,7 @@ class SCMInputWidgetEditorOptions { return { ...getSimpleEditorOptions(this.configurationService), ...this.getEditorOptions(), + allowVariableLineHeights: false, dragAndDrop: true, dropIntoEditor: { enabled: true }, formatOnType: true, From ab6d98e59979694408744de691bd64b540ad8f0b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 00:11:43 -0700 Subject: [PATCH 052/236] Fix extraction of tab title name (#250621) * Fix extraction of tab title name Fixes microsoft/vscode-internalbacklog#5499 * Engineering - update agent pool --------- Co-authored-by: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> --- build/azure-pipelines/product-build.yml | 2 +- test/automation/src/terminal.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index a6116d8c05c..12e7b05d4ba 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -337,7 +337,7 @@ extends: - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true),eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true),eq(parameters.VSCODE_BUILD_LINUX_ARM64, true),eq(parameters.VSCODE_BUILD_ALPINE, true),eq(parameters.VSCODE_BUILD_ALPINE_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}: - CompileCLI pool: - name: 1es-windows-2019-x64 + name: 1es-windows-2022-x64 os: windows jobs: - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: diff --git a/test/automation/src/terminal.ts b/test/automation/src/terminal.ts index 214ca824f7c..af2a152fb81 100644 --- a/test/automation/src/terminal.ts +++ b/test/automation/src/terminal.ts @@ -17,6 +17,7 @@ export enum Selector { Xterm = `#terminal .terminal-wrapper`, XtermEditor = `.editor-instance .terminal-wrapper`, TabsEntry = '.terminal-tabs-entry', + Name = '.label-name', Description = '.label-description', XtermFocused = '.terminal.xterm.focus', PlusButton = '.codicon-plus', @@ -212,7 +213,7 @@ export class Terminal { const tabCount = (await this.code.waitForElements(Selector.Tabs, true)).length; const groups: TerminalGroup[] = []; for (let i = 0; i < tabCount; i++) { - const title = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry}`, e => e?.textContent?.length ? e?.textContent?.length > 1 : false); + const title = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry} ${Selector.Name}`, e => e?.textContent?.length ? e?.textContent?.length > 1 : false); const description: IElement | undefined = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry} ${Selector.Description}`, () => true); const label: TerminalLabel = { @@ -237,7 +238,7 @@ export class Terminal { private async assertTabExpected(selector?: string, listIndex?: number, nameRegex?: RegExp, icon?: string, color?: string, description?: string): Promise { if (listIndex) { if (nameRegex) { - await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry}`, entry => !!entry && !!entry?.textContent.match(nameRegex)); + await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry} ${Selector.Name}`, entry => !!entry && !!entry?.textContent.match(nameRegex)); if (description) { await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry} ${Selector.Description}`, e => !!e && e.textContent === description); } From 0a63b0345d64915b48574376e919710a657ec9ab Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 10:15:44 +0200 Subject: [PATCH 053/236] fix https://github.com/microsoft/vscode/issues/248686 (#250810) * replace `wait` util with `timeout` usage * remove `waitRandom` * use `mock` over `mockObject` duplicate --- src/vs/base/test/common/logTime.test.ts | 8 +- src/vs/base/test/common/mockObject.test.ts | 101 ------------------ src/vs/base/test/common/objectCache.test.ts | 4 +- .../test/common/observableDisposable.test.ts | 30 +++--- src/vs/base/test/common/testUtils.ts | 48 --------- .../filePromptContentsProvider.test.ts | 19 ++-- .../promptSyntax/promptFileReference.test.ts | 5 +- .../service/promptsService.test.ts | 11 +- .../promptSyntax/testUtils/mockFilesystem.ts | 4 +- .../utils/promptFilesLocator.test.ts | 18 ++-- 10 files changed, 51 insertions(+), 197 deletions(-) delete mode 100644 src/vs/base/test/common/mockObject.test.ts diff --git a/src/vs/base/test/common/logTime.test.ts b/src/vs/base/test/common/logTime.test.ts index 2e2f71127d9..18f7488e4ad 100644 --- a/src/vs/base/test/common/logTime.test.ts +++ b/src/vs/base/test/common/logTime.test.ts @@ -5,7 +5,7 @@ import assert from 'assert'; import * as sinon from 'sinon'; -import { waitRandom } from './testUtils.js'; +import { timeout } from '../../common/async.js'; import { randomInt } from '../../common/numbers.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js'; import { logExecutionTime, logTime } from '../../common/decorators/logTime.js'; @@ -46,7 +46,7 @@ suite('logTime', () => { @logTime() public async myAsyncMethod(): Promise { - await waitRandom(10); + await timeout(10); return this.returnValue; } @@ -146,7 +146,7 @@ suite('logTime', () => { @logTime() public async myAsyncMethod(): Promise { - await waitRandom(10); + await timeout(10); return this.returnValue; } @@ -196,7 +196,7 @@ suite('logTime', () => { const resultPromise = logExecutionTime( 'my-async-function', async () => { - await waitRandom(10); + await timeout(10); return expectedReturnValue; }, diff --git a/src/vs/base/test/common/mockObject.test.ts b/src/vs/base/test/common/mockObject.test.ts deleted file mode 100644 index eff91bb91a4..00000000000 --- a/src/vs/base/test/common/mockObject.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import assert from 'assert'; -import { typeCheck } from '../../common/types.js'; -import { randomInt } from '../../common/numbers.js'; -import { mockObject, randomBoolean } from './testUtils.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js'; - - -suite('mockObject', () => { - ensureNoDisposablesAreLeakedInTestSuite(); - - test('• overrides properties and functions', () => { - interface ITestObject { - foo: string; - bar: string; - readonly baz: number; - someMethod(arg: boolean): string; - anotherMethod(arg: number): boolean; - } - - const mock = mockObject({ - bar: 'oh hi!', - baz: 42, - anotherMethod(arg: number): boolean { - return isNaN(arg); - }, - }); - - typeCheck(mock); - - assert.strictEqual( - mock.bar, - 'oh hi!', - 'bar should be overridden', - ); - - assert.strictEqual( - mock.baz, - 42, - 'baz should be overridden', - ); - - assert( - !(mock.anotherMethod(randomInt(100))), - 'Must execute overridden method correctly 1.', - ); - - assert( - mock.anotherMethod(NaN), - 'Must execute overridden method correctly 2.', - ); - - assert.throws(() => { - // property is not overridden so must throw - // eslint-disable-next-line local/code-no-unused-expressions - mock.foo; - }); - - assert.throws(() => { - // function is not overridden so must throw - mock.someMethod(randomBoolean()); - }); - }); - - test('• immutability of the overrides object', () => { - interface ITestObject { - foo: string; - bar: string; - readonly baz: number; - someMethod(arg: boolean): string; - anotherMethod(arg: number): boolean; - } - - const overrides: Partial = { - baz: 4, - }; - const mock = mockObject(overrides); - typeCheck(mock); - - assert.strictEqual( - mock.baz, - 4, - 'baz should be overridden', - ); - - // overrides object must be immutable - assert.throws(() => { - overrides.foo = 'test'; - }); - - assert.throws(() => { - overrides.someMethod = (arg: boolean) => { - return `${arg}__${arg}`; - }; - }); - }); -}); diff --git a/src/vs/base/test/common/objectCache.test.ts b/src/vs/base/test/common/objectCache.test.ts index fb80b91c49e..0e0053c0dab 100644 --- a/src/vs/base/test/common/objectCache.test.ts +++ b/src/vs/base/test/common/objectCache.test.ts @@ -6,7 +6,7 @@ import assert from 'assert'; import { spy } from 'sinon'; import { ObjectCache } from '../../common/objectCache.js'; -import { wait } from '../../../base/test/common/testUtils.js'; +import { timeout } from '../../../base/common/async.js'; import { ObservableDisposable } from '../../common/observableDisposable.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../base/test/common/utils.js'; @@ -126,7 +126,7 @@ suite('ObjectCache', function () { obj3.dispose(); // the object is removed from the cache asynchronously // so add a small delay to ensure the object is removed - await wait(5); + await timeout(5); const obj5 = cache.get(key1); assert( diff --git a/src/vs/base/test/common/observableDisposable.test.ts b/src/vs/base/test/common/observableDisposable.test.ts index afc90077fd8..06a820cbc90 100644 --- a/src/vs/base/test/common/observableDisposable.test.ts +++ b/src/vs/base/test/common/observableDisposable.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; import { spy } from 'sinon'; -import { wait, waitRandom } from './testUtils.js'; +import { timeout } from '../../common/async.js'; import { randomInt } from '../../common/numbers.js'; import { Disposable, IDisposable } from '../../common/lifecycle.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js'; @@ -62,7 +62,7 @@ suite('ObservableDisposable', () => { '`onDispose` callback must not be called yet.', ); - await waitRandom(10); + await timeout(10); assert( onDisposeSpy.notCalled, @@ -71,7 +71,7 @@ suite('ObservableDisposable', () => { // dispose object and wait for the event to be fired/received object.dispose(); - await wait(1); + await timeout(1); /** * Validate that the callback was called. @@ -93,7 +93,7 @@ suite('ObservableDisposable', () => { object.dispose(); object.dispose(); - await waitRandom(10, 5); + await timeout(10); object.dispose(); assert( @@ -115,23 +115,23 @@ suite('ObservableDisposable', () => { // dispose object and wait for the event to be fired/received object.dispose(); - await wait(10); + await timeout(10); const onDisposeSpy = spy(); disposables.add(object.onDispose(onDisposeSpy)); - await wait(10); + await timeout(10); assert( onDisposeSpy.calledOnce, '`onDispose` callback must be called immediately.', ); - await waitRandom(10, 5); + await timeout(10); disposables.add(object.onDispose(onDisposeSpy)); - await wait(10); + await timeout(10); assert( onDisposeSpy.calledTwice, @@ -140,7 +140,7 @@ suite('ObservableDisposable', () => { // dispose object and wait for the event to be fired/received object.dispose(); - await wait(10); + await timeout(10); assert( onDisposeSpy.calledTwice, @@ -301,7 +301,7 @@ suite('ObservableDisposable', () => { object.assertNotDisposed('Object must not be disposed.'); }); - await waitRandom(10); + await timeout(10); assert.doesNotThrow(() => { object.assertNotDisposed('Object must not be disposed.'); @@ -309,13 +309,13 @@ suite('ObservableDisposable', () => { // dispose object and wait for the event to be fired/received object.dispose(); - await wait(1); + await timeout(1); assert.throws(() => { object.assertNotDisposed('Object must not be disposed.'); }); - await waitRandom(10); + await timeout(10); assert.throws(() => { object.assertNotDisposed('Object must not be disposed.'); @@ -335,7 +335,7 @@ suite('ObservableDisposable', () => { ); }); - await waitRandom(10); + await timeout(10); assert.doesNotThrow(() => { assertNotDisposed( @@ -346,7 +346,7 @@ suite('ObservableDisposable', () => { // dispose object and wait for the event to be fired/received object.dispose(); - await wait(1); + await timeout(1); assert.throws(() => { assertNotDisposed( @@ -355,7 +355,7 @@ suite('ObservableDisposable', () => { ); }); - await waitRandom(10); + await timeout(10); assert.throws(() => { assertNotDisposed( diff --git a/src/vs/base/test/common/testUtils.ts b/src/vs/base/test/common/testUtils.ts index cc80cf68514..91011c41299 100644 --- a/src/vs/base/test/common/testUtils.ts +++ b/src/vs/base/test/common/testUtils.ts @@ -3,9 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assert } from '../../common/assert.js'; -import { isOneOf } from '../../common/types.js'; -import { randomInt } from '../../common/numbers.js'; export function flakySuite(title: string, fn: () => void) /* Suite */ { return suite(title, function () { @@ -22,22 +19,6 @@ export function flakySuite(title: string, fn: () => void) /* Suite */ { }); } -/** - * @deprecated use `async#timeout` instead - */ -export const wait = (ms: number): Promise => { - return new Promise(resolve => setTimeout(resolve, ms)); -}; - -/** - * Helper function that allows to await for a random amount of time. - * @param maxMs The `maximum` amount of time to wait, in milliseconds. - * @param minMs [`optional`] The `minimum` amount of time to wait, in milliseconds. - */ -export const waitRandom = (maxMs: number, minMs: number = 0): Promise => { - return wait(randomInt(maxMs, minMs)); -}; - /** * (pseudo)Random boolean generator. * @@ -51,32 +32,3 @@ export const waitRandom = (maxMs: number, minMs: number = 0): Promise => { export const randomBoolean = (): boolean => { return Math.random() > 0.5; }; - -/** - * @deprecated use `mock.ts#mock` instead - */ -export function mockObject( - overrides: Partial, -): TObject { - // ensure that the overrides object cannot be modified afterward - overrides = Object.freeze(overrides); - - const keys = Object.keys(overrides) as (keyof (typeof overrides))[]; - const service = new Proxy( - {}, - { - get: (_target, key: string | number | Symbol) => { - // sanity check for the provided `key` - assert( - isOneOf(key, keys), - `The '${key}' is not mocked.`, - ); - - return overrides[key]; - }, - }); - - // note! it's ok to `as TObject` here, because of - // the runtime checks in the `Proxy` getter - return service as (typeof overrides) as TObject; -} diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts index 8600c57af5b..88218fd26d4 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts @@ -13,7 +13,8 @@ import { ReadableStream } from '../../../../../../../base/common/stream.js'; import { NotPromptFile } from '../../../../common/promptFileReferenceErrors.js'; import { IFileService } from '../../../../../../../platform/files/common/files.js'; import { FileService } from '../../../../../../../platform/files/common/fileService.js'; -import { randomBoolean, wait } from '../../../../../../../base/test/common/testUtils.js'; +import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; +import { timeout } from '../../../../../../../base/common/async.js'; import { NullPolicyService } from '../../../../../../../platform/policy/common/policy.js'; import { Line } from '../../../../../../../editor/common/codecs/linesCodec/tokens/line.js'; import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; @@ -64,7 +65,7 @@ suite('FilePromptContentsProvider', () => { await fileService.del(fileUri); } await fileService.writeFile(fileUri, VSBuffer.fromString('Hello, world!')); - await wait(5); + await timeout(5); const contentsProvider = testDisposables.add(instantiationService.createInstance( FilePromptContentProvider, @@ -78,7 +79,7 @@ suite('FilePromptContentsProvider', () => { })); contentsProvider.start(); - await wait(CONTENT_CHANGED_TIMEOUT); + await timeout(CONTENT_CHANGED_TIMEOUT); assertDefined( streamOrError, @@ -122,7 +123,7 @@ suite('FilePromptContentsProvider', () => { await fileService.del(fileUri); } await fileService.writeFile(fileUri, VSBuffer.fromString('Hello, world!')); - await wait(5); + await timeout(5); const contentsProvider = testDisposables.add(instantiationService.createInstance( FilePromptContentProvider, @@ -136,7 +137,7 @@ suite('FilePromptContentsProvider', () => { })); contentsProvider.start(); - await wait(CONTENT_CHANGED_TIMEOUT); + await timeout(CONTENT_CHANGED_TIMEOUT); assertDefined( streamOrError, @@ -178,7 +179,7 @@ suite('FilePromptContentsProvider', () => { await fileService.del(fileUri); } await fileService.writeFile(fileUri, VSBuffer.fromString('Hello, world!')); - await wait(5); + await timeout(5); const contentsProvider = testDisposables.add(instantiationService.createInstance( FilePromptContentProvider, @@ -192,7 +193,7 @@ suite('FilePromptContentsProvider', () => { })); contentsProvider.start(); - await wait(CONTENT_CHANGED_TIMEOUT); + await timeout(CONTENT_CHANGED_TIMEOUT); assertDefined( streamOrError, @@ -218,7 +219,7 @@ suite('FilePromptContentsProvider', () => { await fileService.del(fileUri); } await fileService.writeFile(fileUri, VSBuffer.fromString('Hello, world!')); - await wait(5); + await timeout(5); const contentsProvider = testDisposables.add(instantiationService.createInstance( FilePromptContentProvider, @@ -232,7 +233,7 @@ suite('FilePromptContentsProvider', () => { })); contentsProvider.start(); - await wait(CONTENT_CHANGED_TIMEOUT); + await timeout(CONTENT_CHANGED_TIMEOUT); assertDefined( streamOrError, diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts index f769d9d2aee..d088ebe6178 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts @@ -20,7 +20,8 @@ import { ILanguageService } from '../../../../../../editor/common/languages/lang import { ILogService, NullLogService } from '../../../../../../platform/log/common/log.js'; import { FileReference } from '../../../common/promptSyntax/codecs/tokens/fileReference.js'; import { FilePromptParser } from '../../../common/promptSyntax/parsers/filePromptParser.js'; -import { waitRandom, randomBoolean } from '../../../../../../base/test/common/testUtils.js'; +import { timeout } from '../../../../../../base/common/async.js'; +import { randomBoolean } from '../../../../../../base/test/common/testUtils.js'; import { getPromptFileType, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; @@ -97,7 +98,7 @@ class TestPromptFileReference extends Disposable { // randomly test with and without delay to ensure that the file // reference resolution is not susceptible to race conditions if (randomBoolean()) { - await waitRandom(5); + await timeout(5); } // start resolving references for the specified root file diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts index b2d3a409e9d..65460a234af 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts @@ -19,7 +19,8 @@ import { createTextModel } from '../../../../../../../editor/test/common/testTex import { PromptsService } from '../../../../common/promptSyntax/service/promptsService.js'; import { ILanguageService } from '../../../../../../../editor/common/languages/language.js'; import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; -import { randomBoolean, waitRandom } from '../../../../../../../base/test/common/testUtils.js'; +import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; +import { timeout } from '../../../../../../../base/common/async.js'; import { TextModelPromptParser } from '../../../../common/promptSyntax/parsers/textModelPromptParser.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'; @@ -189,7 +190,7 @@ suite('PromptsService', () => { ); // wait for some random amount of time - await waitRandom(5); + await timeout(5); /** * Next, get parser for the same exact model and @@ -222,7 +223,7 @@ suite('PromptsService', () => { )); // wait for some random amount of time - await waitRandom(5); + await timeout(5); const parser2 = service.getSyntaxParserFor(model2); @@ -305,7 +306,7 @@ suite('PromptsService', () => { ); // wait for some random amount of time - await waitRandom(5); + await timeout(5); /** * Dispose the first parser, perform basic validations, and confirm @@ -377,7 +378,7 @@ suite('PromptsService', () => { ); // wait for some random amount of time - await waitRandom(5); + await timeout(5); /** * This time dispose model of the second parser instead of diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.ts index 09d00b4c1dc..dc0a44da5c7 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.ts @@ -6,7 +6,7 @@ import { URI } from '../../../../../../../base/common/uri.js'; import { assert } from '../../../../../../../base/common/assert.js'; import { VSBuffer } from '../../../../../../../base/common/buffer.js'; -import { wait } from '../../../../../../../base/test/common/testUtils.js'; +import { timeout } from '../../../../../../../base/common/async.js'; import { IFileService } from '../../../../../../../platform/files/common/files.js'; /** @@ -58,7 +58,7 @@ export class MockFilesystem { // wait for the filesystem event to settle before proceeding // this is temporary workaround and should be fixed once we // improve behavior of the `settled()` / `allSettled()` methods - await wait(25); + await timeout(25); return result; } diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts index 86b9a78c99f..e6957fb43be 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts @@ -7,7 +7,6 @@ import assert from 'assert'; import { Schemas } from '../../../../../../../base/common/network.js'; import { basename, relativePath } from '../../../../../../../base/common/resources.js'; import { IMockFolder, MockFilesystem } from '../testUtils/mockFilesystem.js'; -import { mockObject } from '../../../../../../../base/test/common/testUtils.js'; import { IFileService } from '../../../../../../../platform/files/common/files.js'; import { PromptsConfig } from '../../../../../../../platform/prompts/common/config.js'; import { FileService } from '../../../../../../../platform/files/common/fileService.js'; @@ -26,6 +25,7 @@ import { IUserDataProfileService } from '../../../../../../services/userDataProf import { ISearchService, IFileQuery, IFileMatch } from '../../../../../../services/search/common/search.js'; import { URI } from '../../../../../../../base/common/uri.js'; import { match } from '../../../../../../../base/common/glob.js'; +import { mock } from '../../../../../../../base/test/common/mock.js'; /** * Mocked instance of {@link IConfigurationService}. @@ -57,9 +57,9 @@ const mockConfigService = (value: T): IConfigurationService => { const mockWorkspaceService = (folders: IWorkspaceFolder[]): IWorkspaceContextService => { return mockService({ getWorkspace(): IWorkspace { - return mockObject({ - folders, - }); + return new class extends mock() { + override folders = folders; + }; }, getWorkspaceFolder(): IWorkspaceFolder | null { return null; @@ -104,11 +104,11 @@ suite('PromptFilesLocator', () => { const workspaceFolders = workspaceFolderPaths.map((path, index) => { const uri = URI.file(path); - return mockObject({ - uri, - name: basename(uri), - index, - }); + return new class extends mock() { + override uri = uri; + override name = basename(uri); + override index = index; + }; }); instantiationService.stub(IWorkspaceContextService, mockWorkspaceService(workspaceFolders)); instantiationService.stub(IWorkbenchEnvironmentService, {} as IWorkbenchEnvironmentService); From f69a03948e3f5c196191ed2718d3e87a35816f24 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 6 Jun 2025 10:32:05 +0200 Subject: [PATCH 054/236] debt - some assorted changes (#250807) * debt - some assorted fixes * fix ci * remove duplicate dependency --- build/checker/layersChecker.js | 23 -------------------- build/checker/layersChecker.ts | 26 ----------------------- package-lock.json | 3 +-- package.json | 5 ++--- remote/package-lock.json | 12 +++++++---- remote/package.json | 2 +- src/vs/platform/product/common/product.ts | 2 +- 7 files changed, 13 insertions(+), 60 deletions(-) diff --git a/build/checker/layersChecker.js b/build/checker/layersChecker.js index 3d149c5248b..3825d3b4308 100644 --- a/build/checker/layersChecker.js +++ b/build/checker/layersChecker.js @@ -163,20 +163,6 @@ const RULES = [ '@types/node' // no node.js ] }, - // Common: vs/workbench/api/common/extHostExtensionService.ts - { - target: '**/vs/workbench/api/common/extHostExtensionService.ts', - allowedTypes: [ - ...CORE_TYPES, - // Safe access to global - 'global' - ], - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] - }, // Common: vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts { target: '**/vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts', @@ -214,15 +200,6 @@ const RULES = [ '@types/node' // no node.js ] }, - // Browser (editor contrib) - { - target: '**/src/vs/editor/contrib/**', - allowedTypes: CORE_TYPES, - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] - }, // node.js { target: '**/vs/**/node/**', diff --git a/build/checker/layersChecker.ts b/build/checker/layersChecker.ts index ea70cd91443..02d5860066a 100644 --- a/build/checker/layersChecker.ts +++ b/build/checker/layersChecker.ts @@ -172,22 +172,6 @@ const RULES: IRule[] = [ ] }, - // Common: vs/workbench/api/common/extHostExtensionService.ts - { - target: '**/vs/workbench/api/common/extHostExtensionService.ts', - allowedTypes: [ - ...CORE_TYPES, - - // Safe access to global - 'global' - ], - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] - }, - // Common: vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts { target: '**/vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts', @@ -229,16 +213,6 @@ const RULES: IRule[] = [ ] }, - // Browser (editor contrib) - { - target: '**/src/vs/editor/contrib/**', - allowedTypes: CORE_TYPES, - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] - }, - // node.js { target: '**/vs/**/node/**', diff --git a/package-lock.json b/package-lock.json index 50c4dec4b82..7e44da42eb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", "kerberos": "2.1.1", - "minimist": "^1.2.6", + "minimist": "^1.2.8", "native-is-elevated": "0.7.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", @@ -131,7 +131,6 @@ "merge-options": "^1.0.1", "mime": "^1.4.1", "minimatch": "^3.0.4", - "minimist": "^1.2.6", "mocha": "^10.8.2", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/package.json b/package.json index 6594dc35c71..c3170a7fc6d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.102.0", - "distro": "0110618df4664082ca0cb597c5f9bf66aeed2e35", + "distro": "1f9299d1fbccfb501bade57b42c8d343c1e4b5a5", "author": { "name": "Microsoft Corporation" }, @@ -100,7 +100,7 @@ "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", "kerberos": "2.1.1", - "minimist": "^1.2.6", + "minimist": "^1.2.8", "native-is-elevated": "0.7.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", @@ -190,7 +190,6 @@ "merge-options": "^1.0.1", "mime": "^1.4.1", "minimatch": "^3.0.4", - "minimist": "^1.2.6", "mocha": "^10.8.2", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", diff --git a/remote/package-lock.json b/remote/package-lock.json index 55f439fb658..a69a4a75ac4 100644 --- a/remote/package-lock.json +++ b/remote/package-lock.json @@ -35,7 +35,7 @@ "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", "kerberos": "2.1.1", - "minimist": "^1.2.6", + "minimist": "^1.2.8", "native-watchdog": "^1.4.1", "node-pty": "^1.1.0-beta33", "tas-client-umd": "0.2.0", @@ -1041,9 +1041,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp": { "version": "1.0.4", diff --git a/remote/package.json b/remote/package.json index 758dbd9201c..81dfbc01cee 100644 --- a/remote/package.json +++ b/remote/package.json @@ -30,7 +30,7 @@ "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", "kerberos": "2.1.1", - "minimist": "^1.2.6", + "minimist": "^1.2.8", "native-watchdog": "^1.4.1", "node-pty": "^1.1.0-beta33", "tas-client-umd": "0.2.0", diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index d27cdce900f..a299f020c6e 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -60,7 +60,7 @@ else { // Running out of sources if (Object.keys(product).length === 0) { Object.assign(product, { - version: '1.95.0-dev', + version: '1.102.0-dev', nameShort: 'Code - OSS Dev', nameLong: 'Code - OSS Dev', applicationName: 'code-oss', From 478c7cf04ee8d0930b32c6700ff9856ac50193b6 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Sat, 31 May 2025 06:29:14 -0700 Subject: [PATCH 055/236] Fix launch.json reference Signed-off-by: Emmanuel Ferdman --- .devcontainer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 3d1e15e5d55..19a85b4692d 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -99,7 +99,7 @@ Next, let's try debugging. 2. Go to your local VS Code client, and use the **Run / Debug** view to launch the **VS Code** configuration. (Typically the default, so you can likely just press F5). - > **Note:** If launching times out, you can increase the value of `timeout` in the "VS Code", "Attach Main Process", "Attach Extension Host", and "Attach to Shared Process" configurations in [launch.json](../../.vscode/launch.json). However, running `./scripts/code.sh` first will set up Electron which will usually solve timeout issues. + > **Note:** If launching times out, you can increase the value of `timeout` in the "VS Code", "Attach Main Process", "Attach Extension Host", and "Attach to Shared Process" configurations in [launch.json](../.vscode/launch.json). However, running `./scripts/code.sh` first will set up Electron which will usually solve timeout issues. 3. After a bit, Code - OSS will appear with the debugger attached! From cec203960c592c9a8c973421e7f970f1342e18dd Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 10:56:29 +0200 Subject: [PATCH 056/236] chore - Use simple suite- and test-names and leave styling up to the reporter (#250811) --- src/vs/base/test/common/logTime.test.ts | 14 ++-- .../test/common/observableDisposable.test.ts | 20 ++--- .../frontMatterBoolean.test.ts | 36 ++++----- .../frontMatterDecoder.test.ts | 22 +++--- .../frontMatterRecord.test.ts | 12 +-- .../frontMatterSequence.test.ts | 10 +-- .../test/common/codecs/linesDecoder.test.ts | 24 +++--- .../common/codecs/markdownDecoder.test.ts | 42 +++++------ .../common/codecs/tokens/baseToken.test.ts | 44 +++++------ .../codecs/tokens/compositeToken.test.ts | 38 +++++----- .../common/codecs/tokens/simpleToken.test.ts | 16 ++-- .../common/codecs/utils/objectStream.test.ts | 18 ++--- .../prompts/test/common/config.test.ts | 48 ++++++------ .../prompts/test/common/constants.test.ts | 10 +-- .../prompts/test/common/utils/mock.test.ts | 12 +-- .../common/promptsSync/promptsSync.test.ts | 68 ++++++++--------- .../codecs/chatPromptCodec.test.ts | 2 +- .../codecs/chatPromptDecoder.test.ts | 14 ++-- .../codecs/markdownExtensionsDecoder.test.ts | 18 ++--- .../codecs/tokens/fileReference.test.ts | 6 +- .../filePromptContentsProvider.test.ts | 12 +-- .../parsers/textModelPromptParser.test.ts | 74 +++++++++---------- .../promptSyntax/promptFileReference.test.ts | 28 +++---- .../service/promptsService.test.ts | 18 ++--- .../testUtils/mockFilesystem.test.ts | 2 +- .../utils/promptFilesLocator.test.ts | 70 +++++++++--------- .../promptSyntax/utils/treeUtils.test.ts | 26 +++---- 27 files changed, 352 insertions(+), 352 deletions(-) diff --git a/src/vs/base/test/common/logTime.test.ts b/src/vs/base/test/common/logTime.test.ts index 18f7488e4ad..9ad514d6f6b 100644 --- a/src/vs/base/test/common/logTime.test.ts +++ b/src/vs/base/test/common/logTime.test.ts @@ -34,8 +34,8 @@ suite('logTime', () => { .replaceAll(/\s\d+.\d{2}\sms$/gi, ' 100.50 ms'); }; - suite('• decorator', () => { - test('• async method', async () => { + suite('decorator', () => { + test('async method', async () => { const logSpy = sinon.spy(); class TestClass { public logTime = logSpy; @@ -89,7 +89,7 @@ suite('logTime', () => { }); }); - test('• sync method', async () => { + test('sync method', async () => { const logSpy = sinon.spy(); class TestClass { @@ -134,7 +134,7 @@ suite('logTime', () => { ); }); - test('• uses \'trace\' level by default', async () => { + test('uses \'trace\' level by default', async () => { const logSpy = sinon.spy(); class TestClass { @@ -188,8 +188,8 @@ suite('logTime', () => { ); }); - suite('• logExecutionTime helper', () => { - test('• async function', async () => { + suite('logExecutionTime helper', () => { + test('async function', async () => { const logSpy = sinon.spy(); const expectedReturnValue = randomInt(1000); @@ -234,7 +234,7 @@ suite('logTime', () => { ); }); - test('• sync function', () => { + test('sync function', () => { const logSpy = sinon.spy(); const expectedReturnValue = randomInt(1000); diff --git a/src/vs/base/test/common/observableDisposable.test.ts b/src/vs/base/test/common/observableDisposable.test.ts index 06a820cbc90..c29b44330c5 100644 --- a/src/vs/base/test/common/observableDisposable.test.ts +++ b/src/vs/base/test/common/observableDisposable.test.ts @@ -13,7 +13,7 @@ import { assertNotDisposed, ObservableDisposable } from '../../common/observable suite('ObservableDisposable', () => { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); - test('• tracks `disposed` state', () => { + test('tracks `disposed` state', () => { // this is an abstract class, so we have to create // an anonymous class that extends it const object = new class extends ObservableDisposable { }(); @@ -42,8 +42,8 @@ suite('ObservableDisposable', () => { ); }); - suite('• onDispose()', () => { - test('• fires the event on dispose', async () => { + suite('onDispose()', () => { + test('fires the event on dispose', async () => { // this is an abstract class, so we have to create // an anonymous class that extends it const object = new class extends ObservableDisposable { }(); @@ -107,7 +107,7 @@ suite('ObservableDisposable', () => { ); }); - test('• executes callback immediately if already disposed', async () => { + test('executes callback immediately if already disposed', async () => { // this is an abstract class, so we have to create // an anonymous class that extends it const object = new class extends ObservableDisposable { }(); @@ -149,8 +149,8 @@ suite('ObservableDisposable', () => { }); }); - suite('• addDisposable()', () => { - test('• disposes provided object with itself', async () => { + suite('addDisposable()', () => { + test('disposes provided object with itself', async () => { class TestDisposable implements IDisposable { private _disposed = false; public get disposed() { @@ -208,7 +208,7 @@ suite('ObservableDisposable', () => { ); }); - test('• disposes the entire tree of disposables', async () => { + test('disposes the entire tree of disposables', async () => { class TestDisposable extends ObservableDisposable { } /** @@ -290,8 +290,8 @@ suite('ObservableDisposable', () => { }); }); - suite('• asserts', () => { - test('• not disposed (method)', async () => { + suite('asserts', () => { + test('not disposed (method)', async () => { // this is an abstract class, so we have to create // an anonymous class that extends it const object: ObservableDisposable = new class extends ObservableDisposable { }(); @@ -322,7 +322,7 @@ suite('ObservableDisposable', () => { }); }); - test('• not disposed (function)', async () => { + test('not disposed (function)', async () => { // this is an abstract class, so we have to create // an anonymous class that extends it const object: ObservableDisposable = new class extends ObservableDisposable { }(); diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterBoolean.test.ts b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterBoolean.test.ts index 45c7b430d17..a117af9a045 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterBoolean.test.ts +++ b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterBoolean.test.ts @@ -14,9 +14,9 @@ import { FrontMatterSequence } from '../../../../common/codecs/frontMatterCodec/ suite('FrontMatterBoolean', () => { ensureNoDisposablesAreLeakedInTestSuite(); - suite('• equals()', () => { - suite('• base case', () => { - test('• true', () => { + suite('equals()', () => { + suite('base case', () => { + test('true', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'true' @@ -48,7 +48,7 @@ suite('FrontMatterBoolean', () => { ); }); - test('• false', () => { + test('false', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'false' @@ -81,9 +81,9 @@ suite('FrontMatterBoolean', () => { }); }); - suite('• non-boolean token', () => { - suite('• word token', () => { - test('• true', () => { + suite('non-boolean token', () => { + suite('word token', () => { + test('true', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'true' @@ -107,7 +107,7 @@ suite('FrontMatterBoolean', () => { ); }); - test('• false', () => { + test('false', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'false' @@ -132,8 +132,8 @@ suite('FrontMatterBoolean', () => { }); }); - suite('• sequence token', () => { - test('• true', () => { + suite('sequence token', () => { + test('true', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'true' @@ -159,7 +159,7 @@ suite('FrontMatterBoolean', () => { ); }); - test('• false', () => { + test('false', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'false' @@ -187,8 +187,8 @@ suite('FrontMatterBoolean', () => { }); }); - suite('• different range', () => { - test('• true', () => { + suite('different range', () => { + test('true', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'true' @@ -214,7 +214,7 @@ suite('FrontMatterBoolean', () => { ); }); - test('• false', () => { + test('false', () => { // both values should yield the same result const booleanText = (randomBoolean()) ? 'false' @@ -241,8 +241,8 @@ suite('FrontMatterBoolean', () => { }); }); - suite('• different text', () => { - test('• true', () => { + suite('different text', () => { + test('true', () => { const boolean = new FrontMatterBoolean( new Word( new Range(1, 1, 1, 5), @@ -263,7 +263,7 @@ suite('FrontMatterBoolean', () => { ); }); - test('• false', () => { + test('false', () => { const boolean = new FrontMatterBoolean( new Word( new Range(5, 15, 5, 15 + 6), @@ -285,7 +285,7 @@ suite('FrontMatterBoolean', () => { }); }); - test('• throws if cannot be converted to a boolean', () => { + test('throws if cannot be converted to a boolean', () => { assert.throws(() => { new FrontMatterBoolean( new Word( diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterDecoder.test.ts b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterDecoder.test.ts index 9bd7164dd5c..1cc9c7f466b 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterDecoder.test.ts +++ b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterDecoder.test.ts @@ -33,7 +33,7 @@ export class TestFrontMatterDecoder extends TestDecoder { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); - test('• produces expected tokens', async () => { + test('produces expected tokens', async () => { const test = disposables.add(new TestFrontMatterDecoder()); await test.run( @@ -115,9 +115,9 @@ suite('FrontMatterDecoder', () => { ]); }); - suite('• record', () => { - suite('• values', () => { - test('• unquoted string', async () => { + suite('record', () => { + suite('values', () => { + test('unquoted string', async () => { const test = disposables.add(new TestFrontMatterDecoder()); await test.run( @@ -164,7 +164,7 @@ suite('FrontMatterDecoder', () => { ]); }); - test('• quoted string', async () => { + test('quoted string', async () => { const test = disposables.add(new TestFrontMatterDecoder()); await test.run( @@ -219,7 +219,7 @@ suite('FrontMatterDecoder', () => { ]); }); - test('• boolean', async () => { + test('boolean', async () => { const test = disposables.add(new TestFrontMatterDecoder()); await test.run( @@ -269,8 +269,8 @@ suite('FrontMatterDecoder', () => { ]); }); - suite('• array', () => { - test('• empty', async () => { + suite('array', () => { + test('empty', async () => { const test = disposables.add(new TestFrontMatterDecoder()); await test.run( @@ -314,7 +314,7 @@ suite('FrontMatterDecoder', () => { ]); }); - test('• mixed values', async () => { + test('mixed values', async () => { const test = disposables.add(new TestFrontMatterDecoder()); await test.run( @@ -358,7 +358,7 @@ suite('FrontMatterDecoder', () => { ]); }); - test('• redundant commas', async () => { + test('redundant commas', async () => { const test = disposables.add(new TestFrontMatterDecoder()); await test.run( @@ -405,7 +405,7 @@ suite('FrontMatterDecoder', () => { }); }); - test('• empty', async () => { + test('empty', async () => { const test = disposables.add( new TestFrontMatterDecoder(), ); diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterRecord.test.ts b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterRecord.test.ts index 1216324289a..cac93d99e46 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterRecord.test.ts +++ b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterRecord.test.ts @@ -13,8 +13,8 @@ import { FrontMatterArray, FrontMatterBoolean, FrontMatterRecord, FrontMatterRec suite('FrontMatterBoolean', () => { ensureNoDisposablesAreLeakedInTestSuite(); - suite('• trimValueEnd()', () => { - test('• trims space tokens at the end of record\'s value', () => { + suite('trimValueEnd()', () => { + test('trims space tokens at the end of record\'s value', () => { const recordName = new FrontMatterRecordName([ new Word( new Range(4, 10, 4, 10 + 3), @@ -59,8 +59,8 @@ suite('FrontMatterBoolean', () => { ); }); - suite('• does not trim non-sequence value tokens', () => { - test('• boolean', () => { + suite('does not trim non-sequence value tokens', () => { + test('boolean', () => { const recordName = new FrontMatterRecordName([ new Word( new Range(4, 10, 4, 10 + 3), @@ -96,7 +96,7 @@ suite('FrontMatterBoolean', () => { ); }); - test('• quoted string', () => { + test('quoted string', () => { const recordName = new FrontMatterRecordName([ new Word( new Range(4, 10, 4, 10 + 3), @@ -134,7 +134,7 @@ suite('FrontMatterBoolean', () => { ); }); - test('• array', () => { + test('array', () => { const recordName = new FrontMatterRecordName([ new Word( new Range(4, 10, 4, 10 + 3), diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterSequence.test.ts b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterSequence.test.ts index 9f752d17698..a17bc998bdc 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterSequence.test.ts +++ b/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterSequence.test.ts @@ -13,7 +13,7 @@ import { FrontMatterSequence } from '../../../../common/codecs/frontMatterCodec/ suite('FrontMatterSequence', () => { ensureNoDisposablesAreLeakedInTestSuite(); - test('• extends \'FrontMatterValueToken\'', () => { + test('extends \'FrontMatterValueToken\'', () => { const sequence = new FrontMatterSequence([ new Word( new Range(1, 1, 1, 5), @@ -27,8 +27,8 @@ suite('FrontMatterSequence', () => { ); }); - suite('• trimEnd()', () => { - test('• trims space tokens at the end of the sequence', () => { + suite('trimEnd()', () => { + test('trims space tokens at the end of the sequence', () => { const sequence = new FrontMatterSequence([ new Word(new Range(4, 18, 4, 18 + 10), 'some-value'), new Space(new Range(4, 28, 4, 29)), @@ -59,7 +59,7 @@ suite('FrontMatterSequence', () => { ); }); - test('• remains functional if only spacing tokens were present', () => { + test('remains functional if only spacing tokens were present', () => { const sequence = new FrontMatterSequence([ new Space(new Range(4, 28, 4, 29)), new Space(new Range(4, 29, 4, 30)), @@ -98,7 +98,7 @@ suite('FrontMatterSequence', () => { }); }); - test('• throws if no tokens provided', () => { + test('throws if no tokens provided', () => { assert.throws(() => { new FrontMatterSequence([]); }); diff --git a/src/vs/editor/test/common/codecs/linesDecoder.test.ts b/src/vs/editor/test/common/codecs/linesDecoder.test.ts index 82ff987120a..8e021b57ec3 100644 --- a/src/vs/editor/test/common/codecs/linesDecoder.test.ts +++ b/src/vs/editor/test/common/codecs/linesDecoder.test.ts @@ -26,14 +26,14 @@ suite('LinesDecoder', () => { * Test the core logic with specific method of consuming * tokens that are produced by a lines decoder instance. */ - suite('• core logic', () => { + suite('core logic', () => { testLinesDecoder('async-generator', disposables); testLinesDecoder('consume-all-method', disposables); testLinesDecoder('on-data-event', disposables); }); - suite('• settled promise', () => { - test('• throws if accessed on not-yet-started decoder instance', () => { + suite('settled promise', () => { + test('throws if accessed on not-yet-started decoder instance', () => { const test = disposables.add(new TestLinesDecoder()); assert.throws( @@ -51,8 +51,8 @@ suite('LinesDecoder', () => { }); }); - suite('• start', () => { - test('• throws if the decoder object is already `disposed`', () => { + suite('start', () => { + test('throws if the decoder object is already `disposed`', () => { const test = disposables.add(new TestLinesDecoder()); const { decoder } = test; decoder.dispose(); @@ -63,7 +63,7 @@ suite('LinesDecoder', () => { ); }); - test('• throws if the decoder object is already `ended`', async () => { + test('throws if the decoder object is already `ended`', async () => { const inputStream = newWriteableStream(null); const test = disposables.add(new TestLinesDecoder(inputStream)); const { decoder } = test; @@ -141,8 +141,8 @@ function testLinesDecoder( disposables: Pick, ) { suite(tokensConsumeMethod, () => { - suite('• produces expected tokens', () => { - test('• input starts with line data', async () => { + suite('produces expected tokens', () => { + test('input starts with line data', async () => { const test = disposables.add(new TestLinesDecoder()); await test.run( @@ -160,7 +160,7 @@ function testLinesDecoder( ); }); - test('• standalone \\r is treated as new line', async () => { + test('standalone \\r is treated as new line', async () => { const test = disposables.add(new TestLinesDecoder()); await test.run( @@ -179,7 +179,7 @@ function testLinesDecoder( ); }); - test('• input starts with a new line', async () => { + test('input starts with a new line', async () => { const test = disposables.add(new TestLinesDecoder()); await test.run( @@ -202,7 +202,7 @@ function testLinesDecoder( ); }); - test('• input starts and ends with multiple new lines', async () => { + test('input starts and ends with multiple new lines', async () => { const test = disposables.add(new TestLinesDecoder()); await test.run( @@ -229,7 +229,7 @@ function testLinesDecoder( ); }); - test('• single carriage return is treated as new line', async () => { + test('single carriage return is treated as new line', async () => { const test = disposables.add(new TestLinesDecoder()); await test.run( diff --git a/src/vs/editor/test/common/codecs/markdownDecoder.test.ts b/src/vs/editor/test/common/codecs/markdownDecoder.test.ts index 2219068bef3..1b395bca186 100644 --- a/src/vs/editor/test/common/codecs/markdownDecoder.test.ts +++ b/src/vs/editor/test/common/codecs/markdownDecoder.test.ts @@ -61,8 +61,8 @@ export class TestMarkdownDecoder extends TestDecoder { const testDisposables = ensureNoDisposablesAreLeakedInTestSuite(); - suite('• general', () => { - test('• base cases', async () => { + suite('general', () => { + test('base cases', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -127,7 +127,7 @@ suite('MarkdownDecoder', () => { ); }); - test('• nuanced', async () => { + test('nuanced', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -174,9 +174,9 @@ suite('MarkdownDecoder', () => { }); }); - suite('• links', () => { - suite('• broken', () => { - test('• invalid', async () => { + suite('links', () => { + suite('broken', () => { + test('invalid', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -226,7 +226,7 @@ suite('MarkdownDecoder', () => { ); }); - suite('• stop characters inside caption/reference (new lines)', () => { + suite('stop characters inside caption/reference (new lines)', () => { for (const StopCharacter of [CarriageReturn, NewLine]) { let characterName = ''; @@ -318,7 +318,7 @@ suite('MarkdownDecoder', () => { /** * Same as above but these stop characters do not move the caret to the next line. */ - suite('• stop characters inside caption/reference (same line)', () => { + suite('stop characters inside caption/reference (same line)', () => { for (const StopCharacter of [VerticalTab, FormFeed]) { let characterName = ''; @@ -410,9 +410,9 @@ suite('MarkdownDecoder', () => { }); - suite('• images', () => { - suite('• general', () => { - test('• base cases', async () => { + suite('images', () => { + suite('general', () => { + test('base cases', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -456,7 +456,7 @@ suite('MarkdownDecoder', () => { ); }); - test('• nuanced', async () => { + test('nuanced', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -494,8 +494,8 @@ suite('MarkdownDecoder', () => { }); }); - suite('• broken', () => { - test('• invalid', async () => { + suite('broken', () => { + test('invalid', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -567,7 +567,7 @@ suite('MarkdownDecoder', () => { ); }); - suite('• stop characters inside caption/reference (new lines)', () => { + suite('stop characters inside caption/reference (new lines)', () => { for (const StopCharacter of [CarriageReturn, NewLine]) { let characterName = ''; @@ -662,7 +662,7 @@ suite('MarkdownDecoder', () => { /** * Same as above but these stop characters do not move the caret to the next line. */ - suite('• stop characters inside caption/reference (same line)', () => { + suite('stop characters inside caption/reference (same line)', () => { for (const stopCharacter of [VerticalTab, FormFeed]) { let characterName = ''; @@ -756,9 +756,9 @@ suite('MarkdownDecoder', () => { }); }); - suite('• comments', () => { - suite('• general', () => { - test('• base cases', async () => { + suite('comments', () => { + suite('general', () => { + test('base cases', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -818,7 +818,7 @@ suite('MarkdownDecoder', () => { ); }); - test('• nuanced', async () => { + test('nuanced', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); @@ -866,7 +866,7 @@ suite('MarkdownDecoder', () => { }); }); - test('• invalid', async () => { + test('invalid', async () => { const test = testDisposables.add( new TestMarkdownDecoder(), ); diff --git a/src/vs/editor/test/common/codecs/tokens/baseToken.test.ts b/src/vs/editor/test/common/codecs/tokens/baseToken.test.ts index 88daa8ed79a..677215bfbec 100644 --- a/src/vs/editor/test/common/codecs/tokens/baseToken.test.ts +++ b/src/vs/editor/test/common/codecs/tokens/baseToken.test.ts @@ -45,12 +45,12 @@ const randomSimpleToken = (): TSimpleToken => { suite('BaseToken', () => { ensureNoDisposablesAreLeakedInTestSuite(); - suite('• render()', () => { + suite('render()', () => { /** * Note! Range of tokens is ignored by the render method, that's * why we generate random ranges for each token in this test. */ - test('• a list of tokens', () => { + test('a list of tokens', () => { const tests: readonly [string, BaseToken[]][] = [ ['/textoftheword$#', [ new Slash(randomRange()), @@ -95,7 +95,7 @@ suite('BaseToken', () => { } }); - test('• accepts tokens delimiter', () => { + test('accepts tokens delimiter', () => { // couple of different delimiters to try const delimiter = (randomBoolean()) ? ', ' @@ -128,7 +128,7 @@ suite('BaseToken', () => { } }); - test('• an empty list of tokens', () => { + test('an empty list of tokens', () => { assert.strictEqual( '', BaseToken.render([]), @@ -137,15 +137,15 @@ suite('BaseToken', () => { }); }); - suite('• fullRange()', () => { - suite('• throws', () => { - test('• if empty list provided', () => { + suite('fullRange()', () => { + suite('throws', () => { + test('if empty list provided', () => { assert.throws(() => { BaseToken.fullRange([]); }); }); - test('• if start line number of the first token is greater than one of the last token', () => { + test('if start line number of the first token is greater than one of the last token', () => { assert.throws(() => { const lastToken = randomSimpleToken(); @@ -177,7 +177,7 @@ suite('BaseToken', () => { }); }); - test('• if start line numbers are equal and end of the first token is greater than the start of the last token', () => { + test('if start line numbers are equal and end of the first token is greater than the start of the last token', () => { assert.throws(() => { const firstToken = randomSimpleToken(); @@ -207,8 +207,8 @@ suite('BaseToken', () => { }); }); - suite('• withRange()', () => { - test('• updates token range', () => { + suite('withRange()', () => { + test('updates token range', () => { class TestToken extends BaseToken { public override get text(): string { throw new Error('Method not implemented.'); @@ -236,8 +236,8 @@ suite('BaseToken', () => { }); }); - suite('• collapseRangeToStart()', () => { - test('• collapses token range to the start position', () => { + suite('collapseRangeToStart()', () => { + test('collapses token range to the start position', () => { class TestToken extends BaseToken { public override get text(): string { throw new Error('Method not implemented.'); @@ -296,8 +296,8 @@ suite('BaseToken', () => { }); }); - suite('• equals()', () => { - test('• true', () => { + suite('equals()', () => { + test('true', () => { class TestToken extends BaseToken { constructor( range: Range, @@ -338,9 +338,9 @@ suite('BaseToken', () => { ); }); - suite('• false', () => { - suite('• different constructor', () => { - test('• same base class', () => { + suite('false', () => { + suite('different constructor', () => { + test('same base class', () => { class TestToken1 extends BaseToken { public override get text(): string { throw new Error('Method not implemented.'); @@ -378,7 +378,7 @@ suite('BaseToken', () => { ); }); - test('• child', () => { + test('child', () => { class TestToken1 extends BaseToken { public override get text(): string { throw new Error('Method not implemented.'); @@ -408,7 +408,7 @@ suite('BaseToken', () => { ); }); - test('• different direct ancestor', () => { + test('different direct ancestor', () => { class TestToken1 extends BaseToken { public override get text(): string { throw new Error('Method not implemented.'); @@ -449,7 +449,7 @@ suite('BaseToken', () => { }); }); - test('• different text', () => { + test('different text', () => { class TestToken extends BaseToken { constructor( private readonly value: string, @@ -482,7 +482,7 @@ suite('BaseToken', () => { ); }); - test('• different range', () => { + test('different range', () => { class TestToken extends BaseToken { public override get text(): string { return 'some text value'; diff --git a/src/vs/editor/test/common/codecs/tokens/compositeToken.test.ts b/src/vs/editor/test/common/codecs/tokens/compositeToken.test.ts index abcdaf1297b..d91f02260fe 100644 --- a/src/vs/editor/test/common/codecs/tokens/compositeToken.test.ts +++ b/src/vs/editor/test/common/codecs/tokens/compositeToken.test.ts @@ -32,9 +32,9 @@ suite('CompositeToken', () => { } } - suite('• constructor', () => { - suite('• infers range from the list of tokens', () => { - test('• one token', () => { + suite('constructor', () => { + suite('infers range from the list of tokens', () => { + test('one token', () => { const range = randomRange(); const token = new TestCompositeToken([ new Word( @@ -49,7 +49,7 @@ suite('CompositeToken', () => { ); }); - test('• multiple tokens', () => { + test('multiple tokens', () => { const tokens = randomTokens(); const token = new TestCompositeToken(tokens); @@ -64,21 +64,21 @@ suite('CompositeToken', () => { ); }); - test('• throws if no tokens provided', () => { + test('throws if no tokens provided', () => { assert.throws(() => { new TestCompositeToken([]); }); }); }); - test('• throws if no tokens provided', () => { + test('throws if no tokens provided', () => { assert.throws(() => { new TestCompositeToken([]); }); }); }); - test('• text', () => { + test('text', () => { const tokens = randomTokens(); const token = new TestCompositeToken(tokens); @@ -89,7 +89,7 @@ suite('CompositeToken', () => { ); }); - test('• tokens', () => { + test('tokens', () => { const tokens = randomTokens(); const token = new TestCompositeToken(tokens); @@ -101,9 +101,9 @@ suite('CompositeToken', () => { } }); - suite('• equals', () => { - suite('• true', () => { - test('• same child tokens', () => { + suite('equals', () => { + suite('true', () => { + test('same child tokens', () => { const tokens = randomTokens(); const token1 = new TestCompositeToken(tokens); const token2 = new TestCompositeToken(tokens); @@ -114,7 +114,7 @@ suite('CompositeToken', () => { ); }); - test('• copied child tokens', () => { + test('copied child tokens', () => { const tokens = randomTokens(); const token1 = new TestCompositeToken([...tokens]); const token2 = new TestCompositeToken([...tokens]); @@ -125,7 +125,7 @@ suite('CompositeToken', () => { ); }); - test('• cloned child tokens', () => { + test('cloned child tokens', () => { const tokens = randomTokens(); const tokens1 = cloneTokens(tokens); @@ -140,7 +140,7 @@ suite('CompositeToken', () => { ); }); - test('• composite tokens', () => { + test('composite tokens', () => { const tokens = randomTokens(); // ensure there is at least one composite token @@ -162,8 +162,8 @@ suite('CompositeToken', () => { }); }); - suite('• false', () => { - test('• unknown children number', () => { + suite('false', () => { + test('unknown children number', () => { const token1 = new TestCompositeToken(randomTokens()); const token2 = new TestCompositeToken(randomTokens()); @@ -173,7 +173,7 @@ suite('CompositeToken', () => { ); }); - test('• different number of children', () => { + test('different number of children', () => { const tokens1 = randomTokens(); const tokens2 = randomTokens(); @@ -192,7 +192,7 @@ suite('CompositeToken', () => { ); }); - test('• same number of children', () => { + test('same number of children', () => { const tokensCount = randomInt(20, 10); const tokens1 = randomTokens(tokensCount); @@ -213,7 +213,7 @@ suite('CompositeToken', () => { ); }); - test('• unequal composite tokens', () => { + test('unequal composite tokens', () => { const tokens = randomTokens(); // ensure there is at least one composite token diff --git a/src/vs/editor/test/common/codecs/tokens/simpleToken.test.ts b/src/vs/editor/test/common/codecs/tokens/simpleToken.test.ts index b93db317d87..66f96a794b1 100644 --- a/src/vs/editor/test/common/codecs/tokens/simpleToken.test.ts +++ b/src/vs/editor/test/common/codecs/tokens/simpleToken.test.ts @@ -11,8 +11,8 @@ import { SpacingToken, SimpleToken, Space, Tab, VerticalTab } from '../../../../ suite('SimpleToken', () => { ensureNoDisposablesAreLeakedInTestSuite(); - suite('• SpacingToken', () => { - test('• extends \'SimpleToken\'', () => { + suite('SpacingToken', () => { + test('extends \'SimpleToken\'', () => { class TestClass extends SpacingToken { public override get text(): string { throw new Error('Method not implemented.'); @@ -31,8 +31,8 @@ suite('SimpleToken', () => { }); }); - suite('• Space', () => { - test('• extends \'SpacingToken\'', () => { + suite('Space', () => { + test('extends \'SpacingToken\'', () => { const token = new Space(new Range(1, 1, 1, 2)); assert( @@ -42,8 +42,8 @@ suite('SimpleToken', () => { }); }); - suite('• Tab', () => { - test('• extends \'SpacingToken\'', () => { + suite('Tab', () => { + test('extends \'SpacingToken\'', () => { const token = new Tab(new Range(1, 1, 1, 2)); assert( @@ -53,8 +53,8 @@ suite('SimpleToken', () => { }); }); - suite('• VerticalTab', () => { - test('• extends \'SpacingToken\'', () => { + suite('VerticalTab', () => { + test('extends \'SpacingToken\'', () => { const token = new VerticalTab(new Range(1, 1, 1, 2)); assert( diff --git a/src/vs/editor/test/common/codecs/utils/objectStream.test.ts b/src/vs/editor/test/common/codecs/utils/objectStream.test.ts index 0dd02446bbc..8191b24ccf0 100644 --- a/src/vs/editor/test/common/codecs/utils/objectStream.test.ts +++ b/src/vs/editor/test/common/codecs/utils/objectStream.test.ts @@ -19,8 +19,8 @@ import { objectStreamFromTextModel } from '../../../../common/codecs/utils/objec suite('ObjectStream', () => { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); - suite('• fromArray()', () => { - test('• sends objects in the array', async () => { + suite('fromArray()', () => { + test('sends objects in the array', async () => { const tokens = randomTokens(); const stream = disposables.add(ObjectStream.fromArray(tokens)); @@ -30,8 +30,8 @@ suite('ObjectStream', () => { }); }); - suite('• fromTextModel()', () => { - test('• sends data in text model', async () => { + suite('fromTextModel()', () => { + test('sends data in text model', async () => { const initialContents = [ 'some contents', 'with some line breaks', @@ -62,8 +62,8 @@ suite('ObjectStream', () => { }); }); - suite('• cancellation token', () => { - test('• can be cancelled', async () => { + suite('cancellation token', () => { + test('can be cancelled', async () => { const initialContents = [ 'some contents', 'with some line breaks', @@ -121,9 +121,9 @@ suite('ObjectStream', () => { }); }); - suite('• helpers', () => { - suite('• arrayToGenerator()', () => { - test('• sends tokens in the array', async () => { + suite('helpers', () => { + suite('arrayToGenerator()', () => { + test('sends tokens in the array', async () => { const tokens = randomTokens(); const generator = arrayToGenerator(tokens); diff --git a/src/vs/platform/prompts/test/common/config.test.ts b/src/vs/platform/prompts/test/common/config.test.ts index eecb8427a9c..3f60a2e6a8e 100644 --- a/src/vs/platform/prompts/test/common/config.test.ts +++ b/src/vs/platform/prompts/test/common/config.test.ts @@ -35,8 +35,8 @@ const createMock = (value: T): IConfigurationService => { suite('PromptsConfig', () => { ensureNoDisposablesAreLeakedInTestSuite(); - suite('• enabled', () => { - test('• true', () => { + suite('enabled', () => { + test('true', () => { const configService = createMock(true); assert.strictEqual( @@ -46,7 +46,7 @@ suite('PromptsConfig', () => { ); }); - test('• false', () => { + test('false', () => { const configService = createMock(false); assert.strictEqual( @@ -56,7 +56,7 @@ suite('PromptsConfig', () => { ); }); - test('• null', () => { + test('null', () => { const configService = createMock(null); assert.strictEqual( @@ -66,7 +66,7 @@ suite('PromptsConfig', () => { ); }); - test('• string', () => { + test('string', () => { const configService = createMock(''); assert.strictEqual( @@ -76,7 +76,7 @@ suite('PromptsConfig', () => { ); }); - test('• true string', () => { + test('true string', () => { const configService = createMock('TRUE'); assert.strictEqual( @@ -86,7 +86,7 @@ suite('PromptsConfig', () => { ); }); - test('• false string', () => { + test('false string', () => { const configService = createMock('FaLsE'); assert.strictEqual( @@ -96,7 +96,7 @@ suite('PromptsConfig', () => { ); }); - test('• number', () => { + test('number', () => { const configService = createMock(randomInt(100)); assert.strictEqual( @@ -106,7 +106,7 @@ suite('PromptsConfig', () => { ); }); - test('• NaN', () => { + test('NaN', () => { const configService = createMock(NaN); assert.strictEqual( @@ -116,7 +116,7 @@ suite('PromptsConfig', () => { ); }); - test('• bigint', () => { + test('bigint', () => { const configService = createMock(BigInt(randomInt(100))); assert.strictEqual( @@ -126,7 +126,7 @@ suite('PromptsConfig', () => { ); }); - test('• symbol', () => { + test('symbol', () => { const configService = createMock(Symbol('test')); assert.strictEqual( @@ -136,7 +136,7 @@ suite('PromptsConfig', () => { ); }); - test('• object', () => { + test('object', () => { const configService = createMock({ '.github/prompts': false, }); @@ -148,7 +148,7 @@ suite('PromptsConfig', () => { ); }); - test('• array', () => { + test('array', () => { const configService = createMock(['.github/prompts']); assert.strictEqual( @@ -160,8 +160,8 @@ suite('PromptsConfig', () => { }); - suite('• getLocationsValue', () => { - test('• undefined', () => { + suite('getLocationsValue', () => { + test('undefined', () => { const configService = createMock(undefined); assert.strictEqual( @@ -171,7 +171,7 @@ suite('PromptsConfig', () => { ); }); - test('• null', () => { + test('null', () => { const configService = createMock(null); assert.strictEqual( @@ -181,8 +181,8 @@ suite('PromptsConfig', () => { ); }); - suite('• object', () => { - test('• empty', () => { + suite('object', () => { + test('empty', () => { assert.deepStrictEqual( PromptsConfig.getLocationsValue(createMock({}), PromptsType.prompt), {}, @@ -190,7 +190,7 @@ suite('PromptsConfig', () => { ); }); - test('• only valid strings', () => { + test('only valid strings', () => { assert.deepStrictEqual( PromptsConfig.getLocationsValue(createMock({ '/root/.bashrc': true, @@ -224,7 +224,7 @@ suite('PromptsConfig', () => { ); }); - test('• filters out non valid entries', () => { + test('filters out non valid entries', () => { assert.deepStrictEqual( PromptsConfig.getLocationsValue(createMock({ '/etc/hosts.backup': '\t\n\t', @@ -263,7 +263,7 @@ suite('PromptsConfig', () => { ); }); - test('• only invalid or false values', () => { + test('only invalid or false values', () => { assert.deepStrictEqual( PromptsConfig.getLocationsValue(createMock({ '/etc/hosts.backup': '\t\n\t', @@ -286,8 +286,8 @@ suite('PromptsConfig', () => { }); }); - suite('• sourceLocations', () => { - test('• undefined', () => { + suite('sourceLocations', () => { + test('undefined', () => { const configService = createMock(undefined); assert.deepStrictEqual( @@ -297,7 +297,7 @@ suite('PromptsConfig', () => { ); }); - test('• null', () => { + test('null', () => { const configService = createMock(null); assert.deepStrictEqual( diff --git a/src/vs/platform/prompts/test/common/constants.test.ts b/src/vs/platform/prompts/test/common/constants.test.ts index d22d8f283dc..d1181219141 100644 --- a/src/vs/platform/prompts/test/common/constants.test.ts +++ b/src/vs/platform/prompts/test/common/constants.test.ts @@ -13,8 +13,8 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/c suite('Prompt Constants', () => { ensureNoDisposablesAreLeakedInTestSuite(); - suite('• getCleanPromptName', () => { - test('• returns a clean prompt name', () => { + suite('getCleanPromptName', () => { + test('returns a clean prompt name', () => { assert.strictEqual( getCleanPromptName(URI.file('/path/to/my-prompt.prompt.md')), 'my-prompt', @@ -53,8 +53,8 @@ suite('Prompt Constants', () => { }); }); - suite('• isPromptOrInstructionsFile', () => { - test('• returns `true` for prompt files', () => { + suite('isPromptOrInstructionsFile', () => { + test('returns `true` for prompt files', () => { assert( isPromptOrInstructionsFile(URI.file('/path/to/my-prompt.prompt.md')), ); @@ -72,7 +72,7 @@ suite('Prompt Constants', () => { ); }); - test('• returns `false` for non-prompt files', () => { + test('returns `false` for non-prompt files', () => { assert( !isPromptOrInstructionsFile(URI.file('/path/to/my-prompt.prompt.md1')), ); diff --git a/src/vs/platform/prompts/test/common/utils/mock.test.ts b/src/vs/platform/prompts/test/common/utils/mock.test.ts index 0539b73bde4..6d50dd24493 100644 --- a/src/vs/platform/prompts/test/common/utils/mock.test.ts +++ b/src/vs/platform/prompts/test/common/utils/mock.test.ts @@ -13,8 +13,8 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/tes suite('mockService', () => { ensureNoDisposablesAreLeakedInTestSuite(); - suite('• mockObject', () => { - test('• overrides properties and functions', () => { + suite('mockObject', () => { + test('overrides properties and functions', () => { interface ITestObject { foo: string; bar: string; @@ -67,7 +67,7 @@ suite('mockService', () => { }); }); - test('• immutability of the overrides object', () => { + test('immutability of the overrides object', () => { interface ITestObject { foo: string; bar: string; @@ -101,8 +101,8 @@ suite('mockService', () => { }); }); - suite('• mockService', () => { - test('• overrides properties and functions', () => { + suite('mockService', () => { + test('overrides properties and functions', () => { interface ITestService { readonly _serviceBrand: undefined; prop1: string; @@ -156,7 +156,7 @@ suite('mockService', () => { }); }); - test('• immutability of the overrides object', () => { + test('immutability of the overrides object', () => { interface ITestService { readonly _serviceBrand: undefined; foo: string; diff --git a/src/vs/platform/userDataSync/test/common/promptsSync/promptsSync.test.ts b/src/vs/platform/userDataSync/test/common/promptsSync/promptsSync.test.ts index e56673233f9..13fa994788b 100644 --- a/src/vs/platform/userDataSync/test/common/promptsSync/promptsSync.test.ts +++ b/src/vs/platform/userDataSync/test/common/promptsSync/promptsSync.test.ts @@ -54,7 +54,7 @@ suite('PromptsSync', () => { await client2.setUp(true); }); - test('• when prompts does not exist', async () => { + test('when prompts does not exist', async () => { const fileService = testClient.instantiationService.get(IFileService); const promptsResource = testClient.instantiationService.get(IUserDataProfilesService).defaultProfile.promptsHome; @@ -91,7 +91,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(server.requests, []); }); - test('• when prompt is created after first sync', async () => { + test('when prompt is created after first sync', async () => { await testObject.sync(await testClient.getResourceManifest()); await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, testClient); @@ -126,7 +126,7 @@ suite('PromptsSync', () => { ); }); - test('• first time sync - outgoing to server (no prompts)', async () => { + test('first time sync - outgoing to server (no prompts)', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, testClient); await updatePrompt('prompt1.prompt.md', PROMPT1_TEXT, testClient); @@ -149,7 +149,7 @@ suite('PromptsSync', () => { }); }); - test('• first time sync - incoming from server (no prompts)', async () => { + test('first time sync - incoming from server (no prompts)', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('prompt1.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -164,7 +164,7 @@ suite('PromptsSync', () => { assert.strictEqual(actual2, PROMPT1_TEXT); }); - test('• first time sync when prompts exists', async () => { + test('first time sync when prompts exists', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); @@ -193,7 +193,7 @@ suite('PromptsSync', () => { }); }); - test('• first time sync when prompts exists - has conflicts', async () => { + test('first time sync when prompts exists - has conflicts', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); @@ -212,7 +212,7 @@ suite('PromptsSync', () => { assertPreviews(testObject.conflicts.conflicts, [local]); }); - test('• first time sync when prompts exists - has conflicts and accept conflicts', async () => { + test('first time sync when prompts exists - has conflicts and accept conflicts', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); @@ -238,7 +238,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'prompt3.prompt.md': PROMPT3_TEXT }); }); - test('• first time sync when prompts exists - has multiple conflicts', async () => { + test('first time sync when prompts exists - has multiple conflicts', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('prompt1.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -254,7 +254,7 @@ suite('PromptsSync', () => { assertPreviews(testObject.conflicts.conflicts, [local1, local2]); }); - test('• first time sync when prompts exists - has multiple conflicts and accept one conflict', async () => { + test('first time sync when prompts exists - has multiple conflicts and accept one conflict', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('prompt1.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -273,7 +273,7 @@ suite('PromptsSync', () => { assertPreviews(testObject.conflicts.conflicts, [local]); }); - test('• first time sync when prompts exists - has multiple conflicts and accept all conflicts', async () => { + test('first time sync when prompts exists - has multiple conflicts and accept all conflicts', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('prompt1.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -305,7 +305,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'prompt3.prompt.md': PROMPT4_TEXT, 'prompt1.prompt.md': PROMPT1_TEXT }); }); - test('• sync adding a prompt', async () => { + test('sync adding a prompt', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, testClient); await testObject.sync(await testClient.getResourceManifest()); @@ -325,7 +325,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'prompt3.prompt.md': PROMPT3_TEXT, 'prompt1.prompt.md': PROMPT1_TEXT }); }); - test('• sync adding a prompt - accept', async () => { + test('sync adding a prompt - accept', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); await testObject.sync(await testClient.getResourceManifest()); @@ -343,7 +343,7 @@ suite('PromptsSync', () => { assert.strictEqual(actual2, PROMPT1_TEXT); }); - test('• sync updating a prompt', async () => { + test('sync updating a prompt', async () => { await updatePrompt('default.prompt.md', PROMPT3_TEXT, testClient); await testObject.sync(await testClient.getResourceManifest()); @@ -361,7 +361,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'default.prompt.md': PROMPT4_TEXT }); }); - test('• sync updating a prompt - accept', async () => { + test('sync updating a prompt - accept', async () => { await updatePrompt('my.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); await testObject.sync(await testClient.getResourceManifest()); @@ -377,7 +377,7 @@ suite('PromptsSync', () => { assert.strictEqual(actual1, PROMPT4_TEXT); }); - test('• sync updating a prompt - conflict', async () => { + test('sync updating a prompt - conflict', async () => { await updatePrompt('some.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); await testObject.sync(await testClient.getResourceManifest()); @@ -393,7 +393,7 @@ suite('PromptsSync', () => { assertPreviews(testObject.conflicts.conflicts, [local]); }); - test('• sync updating a prompt - resolve conflict', async () => { + test('sync updating a prompt - resolve conflict', async () => { await updatePrompt('advanced.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); await testObject.sync(await testClient.getResourceManifest()); @@ -418,7 +418,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'advanced.prompt.md': PROMPT4_TEXT }); }); - test('• sync removing a prompt', async () => { + test('sync removing a prompt', async () => { await updatePrompt('another.prompt.md', PROMPT3_TEXT, testClient); await updatePrompt('chat.prompt.md', PROMPT1_TEXT, testClient); await testObject.sync(await testClient.getResourceManifest()); @@ -443,7 +443,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'chat.prompt.md': PROMPT1_TEXT }); }); - test('• sync removing a prompt - accept', async () => { + test('sync removing a prompt - accept', async () => { await updatePrompt('my-query.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('summarize.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -462,7 +462,7 @@ suite('PromptsSync', () => { assert.strictEqual(actual2, null); }); - test('• sync removing a prompt locally and updating it remotely', async () => { + test('sync removing a prompt locally and updating it remotely', async () => { await updatePrompt('some.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('important.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -483,7 +483,7 @@ suite('PromptsSync', () => { assert.strictEqual(actual2, PROMPT4_TEXT); }); - test('• sync removing a prompt - conflict', async () => { + test('sync removing a prompt - conflict', async () => { await updatePrompt('common.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('rare.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -501,7 +501,7 @@ suite('PromptsSync', () => { assertPreviews(testObject.conflicts.conflicts, [local]); }); - test('• sync removing a prompt - resolve conflict', async () => { + test('sync removing a prompt - resolve conflict', async () => { await updatePrompt('uncommon.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('hot.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -533,7 +533,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'hot.prompt.md': PROMPT1_TEXT, 'uncommon.prompt.md': PROMPT5_TEXT }); }); - test('• sync removing a prompt - resolve conflict by removing', async () => { + test('sync removing a prompt - resolve conflict by removing', async () => { await updatePrompt('prompt3.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('refactor.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -565,7 +565,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'refactor.prompt.md': PROMPT1_TEXT }); }); - test('• sync prompts', async () => { + test('sync prompts', async () => { await updatePrompt('first.prompt.md', PROMPT6_TEXT, client2); await updatePrompt('roaming.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); @@ -589,7 +589,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'roaming.prompt.md': PROMPT3_TEXT, 'first.prompt.md': PROMPT6_TEXT }); }); - test('• sync should ignore non prompts', async () => { + test('sync should ignore non prompts', async () => { await updatePrompt('my.prompt.md', PROMPT6_TEXT, client2); await updatePrompt('html.html', PROMPT3_TEXT, client2); await updatePrompt('shared.prompt.md', PROMPT1_TEXT, client2); @@ -612,7 +612,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(actual, { 'shared.prompt.md': PROMPT1_TEXT, 'my.prompt.md': PROMPT6_TEXT }); }); - test('• previews are reset after all conflicts resolved', async () => { + test('previews are reset after all conflicts resolved', async () => { await updatePrompt('html.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('css.prompt.md', PROMPT1_TEXT, client2); await client2.sync(); @@ -628,7 +628,7 @@ suite('PromptsSync', () => { assert.ok(!await fileService.exists(dirname(conflicts[0].previewResource))); }); - test('• merge when there are multiple prompts and all prompts are merged', async () => { + test('merge when there are multiple prompts and all prompts are merged', async () => { const environmentService = testClient.instantiationService.get(IEnvironmentService); await updatePrompt('sublime.prompt.md', PROMPT4_TEXT, testClient); @@ -644,7 +644,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); }); - test('• merge when there are multiple prompts and all prompts are merged and applied', async () => { + test('merge when there are multiple prompts and all prompts are merged and applied', async () => { await updatePrompt('short.prompt.md', PROMPT4_TEXT, testClient); await updatePrompt('long.prompt.md', PROMPT2_TEXT, testClient); let preview = await testObject.sync(await testClient.getResourceManifest(), true); @@ -655,7 +655,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); }); - test('• merge when there are multiple prompts and one prompt has no changes and one prompt is merged', async () => { + test('merge when there are multiple prompts and one prompt has no changes and one prompt is merged', async () => { const environmentService = testClient.instantiationService.get(IEnvironmentService); await updatePrompt('coding.prompt.md', PROMPT3_TEXT, client2); @@ -674,7 +674,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); }); - test('• merge when there are multiple prompts and one prompt has no changes and prompts is merged and applied', async () => { + test('merge when there are multiple prompts and one prompt has no changes and prompts is merged and applied', async () => { await updatePrompt('quick.prompt.md', PROMPT3_TEXT, client2); await client2.sync(); @@ -689,7 +689,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); }); - test('• merge when there are multiple prompts with conflicts and all prompts are merged', async () => { + test('merge when there are multiple prompts with conflicts and all prompts are merged', async () => { const environmentService = testClient.instantiationService.get(IEnvironmentService); await updatePrompt('reverse.prompt.md', PROMPT3_TEXT, client2); @@ -713,7 +713,7 @@ suite('PromptsSync', () => { ]); }); - test('• accept when there are multiple prompts with conflicts and only one prompt is accepted', async () => { + test('accept when there are multiple prompts with conflicts and only one prompt is accepted', async () => { const environmentService = testClient.instantiationService.get(IEnvironmentService); await updatePrompt('current.prompt.md', PROMPT3_TEXT, client2); @@ -750,7 +750,7 @@ suite('PromptsSync', () => { ]); }); - test('• accept when there are multiple prompts with conflicts and all prompts are accepted', async () => { + test('accept when there are multiple prompts with conflicts and all prompts are accepted', async () => { const environmentService = testClient.instantiationService.get(IEnvironmentService); await updatePrompt('dynamic.prompt.md', PROMPT3_TEXT, client2); @@ -785,7 +785,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); }); - test('• accept when there are multiple prompts with conflicts and all prompts are accepted and applied', async () => { + test('accept when there are multiple prompts with conflicts and all prompts are accepted and applied', async () => { const environmentService = testClient.instantiationService.get(IEnvironmentService); await updatePrompt('edicational.prompt.md', PROMPT3_TEXT, client2); await updatePrompt('unknown.prompt.md', PROMPT1_TEXT, client2); @@ -833,7 +833,7 @@ suite('PromptsSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); }); - test('• sync profile prompts', async () => { + test('sync profile prompts', async () => { const client2 = disposableStore.add(new UserDataSyncClient(server)); await client2.setUp(true); const profile = await client2.instantiationService.get(IUserDataProfilesService).createNamedProfile('profile1'); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts index d8e551d766b..d284843f94a 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts @@ -48,7 +48,7 @@ export class TestChatPromptCodec extends TestDecoder { const testDisposables = ensureNoDisposablesAreLeakedInTestSuite(); - test('• produces expected tokens', async () => { + test('produces expected tokens', async () => { const test = testDisposables.add(new TestChatPromptCodec()); await test.run( diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts index 893986f2a59..e8c57961a94 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts @@ -52,7 +52,7 @@ export class TestChatPromptDecoder extends TestDecoder { const testDisposables = ensureNoDisposablesAreLeakedInTestSuite(); - test('• produces expected tokens', async () => { + test('produces expected tokens', async () => { const test = testDisposables.add( new TestChatPromptDecoder(), ); @@ -205,8 +205,8 @@ suite('ChatPromptDecoder', () => { ); }); - suite('• variables', () => { - test('• produces expected tokens', async () => { + suite('variables', () => { + test('produces expected tokens', async () => { const test = testDisposables.add( new TestChatPromptDecoder(), ); @@ -263,8 +263,8 @@ suite('ChatPromptDecoder', () => { }); }); - suite('• commands', () => { - test('• produces expected tokens', async () => { + suite('commands', () => { + test('produces expected tokens', async () => { const test = testDisposables.add( new TestChatPromptDecoder(), ); @@ -350,8 +350,8 @@ suite('ChatPromptDecoder', () => { }); }); - suite('• template variables', () => { - test('• produces expected tokens', async () => { + suite('template variables', () => { + test('produces expected tokens', async () => { const test = testDisposables.add( new TestChatPromptDecoder(), ); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts index 51955d8ec64..da2d62f7e48 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts @@ -148,9 +148,9 @@ suite('MarkdownExtensionsDecoder', () => { return new Array(dashCount).fill('-').join(''); }; - suite('• Front Matter header', () => { - suite('• successful cases', () => { - test('• produces expected tokens', async () => { + suite('Front Matter header', () => { + suite('successful cases', () => { + test('produces expected tokens', async () => { const test = disposables.add( new TestMarkdownExtensionsDecoder(), ); @@ -206,7 +206,7 @@ suite('MarkdownExtensionsDecoder', () => { ); }); - test('• can contain dashes in the header contents', async () => { + test('can contain dashes in the header contents', async () => { const test = disposables.add( new TestMarkdownExtensionsDecoder(), ); @@ -276,7 +276,7 @@ suite('MarkdownExtensionsDecoder', () => { ); }); - test('• can be at the end of the file', async () => { + test('can be at the end of the file', async () => { const test = disposables.add( new TestMarkdownExtensionsDecoder(), ); @@ -326,8 +326,8 @@ suite('MarkdownExtensionsDecoder', () => { }); }); - suite('• failure cases', () => { - test('• fails if header starts not on the first line', async () => { + suite('failure cases', () => { + test('fails if header starts not on the first line', async () => { const test = disposables.add( new TestMarkdownExtensionsDecoder(), ); @@ -366,7 +366,7 @@ suite('MarkdownExtensionsDecoder', () => { ); }); - test('• fails if header markers do not match (start marker is longer)', async () => { + test('fails if header markers do not match (start marker is longer)', async () => { const test = disposables.add( new TestMarkdownExtensionsDecoder(), ); @@ -404,7 +404,7 @@ suite('MarkdownExtensionsDecoder', () => { ); }); - test('• fails if header markers do not match (end marker is longer)', async () => { + test('fails if header markers do not match (end marker is longer)', async () => { const test = disposables.add( new TestMarkdownExtensionsDecoder(), ); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts index 3478fd7d34d..193354e7759 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts @@ -16,7 +16,7 @@ import { PromptVariable, PromptVariableWithData } from '../../../../../common/pr suite('FileReference', () => { ensureNoDisposablesAreLeakedInTestSuite(); - test('• linkRange', () => { + test('linkRange', () => { const lineNumber = randomInt(100, 1); const columnStartNumber = randomInt(100, 1); const path = `/temp/test/file-${randomInt(Number.MAX_SAFE_INTEGER)}.txt`; @@ -48,7 +48,7 @@ suite('FileReference', () => { ); }); - test('• path', () => { + test('path', () => { const lineNumber = randomInt(100, 1); const columnStartNumber = randomInt(100, 1); const link = `/temp/test/file-${randomInt(Number.MAX_SAFE_INTEGER)}.txt`; @@ -69,7 +69,7 @@ suite('FileReference', () => { ); }); - test('• extends `PromptVariableWithData` and others', () => { + test('extends `PromptVariableWithData` and others', () => { const lineNumber = randomInt(100, 1); const columnStartNumber = randomInt(100, 1); const link = `/temp/test/file-${randomInt(Number.MAX_SAFE_INTEGER)}.txt`; diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts index 88218fd26d4..d4fa753ddec 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts @@ -55,7 +55,7 @@ suite('FilePromptContentsProvider', () => { instantiationService.stub(IConfigurationService, nullConfigService); }); - test('• provides contents of a file', async () => { + test('provides contents of a file', async () => { const fileService = instantiationService.get(IFileService); const fileName = `file-${randomInt(10000)}.prompt.md`; @@ -108,9 +108,9 @@ suite('FilePromptContentsProvider', () => { ); }); - suite('• options', () => { - suite('• allowNonPromptFiles', () => { - test('• true', async () => { + suite('options', () => { + suite('allowNonPromptFiles', () => { + test('true', async () => { const fileService = instantiationService.get(IFileService); const fileName = (randomBoolean() === true) @@ -166,7 +166,7 @@ suite('FilePromptContentsProvider', () => { ); }); - test('• false', async () => { + test('false', async () => { const fileService = instantiationService.get(IFileService); const fileName = (randomBoolean() === true) @@ -206,7 +206,7 @@ suite('FilePromptContentsProvider', () => { ); }); - test('• undefined', async () => { + test('undefined', async () => { const fileService = instantiationService.get(IFileService); const fileName = (randomBoolean() === true) diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts index 32783cd5525..013e8ebb23c 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts @@ -177,7 +177,7 @@ suite('TextModelPromptParser', () => { ); }; - test('• core logic #1', async () => { + test('core logic #1', async () => { const test = createTest( URI.file('/foo/bar.md'), [ @@ -227,7 +227,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• core logic #2', async () => { + test('core logic #2', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -289,7 +289,7 @@ suite('TextModelPromptParser', () => { ]); }); - suite('• header', () => { + suite('header', () => { suite(' • metadata', () => { suite(' • instructions', () => { test(`• empty header`, async () => { @@ -591,8 +591,8 @@ suite('TextModelPromptParser', () => { }); }); - suite('• diagnostics', () => { - test('• core logic', async () => { + suite('diagnostics', () => { + test('core logic', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -685,8 +685,8 @@ suite('TextModelPromptParser', () => { ]); }); - suite('• tools metadata', () => { - test('• tool names can be quoted and non-quoted string', async () => { + suite('tools metadata', () => { + test('tool names can be quoted and non-quoted string', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -722,9 +722,9 @@ suite('TextModelPromptParser', () => { }); }); - suite('• applyTo metadata', () => { - suite('• language', () => { - test('• prompt', async () => { + suite('applyTo metadata', () => { + suite('language', () => { + test('prompt', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -762,7 +762,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• instructions', async () => { + test('instructions', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -802,7 +802,7 @@ suite('TextModelPromptParser', () => { }); }); - test('• invalid glob pattern', async () => { + test('invalid glob pattern', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -843,9 +843,9 @@ suite('TextModelPromptParser', () => { ]); }); - suite('• mode', () => { - suite('• invalid', () => { - test('• quoted string value', async () => { + suite('mode', () => { + suite('invalid', () => { + test('quoted string value', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -873,7 +873,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• single-token unquoted-string value', async () => { + test('single-token unquoted-string value', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -901,7 +901,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• unquoted string value', async () => { + test('unquoted string value', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -929,7 +929,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• multi-token unquoted-string value', async () => { + test('multi-token unquoted-string value', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -957,7 +957,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• after a description metadata', async () => { + test('after a description metadata', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -986,7 +986,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• boolean value', async () => { + test('boolean value', async () => { const booleanValue = randomBoolean(); const test = createTest( @@ -1016,7 +1016,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• empty quoted string value', async () => { + test('empty quoted string value', async () => { const quotedString = (randomBoolean()) ? `''` : '""'; @@ -1048,7 +1048,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• empty value', async () => { + test('empty value', async () => { const value = (randomBoolean()) ? '\t\t \t\t' : ' \t \v \t '; @@ -1080,7 +1080,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• void value', async () => { + test('void value', async () => { const test = createTest( URI.file('/absolute/folder/and/a/my.prompt.md'), [ @@ -1110,9 +1110,9 @@ suite('TextModelPromptParser', () => { }); }); - suite('• tools and mode compatibility', () => { - suite('• tools is set', () => { - test('• ask mode', async () => { + suite('tools and mode compatibility', () => { + suite('tools is set', () => { + test('ask mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1158,7 +1158,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• edit mode', async () => { + test('edit mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1204,7 +1204,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• agent mode', async () => { + test('agent mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1245,7 +1245,7 @@ suite('TextModelPromptParser', () => { await test.validateHeaderDiagnostics([]); }); - test('• no mode', async () => { + test('no mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1285,7 +1285,7 @@ suite('TextModelPromptParser', () => { await test.validateHeaderDiagnostics([]); }); - test('• invalid mode', async () => { + test('invalid mode', async () => { const value = (randomBoolean()) ? 'unknown mode ' : 'unknown'; @@ -1336,8 +1336,8 @@ suite('TextModelPromptParser', () => { }); }); - suite('• tools is not set', () => { - test('• ask mode', async () => { + suite('tools is not set', () => { + test('ask mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1383,7 +1383,7 @@ suite('TextModelPromptParser', () => { ]); }); - test('• edit mode', async () => { + test('edit mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1424,7 +1424,7 @@ suite('TextModelPromptParser', () => { await test.validateHeaderDiagnostics([]); }); - test('• agent mode', async () => { + test('agent mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1464,7 +1464,7 @@ suite('TextModelPromptParser', () => { await test.validateHeaderDiagnostics([]); }); - test('• no mode', async () => { + test('no mode', async () => { const test = createTest( URI.file('/absolute/folder/and/a/filename.txt'), [ @@ -1506,7 +1506,7 @@ suite('TextModelPromptParser', () => { }); }); - test('• gets disposed with the model', async () => { + test('gets disposed with the model', async () => { const test = createTest( URI.file('/some/path/file.prompt.md'), [ @@ -1527,7 +1527,7 @@ suite('TextModelPromptParser', () => { ); }); - test('• toString()', async () => { + test('toString()', async () => { const modelUri = URI.file('/Users/legomushroom/repos/prompt-snippets/README.md'); const test = createTest( modelUri, diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts index d088ebe6178..45b5a66787b 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts @@ -242,7 +242,7 @@ suite('PromptFileReference', function () { }); }); - test('• resolves nested file references', async function () { + test('resolves nested file references', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -392,7 +392,7 @@ suite('PromptFileReference', function () { await test.run(); }); - test('• does not fall into infinite reference recursion', async function () { + test('does not fall into infinite reference recursion', async function () { const rootFolderName = 'infinite-recursion'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -541,8 +541,8 @@ suite('PromptFileReference', function () { await test.run(); }); - suite('• options', () => { - test('• allowNonPromptFiles', async function () { + suite('options', () => { + test('allowNonPromptFiles', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -693,8 +693,8 @@ suite('PromptFileReference', function () { }); }); - suite('• metadata', () => { - test('• tools', async function () { + suite('metadata', () => { + test('tools', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -905,8 +905,8 @@ suite('PromptFileReference', function () { ); }); - suite('• applyTo', () => { - test('• prompt language', async function () { + suite('applyTo', () => { + test('prompt language', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -1024,7 +1024,7 @@ suite('PromptFileReference', function () { }); - test('• instructions language', async function () { + test('instructions language', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -1136,8 +1136,8 @@ suite('PromptFileReference', function () { }); }); - suite('• tools and mode compatibility', () => { - test('• tools are ignored if root prompt is in the ask mode', async function () { + suite('tools and mode compatibility', () => { + test('tools are ignored if root prompt is in the ask mode', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -1248,7 +1248,7 @@ suite('PromptFileReference', function () { ); }); - test('• tools are ignored if root prompt is in the edit mode', async function () { + test('tools are ignored if root prompt is in the edit mode', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -1358,7 +1358,7 @@ suite('PromptFileReference', function () { ); }); - test('• tools are not ignored if root prompt is in the agent mode', async function () { + test('tools are not ignored if root prompt is in the agent mode', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); @@ -1472,7 +1472,7 @@ suite('PromptFileReference', function () { ); }); - test('• tools are not ignored if root prompt implicitly in the agent mode', async function () { + test('tools are not ignored if root prompt implicitly in the agent mode', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; const rootUri = URI.file(rootFolder); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts index 65460a234af..1b169671e33 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts @@ -133,8 +133,8 @@ suite('PromptsService', () => { service = disposables.add(instaService.createInstance(PromptsService)); }); - suite('• getParserFor', () => { - test('• provides cached parser instance', async () => { + suite('getParserFor', () => { + test('provides cached parser instance', async () => { // both languages must yield the same result const languageId = (randomBoolean()) ? PROMPT_LANGUAGE_ID @@ -459,7 +459,7 @@ suite('PromptsService', () => { ); }); - test('• auto-updated on model changes', async () => { + test('auto-updated on model changes', async () => { const langId = 'bazLang'; const model = disposables.add(createTextModel( @@ -527,7 +527,7 @@ suite('PromptsService', () => { ); }); - test('• throws if a disposed model provided', async function () { + test('throws if a disposed model provided', async function () { const model = disposables.add(createTextModel( 'test1\ntest2\n\ntest3\t\n', 'barLang', @@ -544,8 +544,8 @@ suite('PromptsService', () => { }); }); - suite('• getAllMetadata', () => { - test('• explicit', async function () { + suite('getAllMetadata', () => { + test('explicit', async function () { const rootFolderName = 'resolves-nested-file-references'; const rootFolder = `/${rootFolderName}`; @@ -702,12 +702,12 @@ suite('PromptsService', () => { }); }); - suite('• findInstructionFilesFor', () => { + suite('findInstructionFilesFor', () => { teardown(() => { sinon.restore(); }); - test('• finds correct instruction files', async () => { + test('finds correct instruction files', async () => { const rootFolderName = 'finds-instruction-files'; const rootFolder = `/${rootFolderName}`; const rootFolderUri = URI.file(rootFolder); @@ -886,7 +886,7 @@ suite('PromptsService', () => { ); }); - test('• does not have duplicates', async () => { + test('does not have duplicates', async () => { const rootFolderName = 'finds-instruction-files-without-duplicates'; const rootFolder = `/${rootFolderName}`; const rootFolderUri = URI.file(rootFolder); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts index 05f1b5741f3..4d1fb9178fd 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts @@ -195,7 +195,7 @@ suite('MockFilesystem', () => { instantiationService.stub(IFileService, fileService); }); - test('• mocks file structure', async () => { + test('mocks file structure', async () => { const mockFilesystem = instantiationService.createInstance(MockFilesystem, [ { name: '/root/folder', diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts index e6957fb43be..9c4f0a3165c 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts @@ -148,11 +148,11 @@ suite('PromptFilesLocator', () => { return instantiationService.createInstance(PromptFilesLocator); }; - suite('• empty workspace', () => { + suite('empty workspace', () => { const EMPTY_WORKSPACE: string[] = []; - suite('• empty filesystem', () => { - test('• no config value', async () => { + suite('empty filesystem', () => { + test('no config value', async () => { const locator = await createPromptsLocator(undefined, EMPTY_WORKSPACE, []); assertOutcome( @@ -163,7 +163,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• object config value', async () => { + test('object config value', async () => { const locator = await createPromptsLocator({ '/Users/legomushroom/repos/prompts/': true, '/tmp/prompts/': false, @@ -177,7 +177,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• array config value', async () => { + test('array config value', async () => { const locator = await createPromptsLocator([ 'relative/path/to/prompts/', '/abs/path', @@ -191,7 +191,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• null config value', async () => { + test('null config value', async () => { const locator = await createPromptsLocator(null, EMPTY_WORKSPACE, []); assertOutcome( @@ -202,7 +202,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• string config value', async () => { + test('string config value', async () => { const locator = await createPromptsLocator('/etc/hosts/prompts', EMPTY_WORKSPACE, []); assertOutcome( @@ -214,8 +214,8 @@ suite('PromptFilesLocator', () => { }); }); - suite('• non-empty filesystem', () => { - test('• core logic', async () => { + suite('non-empty filesystem', () => { + test('core logic', async () => { const locator = await createPromptsLocator( { '/Users/legomushroom/repos/prompts': true, @@ -270,8 +270,8 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - suite('• absolute', () => { - suite('• wild card', () => { + suite('absolute', () => { + suite('wild card', () => { const settings = [ '/Users/legomushroom/repos/vscode/**', '/Users/legomushroom/repos/vscode/**/*.prompt.md', @@ -512,10 +512,10 @@ suite('PromptFilesLocator', () => { }); }); - suite('• single-root workspace', () => { - suite('• glob pattern', () => { - suite('• relative', () => { - suite('• wild card', () => { + suite('single-root workspace', () => { + suite('glob pattern', () => { + suite('relative', () => { + suite('wild card', () => { const testSettings = [ '**', '**/*.prompt.md', @@ -754,8 +754,8 @@ suite('PromptFilesLocator', () => { }); }); - suite('• absolute', () => { - suite('• wild card', () => { + suite('absolute', () => { + suite('wild card', () => { const settings = [ '/Users/legomushroom/repos/vscode/**', '/Users/legomushroom/repos/vscode/**/*.prompt.md', @@ -996,7 +996,7 @@ suite('PromptFilesLocator', () => { }); }); - test('• core logic', async () => { + test('core logic', async () => { const locator = await createPromptsLocator( { '/Users/legomushroom/repos/prompts': true, @@ -1078,7 +1078,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• with disabled `.github/prompts` location', async () => { + test('with disabled `.github/prompts` location', async () => { const locator = await createPromptsLocator( { '/Users/legomushroom/repos/prompts': true, @@ -1164,9 +1164,9 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - suite('• multi-root workspace', () => { - suite('• core logic', () => { - test('• without top-level `.github` folder', async () => { + suite('multi-root workspace', () => { + suite('core logic', () => { + test('without top-level `.github` folder', async () => { const locator = await createPromptsLocator( { '/Users/legomushroom/repos/prompts': true, @@ -1286,7 +1286,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• with top-level `.github` folder', async () => { + test('with top-level `.github` folder', async () => { const locator = await createPromptsLocator( { '/Users/legomushroom/repos/prompts': true, @@ -1409,7 +1409,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• with disabled `.github/prompts` location', async () => { + test('with disabled `.github/prompts` location', async () => { const locator = await createPromptsLocator( { '/Users/legomushroom/repos/prompts': true, @@ -1529,7 +1529,7 @@ suite('PromptFilesLocator', () => { locator.dispose(); }); - test('• mixed', async () => { + test('mixed', async () => { const locator = await createPromptsLocator( { '/Users/legomushroom/repos/**/*test*': true, @@ -1660,9 +1660,9 @@ suite('PromptFilesLocator', () => { }); }); - suite('• glob pattern', () => { - suite('• relative', () => { - suite('• wild card', () => { + suite('glob pattern', () => { + suite('relative', () => { + suite('wild card', () => { const testSettings = [ '**', '**/*.prompt.md', @@ -1980,8 +1980,8 @@ suite('PromptFilesLocator', () => { }); }); - suite('• absolute', () => { - suite('• wild card', () => { + suite('absolute', () => { + suite('wild card', () => { const testSettings = [ '/Users/legomushroom/repos/**', '/Users/legomushroom/repos/**/*.prompt.md', @@ -2343,8 +2343,8 @@ suite('PromptFilesLocator', () => { }); }); - suite('• isValidGlob', () => { - test('• valid patterns', () => { + suite('isValidGlob', () => { + test('valid patterns', () => { const globs = [ '**', '\*', @@ -2380,7 +2380,7 @@ suite('PromptFilesLocator', () => { } }); - test('• invalid patterns', () => { + test('invalid patterns', () => { const globs = [ '.', '\\*', @@ -2418,8 +2418,8 @@ suite('PromptFilesLocator', () => { }); }); - suite('• getConfigBasedSourceFolders', () => { - test('• gets unambiguous list of folders', async () => { + suite('getConfigBasedSourceFolders', () => { + test('gets unambiguous list of folders', async () => { const locator = await createPromptsLocator( { '.github/prompts': true, diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts index f45cae7dd6b..16927d60d51 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts @@ -15,7 +15,7 @@ import { ExclamationMark, Space, Tab, VerticalTab, Word } from '../../../../../. suite('tree utilities', () => { ensureNoDisposablesAreLeakedInTestSuite(); - test('• flatten', () => { + test('flatten', () => { const tree = { id: '1', children: [ @@ -61,8 +61,8 @@ suite('tree utilities', () => { assert.deepStrictEqual(flatten({}), [{}]); }); - suite('• forEach', () => { - test('• iterates though all nodes', () => { + suite('forEach', () => { + test('iterates though all nodes', () => { const tree = { id: '1', children: [ @@ -120,7 +120,7 @@ suite('tree utilities', () => { ); }); - test('• can be stopped prematurely', () => { + test('can be stopped prematurely', () => { const tree = { id: '1', children: [ @@ -185,8 +185,8 @@ suite('tree utilities', () => { }); }); - suite('• map', () => { - test('• maps a tree', () => { + suite('map', () => { + test('maps a tree', () => { interface ITree { id: string; children?: ITree[]; @@ -295,7 +295,7 @@ suite('tree utilities', () => { ); }); - test('• callback can control resulting children', () => { + test('callback can control resulting children', () => { interface ITree { id: string; children?: ITree[]; @@ -457,7 +457,7 @@ suite('tree utilities', () => { }); }); - test('• curry', () => { + test('curry', () => { const originalFunction = (a: number, b: number, c: number) => { return a + b + c; }; @@ -484,7 +484,7 @@ suite('tree utilities', () => { } }); - suite('• difference', () => { + suite('difference', () => { class TestCompositeToken extends CompositeToken> { public override toString(): string { return `CompositeToken:\n${BaseToken.render(this.children, '\n')})`; @@ -492,7 +492,7 @@ suite('tree utilities', () => { } - test('• tree roots differ (no children)', () => { + test('tree roots differ (no children)', () => { const tree1 = new Word(new Range(1, 1, 1, 1 + 5), 'hello'); const tree2 = new Word(new Range(1, 1, 1, 1 + 5), 'halou'); @@ -507,7 +507,7 @@ suite('tree utilities', () => { ); }); - test('• returns tree difference (single children level)', () => { + test('returns tree difference (single children level)', () => { const tree1 = asTreeNode>( new Word(new Range(1, 1, 1, 1 + 5), 'hello'), [ @@ -548,7 +548,7 @@ suite('tree utilities', () => { ); }); - test('• returns tree difference (multiple children levels)', () => { + test('returns tree difference (multiple children levels)', () => { const compositeToken1 = new TestCompositeToken([ new VerticalTab(new Range(1, 13, 1, 14)), new Space(new Range(1, 14, 1, 15)), @@ -610,7 +610,7 @@ suite('tree utilities', () => { ); }); - test('• returns null for equal trees', () => { + test('returns null for equal trees', () => { const tree1 = new TestCompositeToken([ asTreeNode(new Word( new Range(1, 1, 1, 1 + 5), From 5efdeefa0b31d0a1ce7f42c5346aa073484c0b43 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 11:00:54 +0200 Subject: [PATCH 057/236] deprecate self-dispose object/pattern (#250815) migrate cell entry fyi @DonJayamanne re https://github.com/microsoft/vscode/issues/248366 --- src/vs/base/common/observableDisposable.ts | 12 +++--------- .../notebook/chatEditingNotebookCellEntry.ts | 9 ++++++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/vs/base/common/observableDisposable.ts b/src/vs/base/common/observableDisposable.ts index 41b7a714ddf..91fe9154a41 100644 --- a/src/vs/base/common/observableDisposable.ts +++ b/src/vs/base/common/observableDisposable.ts @@ -6,9 +6,7 @@ import { Disposable, DisposableStore, IDisposable, toDisposable } from './lifecycle.js'; /** - * Disposable object that tracks its {@linkcode isDisposed} state - * as a public attribute and provides the {@linkcode onDispose} - * event to subscribe to. +* @deprecated do not use this, https://github.com/microsoft/vscode/issues/248366 */ export abstract class ObservableDisposable extends Disposable { /** @@ -68,16 +66,12 @@ export abstract class ObservableDisposable extends Disposable { } /** - * Type for a non-disposed object `TObject`. + * @deprecated do not use this, https://github.com/microsoft/vscode/issues/248366 */ type TNotDisposed = TObject & { isDisposed: false }; /** - * Asserts that a provided `object` is not `disposed` yet, - * e.g., its `disposed` property is `false`. - * - * @throws if the provided `object.disposed` equal to `false`. - * @param error Error message or error object to throw if assertion fails. + * @deprecated do not use this, https://github.com/microsoft/vscode/issues/248366 */ export function assertNotDisposed( object: TObject, diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts index 0913bbf6a92..96359ead4e5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { RunOnceScheduler } from '../../../../../../base/common/async.js'; -import { DisposableStore, toDisposable } from '../../../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, toDisposable } from '../../../../../../base/common/lifecycle.js'; import { ITransaction, IObservable, observableValue, autorun, transaction } from '../../../../../../base/common/observable.js'; -import { ObservableDisposable } from '../../../../../../base/common/observableDisposable.js'; import { themeColorFromId } from '../../../../../../base/common/themables.js'; import { URI } from '../../../../../../base/common/uri.js'; import { EditOperation, ISingleEditOperation } from '../../../../../../editor/common/core/editOperation.js'; @@ -37,7 +36,7 @@ import { pendingRewriteMinimap } from '../chatEditingModifiedFileEntry.js'; * Most of the code has been borrowed from there, as a cell is effectively a document. * Hence most of the same functionality applies. */ -export class ChatEditingNotebookCellEntry extends ObservableDisposable { +export class ChatEditingNotebookCellEntry extends Disposable { private static readonly _lastEditDecorationOptions = ModelDecorationOptions.register({ isWholeLine: true, description: 'chat-last-edit', @@ -60,6 +59,10 @@ export class ChatEditingNotebookCellEntry extends ObservableDisposable { }); + public get isDisposed(): boolean { + return this._store.isDisposed; + } + private _edit: StringEdit = StringEdit.empty; private _isEditFromUs: boolean = false; public get isEditFromUs(): boolean { From ff63adf56a3d3bd9858275711def5e09e07cdc31 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 11:11:50 +0200 Subject: [PATCH 058/236] fix https://github.com/microsoft/vscode/issues/247820 (#250816) --- src/vs/base/common/types.ts | 6 ------ .../createPromptCommand/dialogs/askForPromptSourceFolder.ts | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index c895259ac9e..00d8814661e 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from './uri.js'; import { assert } from './assert.js'; /** @@ -342,8 +341,3 @@ export type DeepPartial = { * Represents a type that is a partial version of a given type `T`, except a subset. */ export type PartialExcept = Partial> & Pick; - -/** - * Type for an `object` with its `value` property being a {@link URI}. - */ -export type WithUriValue = T & { value: URI }; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts index 1f8c1f8601c..86ddd6733ae 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts @@ -5,7 +5,6 @@ import { localize } from '../../../../../../../../nls.js'; import { URI } from '../../../../../../../../base/common/uri.js'; -import { WithUriValue } from '../../../../../../../../base/common/types.js'; import { basename, extUri, isEqual } from '../../../../../../../../base/common/resources.js'; import { ILabelService } from '../../../../../../../../platform/label/common/label.js'; import { IOpenerService } from '../../../../../../../../platform/opener/common/opener.js'; @@ -164,7 +163,7 @@ async function showNoFoldersDialog(accessor: ServicesAccessor, type: PromptsType const quickInputService = accessor.get(IQuickInputService); const openerService = accessor.get(IOpenerService); - const docsQuickPick: WithUriValue = { + const docsQuickPick: IQuickPickItem & { value: URI } = { type: 'item', label: getLearnLabel(type), description: PROMPT_DOCUMENTATION_URL, From 2685e2a6b3bc3fceabd689c7b1d4693591b75b37 Mon Sep 17 00:00:00 2001 From: Raffaele Garofalo Date: Fri, 6 Jun 2025 11:17:48 +0200 Subject: [PATCH 059/236] Refactoring editor sticky scroll (#248131) * refactor: enhance documentation for StickyLineCandidateProvider methods #248082 * Removed unusued statement causing hygiene build to fail #244845 * polish --------- Co-authored-by: Aiday Marlen Kyzy Co-authored-by: Aiday Marlen Kyzy --- .../browser/stickyScrollProvider.ts | 134 +++++++++++------- 1 file changed, 85 insertions(+), 49 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts index d5d585d073b..ec587d8c717 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts @@ -9,7 +9,6 @@ import { ILanguageFeaturesService } from '../../../common/services/languageFeatu import { CancellationToken, CancellationTokenSource, } from '../../../../base/common/cancellation.js'; import { EditorOption } from '../../../common/config/editorOptions.js'; import { RunOnceScheduler } from '../../../../base/common/async.js'; -import { Range } from '../../../common/core/range.js'; import { binarySearch } from '../../../../base/common/arrays.js'; import { Event, Emitter } from '../../../../base/common/event.js'; import { ILanguageConfigurationService } from '../../../common/languages/languageConfigurationRegistry.js'; @@ -27,17 +26,33 @@ export class StickyLineCandidate { } export interface IStickyLineCandidateProvider { - + /** + * Dispose resources used by the provider. + */ dispose(): void; - getVersionId(): number | undefined; - update(): Promise; - getCandidateStickyLinesIntersecting(range: StickyRange): StickyLineCandidate[]; - onDidChangeStickyScroll: Event; + /** + * Get the version ID of the sticky model. + */ + getVersionId(): number | undefined; + + /** + * Update the sticky line candidates. + */ + update(): Promise; + + /** + * Get sticky line candidates intersecting a given range. + */ + getCandidateStickyLinesIntersecting(range: StickyRange): StickyLineCandidate[]; + + /** + * Event triggered when sticky scroll changes. + */ + onDidChangeStickyScroll: Event; } export class StickyLineCandidateProvider extends Disposable implements IStickyLineCandidateProvider { - static readonly ID = 'store.contrib.stickyScrollController'; private readonly _onDidChangeStickyScroll = this._register(new Emitter()); @@ -69,6 +84,9 @@ export class StickyLineCandidateProvider extends Disposable implements IStickyLi this.readConfiguration(); } + /** + * Read and apply the sticky scroll configuration. + */ private readConfiguration() { this._sessionStore.clear(); const options = this._editor.getOption(EditorOption.stickyScroll); @@ -76,12 +94,9 @@ export class StickyLineCandidateProvider extends Disposable implements IStickyLi return; } this._sessionStore.add(this._editor.onDidChangeModel(() => { - // We should not show an old model for a different file, it will always be wrong. - // So we clear the model here immediately and then trigger an update. this._model = null; this.updateStickyModelProvider(); this._onDidChangeStickyScroll.fire(); - this.update(); })); this._sessionStore.add(this._editor.onDidChangeHiddenAreas(() => this.update())); @@ -95,17 +110,22 @@ export class StickyLineCandidateProvider extends Disposable implements IStickyLi this.update(); } + /** + * Get the version ID of the sticky model. + */ public getVersionId(): number | undefined { return this._model?.version; } + /** + * Update the sticky model provider. + */ private updateStickyModelProvider() { this._stickyModelProvider?.dispose(); this._stickyModelProvider = null; - const editor = this._editor; - if (editor.hasModel()) { + if (this._editor.hasModel()) { this._stickyModelProvider = new StickyModelProvider( - editor, + this._editor, () => this._updateSoon.schedule(), this._languageConfigurationService, this._languageFeaturesService @@ -113,6 +133,9 @@ export class StickyLineCandidateProvider extends Disposable implements IStickyLi } } + /** + * Update the sticky line candidates. + */ public async update(): Promise { this._cts?.dispose(true); this._cts = new CancellationTokenSource(); @@ -120,29 +143,36 @@ export class StickyLineCandidateProvider extends Disposable implements IStickyLi this._onDidChangeStickyScroll.fire(); } + /** + * Update the sticky model based on the current editor state. + */ private async updateStickyModel(token: CancellationToken): Promise { if (!this._editor.hasModel() || !this._stickyModelProvider || this._editor.getModel().isTooLargeForTokenization()) { this._model = null; return; } const model = await this._stickyModelProvider.update(token); - if (token.isCancellationRequested) { - // the computation was canceled, so do not overwrite the model - return; + if (!token.isCancellationRequested) { + this._model = model; } - this._model = model; } - private updateIndex(index: number) { - if (index === -1) { - index = 0; - } else if (index < 0) { - index = -index - 2; + /** + * Get sticky line candidates intersecting a given range. + */ + public getCandidateStickyLinesIntersecting(range: StickyRange): StickyLineCandidate[] { + if (!this._model?.element) { + return []; } - return index; + const stickyLineCandidates: StickyLineCandidate[] = []; + this.getCandidateStickyLinesIntersectingFromStickyModel(range, this._model.element, stickyLineCandidates, 0, 0, -1); + return this.filterHiddenRanges(stickyLineCandidates); } - public getCandidateStickyLinesIntersectingFromStickyModel( + /** + * Get sticky line candidates intersecting a given range from the sticky model. + */ + private getCandidateStickyLinesIntersectingFromStickyModel( range: StickyRange, outlineModel: StickyElement, result: StickyLineCandidate[], @@ -167,38 +197,44 @@ export class StickyLineCandidateProvider extends Disposable implements IStickyLi for (let i = lowerBound; i <= upperBound; i++) { const child = outlineModel.children[i]; - if (!child) { - return; + if (!child || !child.range) { + continue; } - const childRange = child.range; - if (childRange) { - const childStartLine = childRange.startLineNumber; - const childEndLine = childRange.endLineNumber; - if (range.startLineNumber <= childEndLine + 1 && childStartLine - 1 <= range.endLineNumber && childStartLine !== lastLine) { - lastLine = childStartLine; - const lineHeight = this._editor.getLineHeightForPosition(new Position(childStartLine, 1)); - result.push(new StickyLineCandidate(childStartLine, childEndLine - 1, top, lineHeight)); - this.getCandidateStickyLinesIntersectingFromStickyModel(range, child, result, depth + 1, top + lineHeight, childStartLine); - } - } else { - this.getCandidateStickyLinesIntersectingFromStickyModel(range, child, result, depth, top, lastStartLineNumber); + const { startLineNumber, endLineNumber } = child.range; + if (range.startLineNumber <= endLineNumber + 1 && startLineNumber - 1 <= range.endLineNumber && startLineNumber !== lastLine) { + lastLine = startLineNumber; + const lineHeight = this._editor.getLineHeightForPosition(new Position(startLineNumber, 1)); + result.push(new StickyLineCandidate(startLineNumber, endLineNumber - 1, top, lineHeight)); + this.getCandidateStickyLinesIntersectingFromStickyModel(range, child, result, depth + 1, top + lineHeight, startLineNumber); } } } - public getCandidateStickyLinesIntersecting(range: StickyRange): StickyLineCandidate[] { - if (!this._model?.element) { - return []; + /** + * Filter out sticky line candidates that are within hidden ranges. + */ + private filterHiddenRanges(stickyLineCandidates: StickyLineCandidate[]): StickyLineCandidate[] { + const hiddenRanges = this._editor._getViewModel()?.getHiddenAreas(); + if (!hiddenRanges) { + return stickyLineCandidates; } - let stickyLineCandidates: StickyLineCandidate[] = []; - this.getCandidateStickyLinesIntersectingFromStickyModel(range, this._model.element, stickyLineCandidates, 0, 0, -1); - const hiddenRanges: Range[] | undefined = this._editor._getViewModel()?.getHiddenAreas(); + return stickyLineCandidates.filter(candidate => { + return !hiddenRanges.some(hiddenRange => + candidate.startLineNumber >= hiddenRange.startLineNumber && + candidate.endLineNumber <= hiddenRange.endLineNumber + 1 + ); + }); + } - if (hiddenRanges) { - for (const hiddenRange of hiddenRanges) { - stickyLineCandidates = stickyLineCandidates.filter(stickyLine => !(stickyLine.startLineNumber >= hiddenRange.startLineNumber && stickyLine.endLineNumber <= hiddenRange.endLineNumber + 1)); - } + /** + * Update the binary search index. + */ + private updateIndex(index: number): number { + if (index === -1) { + return 0; + } else if (index < 0) { + return -index - 2; } - return stickyLineCandidates; + return index; } } From d9145a291dcef0bad3ace81a3d55727ca294c122 Mon Sep 17 00:00:00 2001 From: Enzo Nunes Date: Fri, 6 Jun 2025 10:22:37 +0100 Subject: [PATCH 060/236] Fix line comment action for makefiles (Fixes #234464) (#243283) * Fix line comment action for makefiles (Fixes #234464) Pass languageId to _analyzeLines to distinguish makefiles from the rest of the languages. Add test to _analyzeLines specifically for makefiles. * Remove hardcoded string. Apply fix at LanguageConfigurationService. Add comment rule to specify fixed column token placement. Change test scope to test line command instead of just testing the _analyzeLines method. * change added field to use bool instead of user-chosen offset * add check to remove comment detection * add check to following space removal * update branch. add config interface for new noindent option. adapt existing logic for new config format. * fix small issue with following space removal * polish --------- Co-authored-by: Aiday Marlen Kyzy --- extensions/make/language-configuration.json | 5 ++- .../common/languages/languageConfiguration.ts | 20 +++++++++-- .../languageConfigurationRegistry.ts | 8 ++++- .../comment/browser/lineCommentCommand.ts | 15 +++++--- .../test/browser/lineCommentCommand.test.ts | 24 +++++++++++-- src/vs/monaco.d.ts | 20 +++++++++-- .../languageConfigurationExtensionPoint.ts | 36 +++++++++++++++---- 7 files changed, 109 insertions(+), 19 deletions(-) diff --git a/extensions/make/language-configuration.json b/extensions/make/language-configuration.json index 82645b84dfb..05881278a62 100644 --- a/extensions/make/language-configuration.json +++ b/extensions/make/language-configuration.json @@ -1,6 +1,9 @@ { "comments": { - "lineComment": "#" + "lineComment": { + "comment": "#", + "noIndent": true + } }, "brackets": [ [ diff --git a/src/vs/editor/common/languages/languageConfiguration.ts b/src/vs/editor/common/languages/languageConfiguration.ts index b6aa902f78a..c569efd68c1 100644 --- a/src/vs/editor/common/languages/languageConfiguration.ts +++ b/src/vs/editor/common/languages/languageConfiguration.ts @@ -7,14 +7,30 @@ import { CharCode } from '../../../base/common/charCode.js'; import { StandardTokenType } from '../encodedTokenAttributes.js'; import { ScopedLineTokens } from './supports.js'; +/** + * Configuration for line comments. + */ +export interface LineCommentConfig { + /** + * The line comment token, like `//` + */ + comment: string; + /** + * Whether the comment token should not be indented and placed at the first column. + * Defaults to false. + */ + noIndent?: boolean; +} + /** * Describes how comments for a language work. */ export interface CommentRule { /** - * The line comment token, like `// this is a comment` + * The line comment token, like `// this is a comment`. + * Can be a string or an object with comment and optional noIndent properties. */ - lineComment?: string | null; + lineComment?: string | LineCommentConfig | null; /** * The block comment character pair, like `/* block comment */` */ diff --git a/src/vs/editor/common/languages/languageConfigurationRegistry.ts b/src/vs/editor/common/languages/languageConfigurationRegistry.ts index f42b06d0b74..a545b571a8e 100644 --- a/src/vs/editor/common/languages/languageConfigurationRegistry.ts +++ b/src/vs/editor/common/languages/languageConfigurationRegistry.ts @@ -27,6 +27,7 @@ import { LanguageBracketsConfiguration } from './supports/languageBracketsConfig */ export interface ICommentsConfiguration { lineCommentToken?: string; + lineCommentNoIndent?: boolean; blockCommentStartToken?: string; blockCommentEndToken?: string; } @@ -456,7 +457,12 @@ export class ResolvedLanguageConfiguration { const comments: ICommentsConfiguration = {}; if (commentRule.lineComment) { - comments.lineCommentToken = commentRule.lineComment; + if (typeof commentRule.lineComment === 'string') { + comments.lineCommentToken = commentRule.lineComment; + } else { + comments.lineCommentToken = commentRule.lineComment.comment; + comments.lineCommentNoIndent = commentRule.lineComment.noIndent; + } } if (commentRule.blockComment) { const [blockStart, blockEnd] = commentRule.blockComment; diff --git a/src/vs/editor/contrib/comment/browser/lineCommentCommand.ts b/src/vs/editor/contrib/comment/browser/lineCommentCommand.ts index 53875399585..9b169645d6b 100644 --- a/src/vs/editor/contrib/comment/browser/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/browser/lineCommentCommand.ts @@ -112,9 +112,12 @@ export class LineCommentCommand implements ICommand { * Analyze lines and decide which lines are relevant and what the toggle should do. * Also, build up several offsets and lengths useful in the generation of editor operations. */ - public static _analyzeLines(type: Type, insertSpace: boolean, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number, ignoreEmptyLines: boolean, ignoreFirstLine: boolean, languageConfigurationService: ILanguageConfigurationService): IPreflightData { + public static _analyzeLines(type: Type, insertSpace: boolean, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number, ignoreEmptyLines: boolean, ignoreFirstLine: boolean, languageConfigurationService: ILanguageConfigurationService, languageId: string): IPreflightData { let onlyWhitespaceLines = true; + const config = languageConfigurationService.getLanguageConfiguration(languageId).comments; + const lineCommentNoIndent = config?.lineCommentNoIndent ?? false; + let shouldRemoveComments: boolean; if (type === Type.Toggle) { shouldRemoveComments = true; @@ -140,15 +143,16 @@ export class LineCommentCommand implements ICommand { if (lineContentStartOffset === -1) { // Empty or whitespace only line lineData.ignore = ignoreEmptyLines; - lineData.commentStrOffset = lineContent.length; + lineData.commentStrOffset = lineCommentNoIndent ? 0 : lineContent.length; continue; } onlyWhitespaceLines = false; + const offset = lineCommentNoIndent ? 0 : lineContentStartOffset; lineData.ignore = false; - lineData.commentStrOffset = lineContentStartOffset; + lineData.commentStrOffset = offset; - if (shouldRemoveComments && !BlockCommentCommand._haystackHasNeedleAtOffset(lineContent, lineData.commentStr, lineContentStartOffset)) { + if (shouldRemoveComments && !BlockCommentCommand._haystackHasNeedleAtOffset(lineContent, lineData.commentStr, offset)) { if (type === Type.Toggle) { // Every line so far has been a line comment, but this one is not shouldRemoveComments = false; @@ -190,13 +194,14 @@ export class LineCommentCommand implements ICommand { */ public static _gatherPreflightData(type: Type, insertSpace: boolean, model: ITextModel, startLineNumber: number, endLineNumber: number, ignoreEmptyLines: boolean, ignoreFirstLine: boolean, languageConfigurationService: ILanguageConfigurationService): IPreflightData { const lines = LineCommentCommand._gatherPreflightCommentStrings(model, startLineNumber, endLineNumber, languageConfigurationService); + const languageId = model.getLanguageIdAtPosition(startLineNumber, 1); if (lines === null) { return { supported: false }; } - return LineCommentCommand._analyzeLines(type, insertSpace, model, lines, startLineNumber, ignoreEmptyLines, ignoreFirstLine, languageConfigurationService); + return LineCommentCommand._analyzeLines(type, insertSpace, model, lines, startLineNumber, ignoreEmptyLines, ignoreFirstLine, languageConfigurationService, languageId); } /** diff --git a/src/vs/editor/contrib/comment/test/browser/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/browser/lineCommentCommand.test.ts index e738c1d865d..0d8bd9f4151 100644 --- a/src/vs/editor/contrib/comment/test/browser/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/browser/lineCommentCommand.test.ts @@ -48,6 +48,11 @@ suite('Editor Contrib - Line Comment Command', () => { (accessor, sel) => new LineCommentCommand(accessor.get(ILanguageConfigurationService), sel, 4, Type.ForceAdd, true, true) ); + const testLineCommentCommandTokenFirstColumn = createTestCommandHelper( + { lineComment: { comment: '!@#', noIndent: true }, blockComment: [''] }, + (accessor, sel) => new LineCommentCommand(accessor.get(ILanguageConfigurationService), sel, 4, Type.Toggle, true, true) + ); + test('comment single line', function () { testLineCommentCommand( [ @@ -81,6 +86,21 @@ suite('Editor Contrib - Line Comment Command', () => { ); }); + test('comment with token column fixed', function () { + testLineCommentCommandTokenFirstColumn( + [ + 'some text', + '\tsome more text' + ], + new Selection(2, 1, 2, 1), + [ + 'some text', + '!@# \tsome more text' + ], + new Selection(2, 5, 2, 5) + ); + }); + function createSimpleModel(lines: string[]): ISimpleModel { return { getLineContent: (lineNumber: number) => { @@ -110,7 +130,7 @@ suite('Editor Contrib - Line Comment Command', () => { ' ', ' c', '\t\td' - ]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1, true, false, disposable.add(new TestLanguageConfigurationService())); + ]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1, true, false, disposable.add(new TestLanguageConfigurationService()), 'plaintext'); if (!r.supported) { throw new Error(`unexpected`); } @@ -141,7 +161,7 @@ suite('Editor Contrib - Line Comment Command', () => { ' rem ', ' !@# c', '\t\t!@#d' - ]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1, true, false, disposable.add(new TestLanguageConfigurationService())); + ]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1, true, false, disposable.add(new TestLanguageConfigurationService()), 'plaintext'); if (!r.supported) { throw new Error(`unexpected`); } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 115c7b8640d..e204ee859ef 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -6709,14 +6709,30 @@ declare namespace monaco.languages { }>; } + /** + * Configuration for line comments. + */ + export interface LineCommentConfig { + /** + * The line comment token, like `//` + */ + comment: string; + /** + * Whether the comment token should not be indented and placed at the first column. + * Defaults to false. + */ + noIndent?: boolean; + } + /** * Describes how comments for a language work. */ export interface CommentRule { /** - * The line comment token, like `// this is a comment` + * The line comment token, like `// this is a comment`. + * Can be a string or an object with comment and optional noIndent properties. */ - lineComment?: string | null; + lineComment?: string | LineCommentConfig | null; /** * The block comment character pair, like `/* block comment */` */ diff --git a/src/vs/workbench/contrib/codeEditor/common/languageConfigurationExtensionPoint.ts b/src/vs/workbench/contrib/codeEditor/common/languageConfigurationExtensionPoint.ts index 80aa77d2019..739ae4a7706 100644 --- a/src/vs/workbench/contrib/codeEditor/common/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/contrib/codeEditor/common/languageConfigurationExtensionPoint.ts @@ -161,11 +161,22 @@ export class LanguageConfigurationFileHandler extends Disposable { let result: CommentRule | undefined = undefined; if (typeof source.lineComment !== 'undefined') { - if (typeof source.lineComment !== 'string') { - console.warn(`[${languageId}]: language configuration: expected \`comments.lineComment\` to be a string.`); - } else { + if (typeof source.lineComment === 'string') { result = result || {}; result.lineComment = source.lineComment; + } else if (types.isObject(source.lineComment)) { + const lineCommentObj = source.lineComment as any; + if (typeof lineCommentObj.comment === 'string') { + result = result || {}; + result.lineComment = { + comment: lineCommentObj.comment, + noIndent: lineCommentObj.noIndent + }; + } else { + console.warn(`[${languageId}]: language configuration: expected \`comments.lineComment.comment\` to be a string.`); + } + } else { + console.warn(`[${languageId}]: language configuration: expected \`comments.lineComment\` to be a string or an object with comment property.`); } } if (typeof source.blockComment !== 'undefined') { @@ -519,7 +530,7 @@ const schema: IJSONSchema = { comments: { default: { blockComment: ['/*', '*/'], - lineComment: '//' + lineComment: { comment: '//', noIndent: false } }, description: nls.localize('schema.comments', 'Defines the comment symbols'), type: 'object', @@ -536,8 +547,21 @@ const schema: IJSONSchema = { }] }, lineComment: { - type: 'string', - description: nls.localize('schema.lineComment', 'The character sequence that starts a line comment.') + type: 'object', + description: nls.localize('schema.lineComment.object', 'Configuration for line comments.'), + properties: { + comment: { + type: 'string', + description: nls.localize('schema.lineComment.comment', 'The character sequence that starts a line comment.') + }, + noIndent: { + type: 'boolean', + description: nls.localize('schema.lineComment.noIndent', 'Whether the comment token should not be indented and placed at the first column. Defaults to false.'), + default: false + } + }, + required: ['comment'], + additionalProperties: false } } }, From 30625ad8e3d5f0e310a9f189c9fc3c308a3196da Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 6 Jun 2025 11:38:58 +0200 Subject: [PATCH 061/236] Verify the range is valid before getting the lin max column (#250450) verify the range is valid before getting the lin max column --- .../editor/contrib/hover/browser/markerHoverParticipant.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/hover/browser/markerHoverParticipant.ts b/src/vs/editor/contrib/hover/browser/markerHoverParticipant.ts index 986e464be99..2cc8ce5757f 100644 --- a/src/vs/editor/contrib/hover/browser/markerHoverParticipant.ts +++ b/src/vs/editor/contrib/hover/browser/markerHoverParticipant.ts @@ -71,7 +71,11 @@ export class MarkerHoverParticipant implements IEditorHoverParticipant Date: Fri, 6 Jun 2025 11:39:28 +0200 Subject: [PATCH 062/236] Consider line comments when determining indentation (#250591) --- .../indentation/browser/indentation.ts | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/vs/editor/contrib/indentation/browser/indentation.ts b/src/vs/editor/contrib/indentation/browser/indentation.ts index 41e9b7fbd32..85e231bfab6 100644 --- a/src/vs/editor/contrib/indentation/browser/indentation.ts +++ b/src/vs/editor/contrib/indentation/browser/indentation.ts @@ -435,18 +435,6 @@ export class AutoIndentOnPaste implements IEditorContribution { let startLineNumber = range.startLineNumber; - while (startLineNumber <= range.endLineNumber) { - if (this.shouldIgnoreLine(model, startLineNumber)) { - startLineNumber++; - continue; - } - break; - } - - if (startLineNumber > range.endLineNumber) { - return; - } - let firstLineText = model.getLineContent(startLineNumber); if (!/\S/.test(firstLineText.substring(0, range.startColumn - 1))) { const indentOfFirstLine = getGoodIndentForLine(autoIndent, model, model.getLanguageId(), startLineNumber, indentConverter, this._languageConfigurationService); @@ -571,23 +559,6 @@ export class AutoIndentOnPaste implements IEditorContribution { return containsOnlyWhitespace; } - private shouldIgnoreLine(model: ITextModel, lineNumber: number): boolean { - model.tokenization.forceTokenization(lineNumber); - const nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber); - if (nonWhitespaceColumn === 0) { - return true; - } - const tokens = model.tokenization.getLineTokens(lineNumber); - if (tokens.getCount() > 0) { - const firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhitespaceColumn); - if (firstNonWhitespaceTokenIndex >= 0 && tokens.getStandardTokenType(firstNonWhitespaceTokenIndex) === StandardTokenType.Comment) { - return true; - } - } - - return false; - } - public dispose(): void { this.callOnDispose.dispose(); this.callOnModel.dispose(); From 507316dcb42300d1cd4c4b8cc1b0986fbeb9beb4 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 6 Jun 2025 11:40:12 +0200 Subject: [PATCH 063/236] Add setting autoindent on paste (#250463) * add setting autoindent on paste * setting value to false * remove ignoring of indentation when indenting line comments * adding back code --- src/vs/editor/common/config/editorOptions.ts | 9 + .../common/standalone/standaloneEnums.ts | 289 ++++++++--------- .../indentation/browser/indentation.ts | 2 +- src/vs/monaco.d.ts | 294 +++++++++--------- 4 files changed, 305 insertions(+), 289 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index bc577bd8807..d619e9f26fa 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -507,6 +507,10 @@ export interface IEditorOptions { * Defaults to advanced. */ autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'; + /** + * Boolean which controls whether to autoindent on paste + */ + autoIndentOnPaste?: boolean; /** * Emulate selection behaviour of tab characters when using spaces for indentation. * This means selection will stick to tab stops. @@ -5503,6 +5507,7 @@ export const enum EditorOption { autoClosingOvertype, autoClosingQuotes, autoIndent, + autoIndentOnPaste, automaticLayout, autoSurround, bracketPairColorization, @@ -5774,6 +5779,10 @@ export const EditorOptions = { description: nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.") } )), + autoIndentOnPaste: register(new EditorBooleanOption( + EditorOption.autoIndentOnPaste, 'autoIndentOnPaste', false, + { description: nls.localize('autoIndentOnPaste', "Controls whether the editor should automatically auto-indent the pasted content.") } + )), automaticLayout: register(new EditorBooleanOption( EditorOption.automaticLayout, 'automaticLayout', false, )), diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 999efdff88e..0e6925acf49 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -188,150 +188,151 @@ export enum EditorOption { autoClosingOvertype = 11, autoClosingQuotes = 12, autoIndent = 13, - automaticLayout = 14, - autoSurround = 15, - bracketPairColorization = 16, - guides = 17, - codeLens = 18, - codeLensFontFamily = 19, - codeLensFontSize = 20, - colorDecorators = 21, - colorDecoratorsLimit = 22, - columnSelection = 23, - comments = 24, - contextmenu = 25, - copyWithSyntaxHighlighting = 26, - cursorBlinking = 27, - cursorSmoothCaretAnimation = 28, - cursorStyle = 29, - cursorSurroundingLines = 30, - cursorSurroundingLinesStyle = 31, - cursorWidth = 32, - disableLayerHinting = 33, - disableMonospaceOptimizations = 34, - domReadOnly = 35, - dragAndDrop = 36, - dropIntoEditor = 37, - experimentalEditContextEnabled = 38, - emptySelectionClipboard = 39, - experimentalGpuAcceleration = 40, - experimentalWhitespaceRendering = 41, - extraEditorClassName = 42, - fastScrollSensitivity = 43, - find = 44, - fixedOverflowWidgets = 45, - folding = 46, - foldingStrategy = 47, - foldingHighlight = 48, - foldingImportsByDefault = 49, - foldingMaximumRegions = 50, - unfoldOnClickAfterEndOfLine = 51, - fontFamily = 52, - fontInfo = 53, - fontLigatures = 54, - fontSize = 55, - fontWeight = 56, - fontVariations = 57, - formatOnPaste = 58, - formatOnType = 59, - glyphMargin = 60, - gotoLocation = 61, - hideCursorInOverviewRuler = 62, - hover = 63, - inDiffEditor = 64, - inlineSuggest = 65, - letterSpacing = 66, - lightbulb = 67, - lineDecorationsWidth = 68, - lineHeight = 69, - lineNumbers = 70, - lineNumbersMinChars = 71, - linkedEditing = 72, - links = 73, - matchBrackets = 74, - minimap = 75, - mouseStyle = 76, - mouseWheelScrollSensitivity = 77, - mouseWheelZoom = 78, - multiCursorMergeOverlapping = 79, - multiCursorModifier = 80, - multiCursorPaste = 81, - multiCursorLimit = 82, - occurrencesHighlight = 83, - occurrencesHighlightDelay = 84, - overtypeCursorStyle = 85, - overtypeOnPaste = 86, - overviewRulerBorder = 87, - overviewRulerLanes = 88, - padding = 89, - pasteAs = 90, - parameterHints = 91, - peekWidgetDefaultFocus = 92, - placeholder = 93, - definitionLinkOpensInPeek = 94, - quickSuggestions = 95, - quickSuggestionsDelay = 96, - readOnly = 97, - readOnlyMessage = 98, - renameOnType = 99, - renderControlCharacters = 100, - renderFinalNewline = 101, - renderLineHighlight = 102, - renderLineHighlightOnlyWhenFocus = 103, - renderValidationDecorations = 104, - renderWhitespace = 105, - revealHorizontalRightPadding = 106, - roundedSelection = 107, - rulers = 108, - scrollbar = 109, - scrollBeyondLastColumn = 110, - scrollBeyondLastLine = 111, - scrollPredominantAxis = 112, - selectionClipboard = 113, - selectionHighlight = 114, - selectOnLineNumbers = 115, - showFoldingControls = 116, - showUnused = 117, - snippetSuggestions = 118, - smartSelect = 119, - smoothScrolling = 120, - stickyScroll = 121, - stickyTabStops = 122, - stopRenderingLineAfter = 123, - suggest = 124, - suggestFontSize = 125, - suggestLineHeight = 126, - suggestOnTriggerCharacters = 127, - suggestSelection = 128, - tabCompletion = 129, - tabIndex = 130, - unicodeHighlighting = 131, - unusualLineTerminators = 132, - useShadowDOM = 133, - useTabStops = 134, - wordBreak = 135, - wordSegmenterLocales = 136, - wordSeparators = 137, - wordWrap = 138, - wordWrapBreakAfterCharacters = 139, - wordWrapBreakBeforeCharacters = 140, - wordWrapColumn = 141, - wordWrapOverride1 = 142, - wordWrapOverride2 = 143, - wrappingIndent = 144, - wrappingStrategy = 145, - showDeprecated = 146, - inlayHints = 147, - effectiveCursorStyle = 148, - editorClassName = 149, - pixelRatio = 150, - tabFocusMode = 151, - layoutInfo = 152, - wrappingInfo = 153, - defaultColorDecorators = 154, - colorDecoratorsActivatedOn = 155, - inlineCompletionsAccessibilityVerbose = 156, - effectiveExperimentalEditContextEnabled = 157 + autoIndentOnPaste = 14, + automaticLayout = 15, + autoSurround = 16, + bracketPairColorization = 17, + guides = 18, + codeLens = 19, + codeLensFontFamily = 20, + codeLensFontSize = 21, + colorDecorators = 22, + colorDecoratorsLimit = 23, + columnSelection = 24, + comments = 25, + contextmenu = 26, + copyWithSyntaxHighlighting = 27, + cursorBlinking = 28, + cursorSmoothCaretAnimation = 29, + cursorStyle = 30, + cursorSurroundingLines = 31, + cursorSurroundingLinesStyle = 32, + cursorWidth = 33, + disableLayerHinting = 34, + disableMonospaceOptimizations = 35, + domReadOnly = 36, + dragAndDrop = 37, + dropIntoEditor = 38, + experimentalEditContextEnabled = 39, + emptySelectionClipboard = 40, + experimentalGpuAcceleration = 41, + experimentalWhitespaceRendering = 42, + extraEditorClassName = 43, + fastScrollSensitivity = 44, + find = 45, + fixedOverflowWidgets = 46, + folding = 47, + foldingStrategy = 48, + foldingHighlight = 49, + foldingImportsByDefault = 50, + foldingMaximumRegions = 51, + unfoldOnClickAfterEndOfLine = 52, + fontFamily = 53, + fontInfo = 54, + fontLigatures = 55, + fontSize = 56, + fontWeight = 57, + fontVariations = 58, + formatOnPaste = 59, + formatOnType = 60, + glyphMargin = 61, + gotoLocation = 62, + hideCursorInOverviewRuler = 63, + hover = 64, + inDiffEditor = 65, + inlineSuggest = 66, + letterSpacing = 67, + lightbulb = 68, + lineDecorationsWidth = 69, + lineHeight = 70, + lineNumbers = 71, + lineNumbersMinChars = 72, + linkedEditing = 73, + links = 74, + matchBrackets = 75, + minimap = 76, + mouseStyle = 77, + mouseWheelScrollSensitivity = 78, + mouseWheelZoom = 79, + multiCursorMergeOverlapping = 80, + multiCursorModifier = 81, + multiCursorPaste = 82, + multiCursorLimit = 83, + occurrencesHighlight = 84, + occurrencesHighlightDelay = 85, + overtypeCursorStyle = 86, + overtypeOnPaste = 87, + overviewRulerBorder = 88, + overviewRulerLanes = 89, + padding = 90, + pasteAs = 91, + parameterHints = 92, + peekWidgetDefaultFocus = 93, + placeholder = 94, + definitionLinkOpensInPeek = 95, + quickSuggestions = 96, + quickSuggestionsDelay = 97, + readOnly = 98, + readOnlyMessage = 99, + renameOnType = 100, + renderControlCharacters = 101, + renderFinalNewline = 102, + renderLineHighlight = 103, + renderLineHighlightOnlyWhenFocus = 104, + renderValidationDecorations = 105, + renderWhitespace = 106, + revealHorizontalRightPadding = 107, + roundedSelection = 108, + rulers = 109, + scrollbar = 110, + scrollBeyondLastColumn = 111, + scrollBeyondLastLine = 112, + scrollPredominantAxis = 113, + selectionClipboard = 114, + selectionHighlight = 115, + selectOnLineNumbers = 116, + showFoldingControls = 117, + showUnused = 118, + snippetSuggestions = 119, + smartSelect = 120, + smoothScrolling = 121, + stickyScroll = 122, + stickyTabStops = 123, + stopRenderingLineAfter = 124, + suggest = 125, + suggestFontSize = 126, + suggestLineHeight = 127, + suggestOnTriggerCharacters = 128, + suggestSelection = 129, + tabCompletion = 130, + tabIndex = 131, + unicodeHighlighting = 132, + unusualLineTerminators = 133, + useShadowDOM = 134, + useTabStops = 135, + wordBreak = 136, + wordSegmenterLocales = 137, + wordSeparators = 138, + wordWrap = 139, + wordWrapBreakAfterCharacters = 140, + wordWrapBreakBeforeCharacters = 141, + wordWrapColumn = 142, + wordWrapOverride1 = 143, + wordWrapOverride2 = 144, + wrappingIndent = 145, + wrappingStrategy = 146, + showDeprecated = 147, + inlayHints = 148, + effectiveCursorStyle = 149, + editorClassName = 150, + pixelRatio = 151, + tabFocusMode = 152, + layoutInfo = 153, + wrappingInfo = 154, + defaultColorDecorators = 155, + colorDecoratorsActivatedOn = 156, + inlineCompletionsAccessibilityVerbose = 157, + effectiveExperimentalEditContextEnabled = 158 } /** diff --git a/src/vs/editor/contrib/indentation/browser/indentation.ts b/src/vs/editor/contrib/indentation/browser/indentation.ts index 85e231bfab6..46e4374208f 100644 --- a/src/vs/editor/contrib/indentation/browser/indentation.ts +++ b/src/vs/editor/contrib/indentation/browser/indentation.ts @@ -386,7 +386,7 @@ export class AutoIndentOnPaste implements IEditorContribution { this.callOnModel.clear(); // we are disabled - if (this.editor.getOption(EditorOption.autoIndent) < EditorAutoIndentStrategy.Full || !this.editor.getOption(EditorOption.formatOnPaste)) { + if (!this.editor.getOption(EditorOption.autoIndentOnPaste) || this.editor.getOption(EditorOption.autoIndent) < EditorAutoIndentStrategy.Full) { return; } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index e204ee859ef..b0008b0ff59 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3568,6 +3568,10 @@ declare namespace monaco.editor { * Defaults to advanced. */ autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'; + /** + * Boolean which controls whether to autoindent on paste + */ + autoIndentOnPaste?: boolean; /** * Emulate selection behaviour of tab characters when using spaces for indentation. * This means selection will stick to tab stops. @@ -4925,150 +4929,151 @@ declare namespace monaco.editor { autoClosingOvertype = 11, autoClosingQuotes = 12, autoIndent = 13, - automaticLayout = 14, - autoSurround = 15, - bracketPairColorization = 16, - guides = 17, - codeLens = 18, - codeLensFontFamily = 19, - codeLensFontSize = 20, - colorDecorators = 21, - colorDecoratorsLimit = 22, - columnSelection = 23, - comments = 24, - contextmenu = 25, - copyWithSyntaxHighlighting = 26, - cursorBlinking = 27, - cursorSmoothCaretAnimation = 28, - cursorStyle = 29, - cursorSurroundingLines = 30, - cursorSurroundingLinesStyle = 31, - cursorWidth = 32, - disableLayerHinting = 33, - disableMonospaceOptimizations = 34, - domReadOnly = 35, - dragAndDrop = 36, - dropIntoEditor = 37, - experimentalEditContextEnabled = 38, - emptySelectionClipboard = 39, - experimentalGpuAcceleration = 40, - experimentalWhitespaceRendering = 41, - extraEditorClassName = 42, - fastScrollSensitivity = 43, - find = 44, - fixedOverflowWidgets = 45, - folding = 46, - foldingStrategy = 47, - foldingHighlight = 48, - foldingImportsByDefault = 49, - foldingMaximumRegions = 50, - unfoldOnClickAfterEndOfLine = 51, - fontFamily = 52, - fontInfo = 53, - fontLigatures = 54, - fontSize = 55, - fontWeight = 56, - fontVariations = 57, - formatOnPaste = 58, - formatOnType = 59, - glyphMargin = 60, - gotoLocation = 61, - hideCursorInOverviewRuler = 62, - hover = 63, - inDiffEditor = 64, - inlineSuggest = 65, - letterSpacing = 66, - lightbulb = 67, - lineDecorationsWidth = 68, - lineHeight = 69, - lineNumbers = 70, - lineNumbersMinChars = 71, - linkedEditing = 72, - links = 73, - matchBrackets = 74, - minimap = 75, - mouseStyle = 76, - mouseWheelScrollSensitivity = 77, - mouseWheelZoom = 78, - multiCursorMergeOverlapping = 79, - multiCursorModifier = 80, - multiCursorPaste = 81, - multiCursorLimit = 82, - occurrencesHighlight = 83, - occurrencesHighlightDelay = 84, - overtypeCursorStyle = 85, - overtypeOnPaste = 86, - overviewRulerBorder = 87, - overviewRulerLanes = 88, - padding = 89, - pasteAs = 90, - parameterHints = 91, - peekWidgetDefaultFocus = 92, - placeholder = 93, - definitionLinkOpensInPeek = 94, - quickSuggestions = 95, - quickSuggestionsDelay = 96, - readOnly = 97, - readOnlyMessage = 98, - renameOnType = 99, - renderControlCharacters = 100, - renderFinalNewline = 101, - renderLineHighlight = 102, - renderLineHighlightOnlyWhenFocus = 103, - renderValidationDecorations = 104, - renderWhitespace = 105, - revealHorizontalRightPadding = 106, - roundedSelection = 107, - rulers = 108, - scrollbar = 109, - scrollBeyondLastColumn = 110, - scrollBeyondLastLine = 111, - scrollPredominantAxis = 112, - selectionClipboard = 113, - selectionHighlight = 114, - selectOnLineNumbers = 115, - showFoldingControls = 116, - showUnused = 117, - snippetSuggestions = 118, - smartSelect = 119, - smoothScrolling = 120, - stickyScroll = 121, - stickyTabStops = 122, - stopRenderingLineAfter = 123, - suggest = 124, - suggestFontSize = 125, - suggestLineHeight = 126, - suggestOnTriggerCharacters = 127, - suggestSelection = 128, - tabCompletion = 129, - tabIndex = 130, - unicodeHighlighting = 131, - unusualLineTerminators = 132, - useShadowDOM = 133, - useTabStops = 134, - wordBreak = 135, - wordSegmenterLocales = 136, - wordSeparators = 137, - wordWrap = 138, - wordWrapBreakAfterCharacters = 139, - wordWrapBreakBeforeCharacters = 140, - wordWrapColumn = 141, - wordWrapOverride1 = 142, - wordWrapOverride2 = 143, - wrappingIndent = 144, - wrappingStrategy = 145, - showDeprecated = 146, - inlayHints = 147, - effectiveCursorStyle = 148, - editorClassName = 149, - pixelRatio = 150, - tabFocusMode = 151, - layoutInfo = 152, - wrappingInfo = 153, - defaultColorDecorators = 154, - colorDecoratorsActivatedOn = 155, - inlineCompletionsAccessibilityVerbose = 156, - effectiveExperimentalEditContextEnabled = 157 + autoIndentOnPaste = 14, + automaticLayout = 15, + autoSurround = 16, + bracketPairColorization = 17, + guides = 18, + codeLens = 19, + codeLensFontFamily = 20, + codeLensFontSize = 21, + colorDecorators = 22, + colorDecoratorsLimit = 23, + columnSelection = 24, + comments = 25, + contextmenu = 26, + copyWithSyntaxHighlighting = 27, + cursorBlinking = 28, + cursorSmoothCaretAnimation = 29, + cursorStyle = 30, + cursorSurroundingLines = 31, + cursorSurroundingLinesStyle = 32, + cursorWidth = 33, + disableLayerHinting = 34, + disableMonospaceOptimizations = 35, + domReadOnly = 36, + dragAndDrop = 37, + dropIntoEditor = 38, + experimentalEditContextEnabled = 39, + emptySelectionClipboard = 40, + experimentalGpuAcceleration = 41, + experimentalWhitespaceRendering = 42, + extraEditorClassName = 43, + fastScrollSensitivity = 44, + find = 45, + fixedOverflowWidgets = 46, + folding = 47, + foldingStrategy = 48, + foldingHighlight = 49, + foldingImportsByDefault = 50, + foldingMaximumRegions = 51, + unfoldOnClickAfterEndOfLine = 52, + fontFamily = 53, + fontInfo = 54, + fontLigatures = 55, + fontSize = 56, + fontWeight = 57, + fontVariations = 58, + formatOnPaste = 59, + formatOnType = 60, + glyphMargin = 61, + gotoLocation = 62, + hideCursorInOverviewRuler = 63, + hover = 64, + inDiffEditor = 65, + inlineSuggest = 66, + letterSpacing = 67, + lightbulb = 68, + lineDecorationsWidth = 69, + lineHeight = 70, + lineNumbers = 71, + lineNumbersMinChars = 72, + linkedEditing = 73, + links = 74, + matchBrackets = 75, + minimap = 76, + mouseStyle = 77, + mouseWheelScrollSensitivity = 78, + mouseWheelZoom = 79, + multiCursorMergeOverlapping = 80, + multiCursorModifier = 81, + multiCursorPaste = 82, + multiCursorLimit = 83, + occurrencesHighlight = 84, + occurrencesHighlightDelay = 85, + overtypeCursorStyle = 86, + overtypeOnPaste = 87, + overviewRulerBorder = 88, + overviewRulerLanes = 89, + padding = 90, + pasteAs = 91, + parameterHints = 92, + peekWidgetDefaultFocus = 93, + placeholder = 94, + definitionLinkOpensInPeek = 95, + quickSuggestions = 96, + quickSuggestionsDelay = 97, + readOnly = 98, + readOnlyMessage = 99, + renameOnType = 100, + renderControlCharacters = 101, + renderFinalNewline = 102, + renderLineHighlight = 103, + renderLineHighlightOnlyWhenFocus = 104, + renderValidationDecorations = 105, + renderWhitespace = 106, + revealHorizontalRightPadding = 107, + roundedSelection = 108, + rulers = 109, + scrollbar = 110, + scrollBeyondLastColumn = 111, + scrollBeyondLastLine = 112, + scrollPredominantAxis = 113, + selectionClipboard = 114, + selectionHighlight = 115, + selectOnLineNumbers = 116, + showFoldingControls = 117, + showUnused = 118, + snippetSuggestions = 119, + smartSelect = 120, + smoothScrolling = 121, + stickyScroll = 122, + stickyTabStops = 123, + stopRenderingLineAfter = 124, + suggest = 125, + suggestFontSize = 126, + suggestLineHeight = 127, + suggestOnTriggerCharacters = 128, + suggestSelection = 129, + tabCompletion = 130, + tabIndex = 131, + unicodeHighlighting = 132, + unusualLineTerminators = 133, + useShadowDOM = 134, + useTabStops = 135, + wordBreak = 136, + wordSegmenterLocales = 137, + wordSeparators = 138, + wordWrap = 139, + wordWrapBreakAfterCharacters = 140, + wordWrapBreakBeforeCharacters = 141, + wordWrapColumn = 142, + wordWrapOverride1 = 143, + wordWrapOverride2 = 144, + wrappingIndent = 145, + wrappingStrategy = 146, + showDeprecated = 147, + inlayHints = 148, + effectiveCursorStyle = 149, + editorClassName = 150, + pixelRatio = 151, + tabFocusMode = 152, + layoutInfo = 153, + wrappingInfo = 154, + defaultColorDecorators = 155, + colorDecoratorsActivatedOn = 156, + inlineCompletionsAccessibilityVerbose = 157, + effectiveExperimentalEditContextEnabled = 158 } export const EditorOptions: { @@ -5086,6 +5091,7 @@ declare namespace monaco.editor { autoClosingOvertype: IEditorOption; autoClosingQuotes: IEditorOption; autoIndent: IEditorOption; + autoIndentOnPaste: IEditorOption; automaticLayout: IEditorOption; autoSurround: IEditorOption; bracketPairColorization: IEditorOption>>; From d49ebe603c64724e1987458750b1a65af71c0308 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 11:59:12 +0200 Subject: [PATCH 064/236] reveal next file when keep/undoing last hunk (#250821) --- .../browser/chatEditing/chatEditingEditorActions.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorActions.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorActions.ts index 629cbc061f5..85d997a3c35 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorActions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorActions.ts @@ -251,12 +251,20 @@ abstract class AcceptRejectHunkAction extends ChatEditingEditorAction { ); } - override async runChatEditingCommand(_accessor: ServicesAccessor, _session: IChatEditingSession, _entry: IModifiedFileEntry, ctrl: IModifiedFileEntryEditorIntegration, ...args: any[]): Promise { + override async runChatEditingCommand(accessor: ServicesAccessor, session: IChatEditingSession, entry: IModifiedFileEntry, ctrl: IModifiedFileEntryEditorIntegration, ...args: any[]): Promise { + + const instaService = accessor.get(IInstantiationService); + if (this._accept) { await ctrl.acceptNearestChange(args[0]); } else { await ctrl.rejectNearestChange(args[0]); } + + if (entry.changesCount.get() === 0) { + // no more changes, move to next file + await instaService.invokeFunction(openNextOrPreviousChange, session, entry, true); + } } } From 1330a32f25ff4ad4383be975efbd7e17641a49f7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 6 Jun 2025 12:04:01 +0200 Subject: [PATCH 065/236] debt - use `esbuild` for CSS minification (#250820) --- build/gulpfile.reh.js | 6 +- build/gulpfile.vscode.js | 4 +- build/gulpfile.vscode.web.js | 2 +- build/lib/compilation.js | 4 - build/lib/compilation.ts | 5 - build/lib/mangle/index.js | 2 - build/lib/mangle/index.ts | 2 - build/lib/optimize.js | 17 +- build/lib/optimize.ts | 20 +- build/lib/postcss.js | 39 -- build/lib/postcss.ts | 36 -- build/package-lock.json | 982 ----------------------------------- build/package.json | 3 - 13 files changed, 20 insertions(+), 1102 deletions(-) delete mode 100644 build/lib/postcss.js delete mode 100644 build/lib/postcss.ts diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index c1d64c00338..c3db770d0a0 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -257,7 +257,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa const src = gulp.src(sourceFolderName + '/**', { base: '.' }) .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); })) .pipe(util.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + .pipe(filter(['**', '!**/*.{js,css}.map'])); const workspaceExtensionPoints = ['debuggers', 'jsonValidation']; const isUIExtension = (manifest) => { @@ -298,7 +298,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa const extensions = gulp.src(extensionPaths, { base: '.build', dot: true }); const extensionsCommonDependencies = gulp.src('.build/extensions/node_modules/**', { base: '.build', dot: true }); const sources = es.merge(src, extensions, extensionsCommonDependencies) - .pipe(filter(['**', '!**/*.js.map'], { dot: true })); + .pipe(filter(['**', '!**/*.{js,css}.map'], { dot: true })); let version = packageJson.version; const quality = product.quality; @@ -333,7 +333,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa const dependenciesSrc = productionDependencies.map(d => path.relative(REPO_ROOT, d)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`]).flat(); const deps = gulp.src(dependenciesSrc, { base: 'remote', dot: true }) // filter out unnecessary files, no source maps in server build - .pipe(filter(['**', '!**/package-lock.json', '!**/*.js.map'])) + .pipe(filter(['**', '!**/package-lock.json', '!**/*.{js,css}.map'])) .pipe(util.cleanNodeModules(path.join(__dirname, '.moduleignore'))) .pipe(util.cleanNodeModules(path.join(__dirname, `.moduleignore.${process.platform}`))) .pipe(jsFilter) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 2e5ef5277f8..610cbc389fc 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -244,7 +244,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const extensions = gulp.src(['.build/extensions/**', ...platformSpecificBuiltInExtensionsExclusions], { base: '.build', dot: true }); const sources = es.merge(src, extensions) - .pipe(filter(['**', '!**/*.js.map'], { dot: true })); + .pipe(filter(['**', '!**/*.{js,css}.map'], { dot: true })); let version = packageJson.version; const quality = product.quality; @@ -289,7 +289,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const dependenciesSrc = productionDependencies.map(d => path.relative(root, d)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]).flat().concat('!**/*.mk'); const deps = gulp.src(dependenciesSrc, { base: '.', dot: true }) - .pipe(filter(['**', `!**/${config.version}/**`, '!**/bin/darwin-arm64-87/**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.js.map'])) + .pipe(filter(['**', `!**/${config.version}/**`, '!**/bin/darwin-arm64-87/**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.{js,css}.map'])) .pipe(util.cleanNodeModules(path.join(__dirname, '.moduleignore'))) .pipe(util.cleanNodeModules(path.join(__dirname, `.moduleignore.${process.platform}`))) .pipe(jsFilter) diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index e1072c1e665..72423c765ea 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -152,7 +152,7 @@ function packageTask(sourceFolderName, destinationFolderName) { const loader = gulp.src('build/loader.min', { base: 'build', dot: true }).pipe(rename('out/vs/loader.js')); // TODO@esm remove line when we stop supporting web-amd-esm-bridge const sources = es.merge(src, extensions, loader) - .pipe(filter(['**', '!**/*.js.map'], { dot: true })) + .pipe(filter(['**', '!**/*.{js,css}.map'], { dot: true })) // TODO@esm remove me once we stop supporting our web-esm-bridge .pipe(es.through(function (file) { if (file.relative === 'out/vs/workbench/workbench.web.main.internal.css') { diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 55fb148097c..f4202f8677a 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -59,7 +59,6 @@ const os_1 = __importDefault(require("os")); const vinyl_1 = __importDefault(require("vinyl")); const task = __importStar(require("./task")); const index_1 = require("./mangle/index"); -const postcss_1 = require("./postcss"); const ts = require("typescript"); const watch = require('./watch'); // --- gulp-tsb: compile and transpile -------------------------------- @@ -96,14 +95,11 @@ function createCompile(src, { build, emitError, transpileOnly, preserveEnglish } const tsFilter = util.filter(data => /\.ts$/.test(data.path)); const isUtf8Test = (f) => /(\/|\\)test(\/|\\).*utf8/.test(f.path); const isRuntimeJs = (f) => f.path.endsWith('.js') && !f.path.includes('fixtures'); - const isCSS = (f) => f.path.endsWith('.css') && !f.path.includes('fixtures'); const noDeclarationsFilter = util.filter(data => !(/\.d\.ts$/.test(data.path))); - const postcssNesting = require('postcss-nesting'); const input = event_stream_1.default.through(); const output = input .pipe(util.$if(isUtf8Test, bom())) // this is required to preserve BOM in test files that loose it otherwise .pipe(util.$if(!build && isRuntimeJs, util.appendOwnPathSourceURL())) - .pipe(util.$if(isCSS, (0, postcss_1.gulpPostcss)([postcssNesting()], err => reporter(String(err))))) .pipe(tsFilter) .pipe(util.loadSourcemaps()) .pipe(compilation(token)) diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index 625fc430a94..88f5237d820 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -18,7 +18,6 @@ import File from 'vinyl'; import * as task from './task'; import { Mangler } from './mangle/index'; import { RawSourceMap } from 'source-map'; -import { gulpPostcss } from './postcss'; import ts = require('typescript'); const watch = require('./watch'); @@ -72,16 +71,12 @@ export function createCompile(src: string, { build, emitError, transpileOnly, pr const tsFilter = util.filter(data => /\.ts$/.test(data.path)); const isUtf8Test = (f: File) => /(\/|\\)test(\/|\\).*utf8/.test(f.path); const isRuntimeJs = (f: File) => f.path.endsWith('.js') && !f.path.includes('fixtures'); - const isCSS = (f: File) => f.path.endsWith('.css') && !f.path.includes('fixtures'); const noDeclarationsFilter = util.filter(data => !(/\.d\.ts$/.test(data.path))); - const postcssNesting = require('postcss-nesting'); - const input = es.through(); const output = input .pipe(util.$if(isUtf8Test, bom())) // this is required to preserve BOM in test files that loose it otherwise .pipe(util.$if(!build && isRuntimeJs, util.appendOwnPathSourceURL())) - .pipe(util.$if(isCSS, gulpPostcss([postcssNesting()], err => reporter(String(err))))) .pipe(tsFilter) .pipe(util.loadSourcemaps()) .pipe(compilation(token)) diff --git a/build/lib/mangle/index.js b/build/lib/mangle/index.js index ce744642551..fa729052f7c 100644 --- a/build/lib/mangle/index.js +++ b/build/lib/mangle/index.js @@ -251,8 +251,6 @@ function isNameTakenInFile(node, name) { return false; } const skippedExportMangledFiles = [ - // Build - 'css.build', // Monaco 'editorCommon', 'editorOptions', diff --git a/build/lib/mangle/index.ts b/build/lib/mangle/index.ts index 4cbbd3cdadd..2edc27ff55a 100644 --- a/build/lib/mangle/index.ts +++ b/build/lib/mangle/index.ts @@ -280,8 +280,6 @@ function isNameTakenInFile(node: ts.Node, name: string): boolean { } const skippedExportMangledFiles = [ - // Build - 'css.build', // Monaco 'editorCommon', diff --git a/build/lib/optimize.js b/build/lib/optimize.js index 105dc02a79d..2a87c239c94 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -50,7 +50,6 @@ const fs_1 = __importDefault(require("fs")); const pump_1 = __importDefault(require("pump")); const vinyl_1 = __importDefault(require("vinyl")); const bundle = __importStar(require("./bundle")); -const postcss_1 = require("./postcss"); const esbuild_1 = __importDefault(require("esbuild")); const gulp_sourcemaps_1 = __importDefault(require("gulp-sourcemaps")); const fancy_log_1 = __importDefault(require("fancy-log")); @@ -187,12 +186,10 @@ function bundleTask(opts) { function minifyTask(src, sourceMapBaseUrl) { const sourceMappingURL = sourceMapBaseUrl ? ((f) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined; return cb => { - const cssnano = require('cssnano'); const svgmin = require('gulp-svgmin'); - const jsFilter = (0, gulp_filter_1.default)('**/*.js', { restore: true }); - const cssFilter = (0, gulp_filter_1.default)('**/*.css', { restore: true }); + const esbuildFilter = (0, gulp_filter_1.default)('**/*.{js,css}', { restore: true }); const svgFilter = (0, gulp_filter_1.default)('**/*.svg', { restore: true }); - (0, pump_1.default)(gulp_1.default.src([src + '/**', '!' + src + '/**/*.map']), jsFilter, gulp_sourcemaps_1.default.init({ loadMaps: true }), event_stream_1.default.map((f, cb) => { + (0, pump_1.default)(gulp_1.default.src([src + '/**', '!' + src + '/**/*.map']), esbuildFilter, gulp_sourcemaps_1.default.init({ loadMaps: true }), event_stream_1.default.map((f, cb) => { esbuild_1.default.build({ entryPoints: [f.path], minify: true, @@ -201,11 +198,11 @@ function minifyTask(src, sourceMapBaseUrl) { packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages platform: 'neutral', // makes esm target: ['es2022'], - write: false + write: false, }).then(res => { - const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path)); - const sourceMapFile = res.outputFiles.find(f => /\.js\.map$/.test(f.path)); - const contents = Buffer.from(jsFile.contents); + const jsOrCSSFile = res.outputFiles.find(f => /\.(js|css)$/.test(f.path)); + const sourceMapFile = res.outputFiles.find(f => /\.(js|css)\.map$/.test(f.path)); + const contents = Buffer.from(jsOrCSSFile.contents); const unicodeMatch = contents.toString().match(/[^\x00-\xFF]+/g); if (unicodeMatch) { cb(new Error(`Found non-ascii character ${unicodeMatch[0]} in the minified output of ${f.path}. Non-ASCII characters in the output can cause performance problems when loading. Please review if you have introduced a regular expression that esbuild is not automatically converting and convert it to using unicode escape sequences.`)); @@ -216,7 +213,7 @@ function minifyTask(src, sourceMapBaseUrl) { cb(undefined, f); } }, cb); - }), jsFilter.restore, cssFilter, (0, postcss_1.gulpPostcss)([cssnano({ preset: 'default' })]), cssFilter.restore, svgFilter, svgmin(), svgFilter.restore, gulp_sourcemaps_1.default.write('./', { + }), esbuildFilter.restore, svgFilter, svgmin(), svgFilter.restore, gulp_sourcemaps_1.default.write('./', { sourceMappingURL, sourceRoot: undefined, includeContent: true, diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index 88a2a25dae4..d89d0d627f9 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -11,7 +11,6 @@ import fs from 'fs'; import pump from 'pump'; import VinylFile from 'vinyl'; import * as bundle from './bundle'; -import { gulpPostcss } from './postcss'; import esbuild from 'esbuild'; import sourcemaps from 'gulp-sourcemaps'; import fancyLog from 'fancy-log'; @@ -213,16 +212,14 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => const sourceMappingURL = sourceMapBaseUrl ? ((f: any) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined; return cb => { - const cssnano = require('cssnano') as typeof import('cssnano'); const svgmin = require('gulp-svgmin') as typeof import('gulp-svgmin'); - const jsFilter = filter('**/*.js', { restore: true }); - const cssFilter = filter('**/*.css', { restore: true }); + const esbuildFilter = filter('**/*.{js,css}', { restore: true }); const svgFilter = filter('**/*.svg', { restore: true }); pump( gulp.src([src + '/**', '!' + src + '/**/*.map']), - jsFilter, + esbuildFilter, sourcemaps.init({ loadMaps: true }), es.map((f: any, cb) => { esbuild.build({ @@ -233,12 +230,12 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages platform: 'neutral', // makes esm target: ['es2022'], - write: false + write: false, }).then(res => { - const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path))!; - const sourceMapFile = res.outputFiles.find(f => /\.js\.map$/.test(f.path))!; + const jsOrCSSFile = res.outputFiles.find(f => /\.(js|css)$/.test(f.path))!; + const sourceMapFile = res.outputFiles.find(f => /\.(js|css)\.map$/.test(f.path))!; - const contents = Buffer.from(jsFile.contents); + const contents = Buffer.from(jsOrCSSFile.contents); const unicodeMatch = contents.toString().match(/[^\x00-\xFF]+/g); if (unicodeMatch) { cb(new Error(`Found non-ascii character ${unicodeMatch[0]} in the minified output of ${f.path}. Non-ASCII characters in the output can cause performance problems when loading. Please review if you have introduced a regular expression that esbuild is not automatically converting and convert it to using unicode escape sequences.`)); @@ -250,10 +247,7 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => } }, cb); }), - jsFilter.restore, - cssFilter, - gulpPostcss([cssnano({ preset: 'default' })]), - cssFilter.restore, + esbuildFilter.restore, svgFilter, svgmin(), svgFilter.restore, diff --git a/build/lib/postcss.js b/build/lib/postcss.js deleted file mode 100644 index 210a184e5f5..00000000000 --- a/build/lib/postcss.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.gulpPostcss = gulpPostcss; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const postcss_1 = __importDefault(require("postcss")); -const event_stream_1 = __importDefault(require("event-stream")); -function gulpPostcss(plugins, handleError) { - const instance = (0, postcss_1.default)(plugins); - return event_stream_1.default.map((file, callback) => { - if (file.isNull()) { - return callback(null, file); - } - if (file.isStream()) { - return callback(new Error('Streaming not supported')); - } - instance - .process(file.contents.toString(), { from: file.path }) - .then((result) => { - file.contents = Buffer.from(result.css); - callback(null, file); - }) - .catch((error) => { - if (handleError) { - handleError(error); - callback(); - } - else { - callback(error); - } - }); - }); -} -//# sourceMappingURL=postcss.js.map \ No newline at end of file diff --git a/build/lib/postcss.ts b/build/lib/postcss.ts deleted file mode 100644 index 9ec2188d13a..00000000000 --- a/build/lib/postcss.ts +++ /dev/null @@ -1,36 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import postcss from 'postcss'; -import File from 'vinyl'; -import es from 'event-stream'; - -export function gulpPostcss(plugins: postcss.AcceptedPlugin[], handleError?: (err: Error) => void) { - const instance = postcss(plugins); - - return es.map((file: File, callback: (error?: any, file?: any) => void) => { - if (file.isNull()) { - return callback(null, file); - } - - if (file.isStream()) { - return callback(new Error('Streaming not supported')); - } - - instance - .process(file.contents.toString(), { from: file.path }) - .then((result) => { - file.contents = Buffer.from(result.css); - callback(null, file); - }) - .catch((error) => { - if (handleError) { - handleError(error); - callback(); - } else { - callback(error); - } - }); - }); -} diff --git a/build/package-lock.json b/build/package-lock.json index 212d9baef7a..d3d02a29d7d 100644 --- a/build/package-lock.json +++ b/build/package-lock.json @@ -45,7 +45,6 @@ "@vscode/ripgrep": "^1.15.10", "@vscode/vsce": "2.20.1", "byline": "^5.0.0", - "cssnano": "^7.0.7", "debug": "^4.3.2", "electron-osx-sign": "^0.4.16", "esbuild": "0.25.0", @@ -55,8 +54,6 @@ "jsonc-parser": "^2.3.0", "jws": "^4.0.0", "mime": "^1.4.1", - "postcss": "^8.5.3", - "postcss-nesting": "^13.0.1", "source-map": "0.6.1", "ternary-stream": "^3.0.0", "through2": "^4.0.2", @@ -444,52 +441,6 @@ "node": ">=18.0.0" } }, - "node_modules/@csstools/selector-resolve-nested": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz", - "integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" - } - }, - "node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" - } - }, "node_modules/@electron/asar": { "version": "3.2.10", "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.10.tgz", @@ -1008,16 +959,6 @@ "node": ">=10" } }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/@types/ansi-colors": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@types/ansi-colors/-/ansi-colors-3.2.0.tgz", @@ -1690,39 +1631,6 @@ "node": ">=8" } }, - "node_modules/browserslist": { - "version": "4.24.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", - "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001716", - "electron-to-chromium": "^1.5.149", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -1840,40 +1748,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001718", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", - "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2037,23 +1911,6 @@ "color-support": "bin.js" } }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, "node_modules/compare-version": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", @@ -2090,19 +1947,6 @@ "node": ">= 8" } }, - "node_modules/css-declaration-sorter": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", - "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, "node_modules/css-select": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -2119,20 +1963,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -2145,134 +1975,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.0.7.tgz", - "integrity": "sha512-evKu7yiDIF7oS+EIpwFlMF730ijRyLFaM2o5cTxRGJR9OKHKkc+qP443ZEVR9kZG0syaAJJCPJyfv5pbrxlSng==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssnano-preset-default": "^7.0.7", - "lilconfig": "^3.1.3" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/cssnano-preset-default": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.7.tgz", - "integrity": "sha512-jW6CG/7PNB6MufOrlovs1TvBTEVmhY45yz+bd0h6nw3h6d+1e+/TX+0fflZ+LzvZombbT5f+KC063w9VoHeHow==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "css-declaration-sorter": "^7.2.0", - "cssnano-utils": "^5.0.1", - "postcss-calc": "^10.1.1", - "postcss-colormin": "^7.0.3", - "postcss-convert-values": "^7.0.5", - "postcss-discard-comments": "^7.0.4", - "postcss-discard-duplicates": "^7.0.2", - "postcss-discard-empty": "^7.0.1", - "postcss-discard-overridden": "^7.0.1", - "postcss-merge-longhand": "^7.0.5", - "postcss-merge-rules": "^7.0.5", - "postcss-minify-font-values": "^7.0.1", - "postcss-minify-gradients": "^7.0.1", - "postcss-minify-params": "^7.0.3", - "postcss-minify-selectors": "^7.0.5", - "postcss-normalize-charset": "^7.0.1", - "postcss-normalize-display-values": "^7.0.1", - "postcss-normalize-positions": "^7.0.1", - "postcss-normalize-repeat-style": "^7.0.1", - "postcss-normalize-string": "^7.0.1", - "postcss-normalize-timing-functions": "^7.0.1", - "postcss-normalize-unicode": "^7.0.3", - "postcss-normalize-url": "^7.0.1", - "postcss-normalize-whitespace": "^7.0.1", - "postcss-ordered-values": "^7.0.2", - "postcss-reduce-initial": "^7.0.3", - "postcss-reduce-transforms": "^7.0.1", - "postcss-svgo": "^7.0.2", - "postcss-unique-selectors": "^7.0.4" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/cssnano-utils": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz", - "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true, - "license": "CC0-1.0" - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2515,13 +2217,6 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/electron-to-chromium": { - "version": "1.5.158", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.158.tgz", - "integrity": "sha512-9vcp2xHhkvraY6AHw2WMi+GDSLPX42qe2xjYaVoZqFRJiOcilVQFq9mZmpuHEQpzlgGDelKlV7ZiGcmMsc8WxQ==", - "dev": true, - "license": "ISC" - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -2621,16 +2316,6 @@ "@esbuild/win32-x64": "0.25.0" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3515,19 +3200,6 @@ "node": ">=6" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, "node_modules/linkify-it": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", @@ -3543,26 +3215,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.mergewith": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", "dev": true }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -3635,13 +3293,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true, - "license": "CC0-1.0" - }, "node_modules/mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", @@ -3712,25 +3363,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -3792,13 +3424,6 @@ "node-gyp-build-test": "build-test.js" } }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, - "license": "MIT" - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3989,13 +3614,6 @@ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA= sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, "node_modules/picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", @@ -4046,522 +3664,6 @@ "node": ">= 0.10" } }, - "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-calc": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", - "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12 || ^20.9 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.38" - } - }, - "node_modules/postcss-colormin": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.3.tgz", - "integrity": "sha512-xZxQcSyIVZbSsl1vjoqZAcMYYdnJsIyG8OvqShuuqf12S88qQboxxEy0ohNCOLwVPXTU+hFHvJPACRL2B5ohTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "caniuse-api": "^3.0.0", - "colord": "^2.9.3", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-convert-values": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.5.tgz", - "integrity": "sha512-0VFhH8nElpIs3uXKnVtotDJJNX0OGYSZmdt4XfSfvOMrFw1jKfpwpZxfC4iN73CTM/MWakDEmsHQXkISYj4BXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-discard-comments": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.4.tgz", - "integrity": "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^7.1.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", - "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-discard-empty": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", - "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz", - "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz", - "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^7.0.5" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-merge-rules": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.5.tgz", - "integrity": "sha512-ZonhuSwEaWA3+xYbOdJoEReKIBs5eDiBVLAGpYZpNFPzXZcEE5VKR7/qBEQvTZpiwjqhhqEQ+ax5O3VShBj9Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^5.0.1", - "postcss-selector-parser": "^7.1.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz", - "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz", - "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "colord": "^2.9.3", - "cssnano-utils": "^5.0.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-minify-params": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.3.tgz", - "integrity": "sha512-vUKV2+f5mtjewYieanLX0xemxIp1t0W0H/D11u+kQV/MWdygOO7xPMkbK+r9P6Lhms8MgzKARF/g5OPXhb8tgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "cssnano-utils": "^5.0.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz", - "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "postcss-selector-parser": "^7.1.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-nesting": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz", - "integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/selector-resolve-nested": "^3.0.0", - "@csstools/selector-specificity": "^5.0.0", - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz", - "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz", - "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz", - "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz", - "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-string": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz", - "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz", - "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.3.tgz", - "integrity": "sha512-EcoA29LvG3F+EpOh03iqu+tJY3uYYKzArqKJHxDhUYLa2u58aqGq16K6/AOsXD9yqLN8O6y9mmePKN5cx6krOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-url": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz", - "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", - "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-ordered-values": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz", - "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssnano-utils": "^5.0.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.3.tgz", - "integrity": "sha512-RFvkZaqiWtGMlVjlUHpaxGqEL27lgt+Q2Ixjf83CRAzqdo+TsDyGPtJUbPx2MuYIJ+sCQc2TrOvRnhcXQfgIVA==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz", - "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.0.2.tgz", - "integrity": "sha512-5Dzy66JlnRM6pkdOTF8+cGsB1fnERTE8Nc+Eed++fOWo1hdsBptCsbG8UuJkgtZt75bRtMJIrPeZmtfANixdFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.3.2" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >= 18" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz", - "integrity": "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^7.1.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, "node_modules/prebuild-install": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", @@ -4924,16 +4026,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", @@ -5026,23 +4118,6 @@ "dev": true, "license": "MIT" }, - "node_modules/stylehacks": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.5.tgz", - "integrity": "sha512-5kNb7V37BNf0Q3w+1pxfa+oiNPS++/b4Jil9e/kPDgrk1zjEd6uR7SZeJiYaLYH6RRSC1XX2/37OTeU/4FvuIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.5", - "postcss-selector-parser": "^7.1.0" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.32" - } - }, "node_modules/sumchecker": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", @@ -5067,32 +4142,6 @@ "node": ">=4" } }, - "node_modules/svgo": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", - "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.3.1", - "css-what": "^6.1.0", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, "node_modules/tar-fs": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", @@ -5360,37 +4409,6 @@ "node": ">= 4.0.0" } }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, "node_modules/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", diff --git a/build/package.json b/build/package.json index 64c0d7530f5..c19196d45c7 100644 --- a/build/package.json +++ b/build/package.json @@ -39,7 +39,6 @@ "@vscode/ripgrep": "^1.15.10", "@vscode/vsce": "2.20.1", "byline": "^5.0.0", - "cssnano": "^7.0.7", "debug": "^4.3.2", "electron-osx-sign": "^0.4.16", "esbuild": "0.25.0", @@ -49,8 +48,6 @@ "jsonc-parser": "^2.3.0", "jws": "^4.0.0", "mime": "^1.4.1", - "postcss": "^8.5.3", - "postcss-nesting": "^13.0.1", "source-map": "0.6.1", "ternary-stream": "^3.0.0", "through2": "^4.0.2", From de44553a7a17a5515b8522583b073011b8f8125a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 12:26:48 +0200 Subject: [PATCH 066/236] avoid const-export-function-expression (#250826) https://github.com/microsoft/vscode/issues/248387 --- src/vs/base/common/glob.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 1057364d7fc..276f076788d 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -311,9 +311,7 @@ const NULL = function (): string | null { * * See {@link FALSE} and {@link NULL}. */ -export const isEmptyPattern = ( - pattern: ParsedPattern | ParsedExpression, -): pattern is (typeof FALSE | typeof NULL) => { +export function isEmptyPattern(pattern: ParsedPattern | ParsedExpression): pattern is (typeof FALSE | typeof NULL) { if (pattern === FALSE) { return true; } @@ -323,7 +321,7 @@ export const isEmptyPattern = ( } return false; -}; +} function parsePattern(arg1: string | IRelativePattern, options: IGlobOptions): ParsedStringPattern { if (!arg1) { From 9ab31573573ac9ae7506d5b4e852a156c1e02926 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 12:27:05 +0200 Subject: [PATCH 067/236] chore - cleanup decoratior util (#250827) --- src/vs/base/common/decorators/logTime.ts | 171 ----------- src/vs/base/test/common/logTime.test.ts | 274 ------------------ .../contrib/chat/browser/chatInputPart.ts | 8 +- .../promptSyntax/service/promptsService.ts | 11 - 4 files changed, 2 insertions(+), 462 deletions(-) delete mode 100644 src/vs/base/common/decorators/logTime.ts delete mode 100644 src/vs/base/test/common/logTime.test.ts diff --git a/src/vs/base/common/decorators/logTime.ts b/src/vs/base/common/decorators/logTime.ts deleted file mode 100644 index 1ce87e4cdaf..00000000000 --- a/src/vs/base/common/decorators/logTime.ts +++ /dev/null @@ -1,171 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { assertDefined } from '../types.js'; - -/** - * Type for a function that logs a message. - */ -export type TLogFunction = (message: string, ...args: any[]) => void; - -/** - * Type for an object that contains a `logger` property - * with the logging methods. - */ -type TObjectWithLogFunction = T & { logTime: TLogFunction }; - -/** - * Decorator allows to log execution time of any method of a class. - * The class must have the `logTime` method that provides logs - * a provided message. - * - * The decorated method can be asynchronous or synchronous, but - * the timing message is logged only if it finishes *successfully*. - * - * ## Examples - * - * ```typescript - * class MyClass { - * public readonly logTime: TLogFunction; - - * constructor( - * // because we have the interface restrictions on the class - * // which does not support 'private'/'protected' fields, we are - * // forced to use the 'public' modifier here - * \@ILogService public readonly logService: ILogService, - * ) { - * this.logTime = logService.info.bind(logService); - * } - * - * @logTime() - * public async myMethod(): Promise { - * // some artificial delay - * await new Promise((resolve) => setTimeout(resolve, 10)); - * - * return 'haalou!'; - * } - * } - * - * const myObject = instantiationService.createInstance(MyClass); - * - * // once the method completes successfully, the information - * // message '[MyClass.myMethod] took 10.00 ms' is logged - * const result = await myObject.myMethod(); - * - * assert.strictEqual( - * result, - * 'haalou!', - * 'Must yield original return value', - * ); - * ``` - */ -export function logTime() { - return function logExecutionTimeDecorator< - TObject extends TObjectWithLogFunction, - >( - _proto: TObject, - methodName: string, - descriptor: TypedPropertyDescriptor<(...args: any[]) => any | Promise>, - ) { - const originalMethod = descriptor.value; - - assertDefined( - originalMethod, - `Method '${methodName}' is not defined.`, - ); - - // override the decorated method with the one that logs - // a timing message after the original method finishes execution - descriptor.value = function ( - this: TObject, - ...args: Parameters - ): ReturnType { - return logExecutionTime( - `${this.constructor.name}.${methodName}`, - originalMethod.bind(this, ...args), - this.logTime.bind(this), - ); - }; - - return descriptor; - }; -} - -/** - * Helper allows to log execution time of code block or function. - * - * The code block or function can be asynchronous or synchronous, but - * the timing message is logged only if it finishes *successfully*. - * - * ## Examples - * - * ```typescript - * const result = logExecutionTime( - * 'my asynchronous block', - * async () => { - * // some artificial delay - * await new Promise((resolve) => setTimeout(resolve, 10)); - * - * return 'haalou!'; - * }, - * this.logService.info, - * } - * - * // once the callback completes successfully, the information - * // message '[MyClass.myMethod] took 10.00 ms' is logged - * assert.strictEqual( - * result, - * 'haalou!', - * 'Must yield original return value', - * ); - * ``` - */ -export const logExecutionTime = ( - blockName: string, - callback: () => T | Promise, - logger: TLogFunction, -): ReturnType => { - const startTime = performance.now(); - const result = callback(); - const syncTimeMs = performance.now() - startTime; - - // handle asynchronous decorated methods - if (result instanceof Promise) { - return result.then((resolved) => { - const asyncTimeMs = performance.now() - startTime; - - log( - blockName, - asyncTimeMs, - logger, - ); - return resolved; - }); - } - - // handle synchronous decorated methods - log( - blockName, - syncTimeMs, - logger, - ); - - return result; -}; - -/** - * Internal helper to log the timing message with - * provided details and logger. - */ -const log = ( - methodName: string, - timeMs: number, - logger: TLogFunction, -): void => { - return logger( - // allow-any-unicode-next-line - `[⏱][${methodName}] took ${timeMs.toFixed(2)} ms`, - ); -}; diff --git a/src/vs/base/test/common/logTime.test.ts b/src/vs/base/test/common/logTime.test.ts deleted file mode 100644 index 9ad514d6f6b..00000000000 --- a/src/vs/base/test/common/logTime.test.ts +++ /dev/null @@ -1,274 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import assert from 'assert'; -import * as sinon from 'sinon'; -import { timeout } from '../../common/async.js'; -import { randomInt } from '../../common/numbers.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js'; -import { logExecutionTime, logTime } from '../../common/decorators/logTime.js'; - -suite('logTime', () => { - ensureNoDisposablesAreLeakedInTestSuite(); - - /** - * Helper that replaces the timing part of a message to - * a predictable constant value so the message can be - * consistently compared in the tests - */ - const cleanupTimingMessage = ( - message: string, - ): string => { - // sanity check on the message type since this function - // can be called with `any` inside these tests - assert( - typeof message === 'string', - `Message must be a string, got '${message}'.`, - ); - - // regex: targets the ' 123.75 ms' part at the end - // of the provided 'message' string - return message - .replaceAll(/\s\d+.\d{2}\sms$/gi, ' 100.50 ms'); - }; - - suite('decorator', () => { - test('async method', async () => { - const logSpy = sinon.spy(); - class TestClass { - public logTime = logSpy; - - constructor( - private readonly returnValue: number - ) { } - - @logTime() - public async myAsyncMethod(): Promise { - await timeout(10); - - return this.returnValue; - } - } - - const expectedReturnValue = randomInt(1000); - const testObject = new TestClass(expectedReturnValue); - - const resultPromise = testObject.myAsyncMethod(); - - assert( - resultPromise instanceof Promise, - 'My method must return a promise.', - ); - - const result = await resultPromise; - assert.strictEqual( - result, - expectedReturnValue, - 'Decorator must return correct value.', - ); - - assert( - logSpy.calledOnce, - 'The trace logger method must be called.', - ); - - const callArgs = logSpy.getCalls()[0].args; - - assert( - callArgs.length === 1, - 'Logger method must be called with correct number of arguments.', - ); - - assert.strictEqual( - cleanupTimingMessage(callArgs[0]), - '[⏱][TestClass.myAsyncMethod] took 100.50 ms', - 'Logger method must be called with correct message.', - ); - }); - }); - - test('sync method', async () => { - const logSpy = sinon.spy(); - - class TestClass { - public logTime = logSpy; - - constructor( - private readonly returnValue: number - ) { } - - @logTime() - public mySyncMethod(): number { - return this.returnValue; - } - } - - const expectedReturnValue = randomInt(1000); - const testObject = new TestClass(expectedReturnValue); - - const result = testObject.mySyncMethod(); - assert.strictEqual( - result, - expectedReturnValue, - 'Decorator must return correct value.', - ); - - assert( - logSpy.calledOnce, - 'The trace logger method must be called.', - ); - - const callArgs = logSpy.getCalls()[0].args; - - assert( - callArgs.length === 1, - 'Logger method must be called with correct number of arguments.', - ); - - assert.strictEqual( - cleanupTimingMessage(callArgs[0]), - '[⏱][TestClass.mySyncMethod] took 100.50 ms', - 'Logger method must be called with correct message.', - ); - }); - - test('uses \'trace\' level by default', async () => { - const logSpy = sinon.spy(); - - class TestClass { - public logTime = logSpy; - - constructor( - private readonly returnValue: number - ) { } - - @logTime() - public async myAsyncMethod(): Promise { - await timeout(10); - - return this.returnValue; - } - } - - const expectedReturnValue = randomInt(1000); - const testObject = new TestClass(expectedReturnValue); - - const resultPromise = testObject.myAsyncMethod(); - - assert( - resultPromise instanceof Promise, - 'My method must return a promise.', - ); - - const result = await resultPromise; - assert.strictEqual( - result, - expectedReturnValue, - 'Decorator must return correct value.', - ); - - assert( - logSpy.calledOnce, - 'The trace logger method must be called.', - ); - - const callArgs = logSpy.getCalls()[0].args; - - assert( - callArgs.length === 1, - 'Logger method must be called with correct number of arguments.', - ); - - assert.strictEqual( - cleanupTimingMessage(callArgs[0]), - '[⏱][TestClass.myAsyncMethod] took 100.50 ms', - 'Logger method must be called with correct message.', - ); - }); - - suite('logExecutionTime helper', () => { - test('async function', async () => { - const logSpy = sinon.spy(); - - const expectedReturnValue = randomInt(1000); - const resultPromise = logExecutionTime( - 'my-async-function', - async () => { - await timeout(10); - - return expectedReturnValue; - }, - logSpy, - ); - - assert( - resultPromise instanceof Promise, - 'Callback function must return a promise.', - ); - - const result = await resultPromise; - assert.strictEqual( - result, - expectedReturnValue, - 'Helper must return correct value.', - ); - - assert( - logSpy.calledOnce, - 'The trace logger method must be called.', - ); - - const callArgs = logSpy.getCalls()[0].args; - - assert( - callArgs.length === 1, - 'Logger method must be called with correct number of arguments.', - ); - - assert.strictEqual( - cleanupTimingMessage(callArgs[0]), - '[⏱][my-async-function] took 100.50 ms', - 'Logger message must start with the correct value.', - ); - }); - - test('sync function', () => { - const logSpy = sinon.spy(); - - const expectedReturnValue = randomInt(1000); - const result = logExecutionTime( - 'my-sync-function', - () => { - return expectedReturnValue; - }, - logSpy, - ); - - assert.strictEqual( - result, - expectedReturnValue, - 'Helper must return correct value.', - ); - - assert( - logSpy.calledOnce, - 'The trace logger method must be called.', - ); - - const callArgs = logSpy.getCalls()[0].args; - - assert( - callArgs.length === 1, - 'Logger method must be called with correct number of arguments.', - ); - - assert.strictEqual( - cleanupTimingMessage(callArgs[0]), - '[⏱][my-sync-function] took 100.50 ms', - 'Logger message must start with the correct value.', - ); - }); - }); -}); diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index d6903664e1e..9caa28e5b2a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -17,7 +17,6 @@ import { IAction } from '../../../../base/common/actions.js'; import { DeferredPromise } from '../../../../base/common/async.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Codicon } from '../../../../base/common/codicons.js'; -import { logExecutionTime } from '../../../../base/common/decorators/logTime.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { HistoryNavigator2 } from '../../../../base/common/history.js'; import { KeyCode } from '../../../../base/common/keyCodes.js'; @@ -193,11 +192,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge // prompt files may have nested child references to other prompt // files that are resolved asynchronously, hence we need to wait // for the entire prompt instruction tree to be processed - await logExecutionTime('instructions tree resolve', - this.promptInstructionsAttachmentsPart - .allSettled.bind(this.promptInstructionsAttachmentsPart), - this.logService.trace.bind(this.logService), - ); + this.promptInstructionsAttachmentsPart + .allSettled.bind(this.promptInstructionsAttachmentsPart); contextArr .push(...this.promptInstructionsAttachmentsPart.chatAttachments); diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 6ceecda1415..9f55575c80a 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -23,7 +23,6 @@ import { TextModelPromptParser } from '../parsers/textModelPromptParser.js'; import { ILabelService } from '../../../../../../platform/label/common/label.js'; import { IModelService } from '../../../../../../editor/common/services/model.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; -import { logTime, TLogFunction } from '../../../../../../base/common/decorators/logTime.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { IUserDataProfileService } from '../../../../../services/userDataProfile/common/userDataProfile.js'; import type { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptPath, IPromptsService, TPromptsStorage } from './types.js'; @@ -45,11 +44,6 @@ export class PromptsService extends Disposable implements IPromptsService { */ private readonly fileLocator: PromptFilesLocator; - /** - * Function used by the `@logTime` decorator to log - * execution time of some of the decorated methods. - */ - public logTime: TLogFunction; /** * Lazily created event that is fired when the custom chat modes change. @@ -67,8 +61,6 @@ export class PromptsService extends Disposable implements IPromptsService { this.fileLocator = this._register(this.instantiationService.createInstance(PromptFilesLocator)); - this.logTime = this.logger.trace.bind(this.logger); - // the factory function below creates a new prompt parser object // for the provided model, if no active non-disposed parser exists this.cache = this._register( @@ -200,7 +192,6 @@ export class PromptsService extends Disposable implements IPromptsService { }); } - @logTime() public async getCustomChatModes(): Promise { const modeFiles = (await this.listPromptFiles(PromptsType.mode, CancellationToken.None)) .map(modeFile => modeFile.uri); @@ -241,7 +232,6 @@ export class PromptsService extends Disposable implements IPromptsService { return metadataList; } - @logTime() public async findInstructionFilesFor( files: readonly URI[], ): Promise { @@ -307,7 +297,6 @@ export class PromptsService extends Disposable implements IPromptsService { return metaDatas[0]; } - @logTime() public async getAllMetadata( promptUris: readonly URI[], ): Promise { From c7ae22259ee32d2bc66e8daa2accdd1b718c4435 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 13:00:19 +0200 Subject: [PATCH 068/236] no more `asyncTransaction` usage in chat land (#250831) fixes https://github.com/microsoft/vscode/issues/248827 --- .../chatEditingModifiedDocumentEntry.ts | 13 +-- .../chatEditingModifiedFileEntry.ts | 36 ++++---- .../chatEditingModifiedNotebookEntry.ts | 12 +-- .../browser/chatEditing/chatEditingSession.ts | 92 ++++++++----------- .../contrib/chat/common/chatEditingService.ts | 6 +- .../test/browser/chatEditingService.test.ts | 2 +- 6 files changed, 75 insertions(+), 86 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts index 1c7566e986a..39bfb47d8c2 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts @@ -491,11 +491,11 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie return undefined; } - protected override async _doAccept(tx: ITransaction | undefined): Promise { + protected override async _doAccept(): Promise { this.originalModel.setValue(this.modifiedModel.createSnapshot()); - this._diffInfo.set(nullDocumentDiff, tx); + this._diffInfo.set(nullDocumentDiff, undefined); this._edit = StringEdit.empty; - await this._collapse(tx); + this._multiDiffEntryDelegate.collapse(undefined); const config = this._fileConfigService.getAutoSaveConfiguration(this.modifiedURI); if (!config.autoSave || !this._textFileService.isDirty(this.modifiedURI)) { @@ -513,7 +513,7 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie } } - protected override async _doReject(tx: ITransaction | undefined): Promise { + protected override async _doReject(): Promise { if (this.createdInRequestId === this._telemetryInfo.requestId) { if (isTextFileEditorModel(this._docFileEditorModel)) { await this._docFileEditorModel.revert({ soft: true }); @@ -527,7 +527,7 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie // and so that an intermediate saved state gets reverted await this._docFileEditorModel.save({ reason: SaveReason.EXPLICIT, skipSaveParticipants: true }); } - await this._collapse(tx); + this._multiDiffEntryDelegate.collapse(undefined); } } @@ -543,9 +543,6 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie } } - private async _collapse(transaction: ITransaction | undefined): Promise { - this._multiDiffEntryDelegate.collapse(transaction); - } protected _createEditorIntegration(editor: IEditorPane): IModifiedFileEntryEditorIntegration { const codeEditor = getCodeEditor(editor.getControl()); diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts index a6754bc2ce9..08328ef44d4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts @@ -8,7 +8,7 @@ import { Emitter } from '../../../../../base/common/event.js'; import { Disposable, DisposableMap, MutableDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../../base/common/network.js'; import { clamp } from '../../../../../base/common/numbers.js'; -import { autorun, derived, IObservable, ITransaction, observableValue, observableValueOpts } from '../../../../../base/common/observable.js'; +import { autorun, derived, IObservable, ITransaction, observableValue, observableValueOpts, transaction } from '../../../../../base/common/observable.js'; import { URI } from '../../../../../base/common/uri.js'; import { StringEdit } from '../../../../../editor/common/core/edits/stringEdit.js'; import { TextEdit } from '../../../../../editor/common/languages.js'; @@ -161,7 +161,7 @@ export abstract class AbstractChatEditingModifiedFileEntry extends Disposable im const remain = Math.round(future - Date.now()); if (remain <= 0) { - this.accept(undefined); + this.accept(); } else { const handle = setTimeout(update, 100); this._autoAcceptCtrl.set(new AutoAcceptControl(acceptTimeout, remain, () => { @@ -206,34 +206,38 @@ export abstract class AbstractChatEditingModifiedFileEntry extends Disposable im this._telemetryInfo = telemetryInfo; } - async accept(tx: ITransaction | undefined): Promise { + async accept(): Promise { if (this._stateObs.get() !== ModifiedFileEntryState.Modified) { // already accepted or rejected return; } - await this._doAccept(tx); - this._stateObs.set(ModifiedFileEntryState.Accepted, tx); - this._autoAcceptCtrl.set(undefined, tx); + await this._doAccept(); + transaction(tx => { + this._stateObs.set(ModifiedFileEntryState.Accepted, tx); + this._autoAcceptCtrl.set(undefined, tx); + }); this._notifyAction('accepted'); } - protected abstract _doAccept(tx: ITransaction | undefined): Promise; + protected abstract _doAccept(): Promise; - async reject(tx: ITransaction | undefined): Promise { + async reject(): Promise { if (this._stateObs.get() !== ModifiedFileEntryState.Modified) { // already accepted or rejected return; } this._notifyAction('rejected'); - await this._doReject(tx); - this._stateObs.set(ModifiedFileEntryState.Rejected, tx); - this._autoAcceptCtrl.set(undefined, tx); + await this._doReject(); + transaction(tx => { + this._stateObs.set(ModifiedFileEntryState.Rejected, tx); + this._autoAcceptCtrl.set(undefined, tx); + }); } - protected abstract _doReject(tx: ITransaction | undefined): Promise; + protected abstract _doReject(): Promise; protected _notifyAction(outcome: 'accepted' | 'rejected' | 'userModified') { this._chatService.notifyUserAction({ @@ -283,18 +287,18 @@ export abstract class AbstractChatEditingModifiedFileEntry extends Disposable im abstract acceptAgentEdits(uri: URI, edits: (TextEdit | ICellEditOperation)[], isLastEdits: boolean, responseModel: IChatResponseModel): Promise; - async acceptStreamingEditsEnd(tx: ITransaction) { - this._resetEditsState(tx); + async acceptStreamingEditsEnd() { + this._resetEditsState(undefined); if (await this._areOriginalAndModifiedIdentical()) { // ACCEPT if identical - await this.accept(tx); + await this.accept(); } } protected abstract _areOriginalAndModifiedIdentical(): Promise; - protected _resetEditsState(tx: ITransaction): void { + protected _resetEditsState(tx: ITransaction | undefined): void { this._isCurrentlyBeingModifiedByObs.set(undefined, tx); this._rewriteRatioObs.set(0, tx); this._waitsForLastEdits.set(false, tx); diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts index 9967b9030b8..cc23b401827 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts @@ -412,12 +412,12 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie } } - protected override async _doAccept(tx: ITransaction | undefined): Promise { - this.updateCellDiffInfo([], tx); + protected override async _doAccept(): Promise { + this.updateCellDiffInfo([], undefined); const snapshot = createSnapshot(this.modifiedModel, this.transientOptions, this.configurationService); restoreSnapshot(this.originalModel, snapshot); this.initializeModelsFromDiff(); - await this._collapse(tx); + await this._collapse(undefined); const config = this._fileConfigService.getAutoSaveConfiguration(this.modifiedURI); if (this.modifiedModel.uri.scheme !== Schemas.untitled && (!config.autoSave || !this.notebookResolver.isDirty(this.modifiedURI))) { @@ -436,8 +436,8 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie } } - protected override async _doReject(tx: ITransaction | undefined): Promise { - this.updateCellDiffInfo([], tx); + protected override async _doReject(): Promise { + this.updateCellDiffInfo([], undefined); if (this.createdInRequestId === this._telemetryInfo.requestId) { await this._applyEdits(async () => { await this.modifiedResourceRef.object.revert({ soft: true }); @@ -455,7 +455,7 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie } }); this.initializeModelsFromDiff(); - await this._collapse(tx); + await this._collapse(undefined); } } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts index 9f89be21ccd..b78e1f354de 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts @@ -12,7 +12,7 @@ import { Emitter } from '../../../../../base/common/event.js'; import { Iterable } from '../../../../../base/common/iterator.js'; import { Disposable, DisposableStore, dispose } from '../../../../../base/common/lifecycle.js'; import { ResourceMap } from '../../../../../base/common/map.js'; -import { asyncTransaction, autorun, derived, derivedOpts, IObservable, IReader, ITransaction, ObservablePromise, observableValue, transaction } from '../../../../../base/common/observable.js'; +import { autorun, derived, derivedOpts, IObservable, IReader, ITransaction, ObservablePromise, observableValue, transaction } from '../../../../../base/common/observable.js'; import { isEqual } from '../../../../../base/common/resources.js'; import { URI } from '../../../../../base/common/uri.js'; import { IBulkEditService } from '../../../../../editor/browser/services/bulkEditService.js'; @@ -224,9 +224,9 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio for (const [uri, content] of restoredSessionState.initialFileContents) { this._initialFileContents.set(uri, content); } - await asyncTransaction(async tx => { - this._pendingSnapshot = restoredSessionState.pendingSnapshot; - await this._restoreSnapshot(restoredSessionState.recentSnapshot, tx, false); + this._pendingSnapshot = restoredSessionState.pendingSnapshot; + await this._restoreSnapshot(restoredSessionState.recentSnapshot, false); + transaction(async tx => { this._linearHistory.set(restoredSessionState.linearHistory, tx); this._linearHistoryIndex.set(restoredSessionState.linearHistoryIndex, tx); this._state.set(ChatEditingSessionState.Idle, tx); @@ -491,10 +491,8 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio const stopRef = this._findEditStop(requestId, stopId); if (stopRef) { this._ensurePendingSnapshot(); - await asyncTransaction(async tx => { - this._linearHistoryIndex.set(stopRef.historyIndex, tx); - await this._restoreSnapshot(stopRef.stop, tx); - }); + this._linearHistoryIndex.set(stopRef.historyIndex, undefined); + await this._restoreSnapshot(stopRef.stop); this._updateRequestHiddenState(); } } else { @@ -507,7 +505,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio } } - private async _restoreSnapshot({ entries }: IChatEditingSessionStop, tx: ITransaction | undefined, restoreResolvedToDisk = true): Promise { + private async _restoreSnapshot({ entries }: IChatEditingSessionStop, restoreResolvedToDisk = true): Promise { // Reset all the files which are modified in this session state // but which are not found in the snapshot @@ -528,7 +526,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio entriesArr.push(entry); } - this._entriesObs.set(entriesArr, tx); + this._entriesObs.set(entriesArr, undefined); } remove(...uris: URI[]): void { @@ -562,37 +560,32 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio async accept(...uris: URI[]): Promise { this._assertNotDisposed(); - await asyncTransaction(async tx => { + if (uris.length === 0) { + await Promise.all(this._entriesObs.get().map(entry => entry.accept())); + } - if (uris.length === 0) { - await Promise.all(this._entriesObs.get().map(entry => entry.accept(tx))); + for (const uri of uris) { + const entry = this._entriesObs.get().find(e => isEqual(e.modifiedURI, uri)); + if (entry) { + await entry.accept(); } - - for (const uri of uris) { - const entry = this._entriesObs.get().find(e => isEqual(e.modifiedURI, uri)); - if (entry) { - await entry.accept(tx); - } - } - }); + } this._accessibilitySignalService.playSignal(AccessibilitySignal.editsKept, { allowManyInParallel: true }); } async reject(...uris: URI[]): Promise { this._assertNotDisposed(); - await asyncTransaction(async tx => { - if (uris.length === 0) { - await Promise.all(this._entriesObs.get().map(entry => entry.reject(tx))); - } + if (uris.length === 0) { + await Promise.all(this._entriesObs.get().map(entry => entry.reject())); + } - for (const uri of uris) { - const entry = this._entriesObs.get().find(e => isEqual(e.modifiedURI, uri)); - if (entry) { - await entry.reject(tx); - } + for (const uri of uris) { + const entry = this._entriesObs.get().find(e => isEqual(e.modifiedURI, uri)); + if (entry) { + await entry.reject(); } - }); + } this._accessibilitySignalService.playSignal(AccessibilitySignal.editsUndone, { allowManyInParallel: true }); } @@ -738,10 +731,8 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio } this._ensurePendingSnapshot(); - await asyncTransaction(async tx => { - await this._restoreSnapshot(previousSnapshot.stop, tx); - this._linearHistoryIndex.set(newIndex, tx); - }); + await this._restoreSnapshot(previousSnapshot.stop); + this._linearHistoryIndex.set(newIndex, undefined); this._updateRequestHiddenState(); } @@ -756,10 +747,8 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio if (!nextSnapshot) { return; } - await asyncTransaction(async tx => { - await this._restoreSnapshot(nextSnapshot, tx); - this._linearHistoryIndex.set(newIndex, tx); - }); + await this._restoreSnapshot(nextSnapshot); + this._linearHistoryIndex.set(newIndex, undefined); this._updateRequestHiddenState(); } @@ -809,7 +798,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio * * @param next If true, this will edit the snapshot _after_ the undo stop */ - private ensureEditInUndoStopMatches(requestId: string, undoStop: string | undefined, entry: AbstractChatEditingModifiedFileEntry, next: boolean, tx: ITransaction) { + private ensureEditInUndoStopMatches(requestId: string, undoStop: string | undefined, entry: AbstractChatEditingModifiedFileEntry, next: boolean, tx: ITransaction | undefined) { const history = this._linearHistory.get(); const snapIndex = history.findIndex(s => s.requestId === requestId); if (snapIndex === -1) { @@ -871,20 +860,19 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio } private async _resolve(requestId: string, undoStop: string | undefined, resource: URI): Promise { - await asyncTransaction(async (tx) => { - const hasOtherTasks = Iterable.some(this._streamingEditLocks.keys(), k => k !== resource.toString()); - if (!hasOtherTasks) { - this._state.set(ChatEditingSessionState.Idle, tx); - } - const entry = this._getEntry(resource); - if (!entry) { - return; - } + const hasOtherTasks = Iterable.some(this._streamingEditLocks.keys(), k => k !== resource.toString()); + if (!hasOtherTasks) { + this._state.set(ChatEditingSessionState.Idle, undefined); + } - this.ensureEditInUndoStopMatches(requestId, undoStop, entry, /* next= */ true, tx); - return entry.acceptStreamingEditsEnd(tx); - }); + const entry = this._getEntry(resource); + if (!entry) { + return; + } + + this.ensureEditInUndoStopMatches(requestId, undoStop, entry, /* next= */ true, undefined); + return entry.acceptStreamingEditsEnd(); } diff --git a/src/vs/workbench/contrib/chat/common/chatEditingService.ts b/src/vs/workbench/contrib/chat/common/chatEditingService.ts index aaf9bf48ac7..4bf57eee5b5 100644 --- a/src/vs/workbench/contrib/chat/common/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/common/chatEditingService.ts @@ -6,7 +6,7 @@ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Event } from '../../../../base/common/event.js'; import { IDisposable } from '../../../../base/common/lifecycle.js'; -import { IObservable, IReader, ITransaction } from '../../../../base/common/observable.js'; +import { IObservable, IReader } from '../../../../base/common/observable.js'; import { URI } from '../../../../base/common/uri.js'; import { TextEdit } from '../../../../editor/common/languages.js'; import { localize } from '../../../../nls.js'; @@ -217,8 +217,8 @@ export interface IModifiedFileEntry { readonly waitsForLastEdits: IObservable; - accept(transaction: ITransaction | undefined): Promise; - reject(transaction: ITransaction | undefined): Promise; + accept(): Promise; + reject(): Promise; reviewMode: IObservable; autoAcceptController: IObservable<{ total: number; remaining: number; cancel(): void } | undefined>; diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts index 0d5400e2fa0..cc3c6fcaef4 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts @@ -166,7 +166,7 @@ suite('ChatEditingService', function () { await unset; - await entry.reject(undefined); + await entry.reject(); model.dispose(); }); From 4097467973389122ec310ebc914a6f0f42cebcf1 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 6 Jun 2025 12:56:23 +0200 Subject: [PATCH 069/236] Fixes #242059 --- .../inlineChat/browser/inlineChatCurrentLine.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts index d78f4aef478..6342f587a42 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts @@ -38,7 +38,6 @@ import { PLAINTEXT_LANGUAGE_ID } from '../../../../editor/common/languages/modes import { createStyleSheet2 } from '../../../../base/browser/domStylesheets.js'; import { stringValue } from '../../../../base/browser/cssValue.js'; import { observableConfigValue } from '../../../../platform/observable/common/platformObservableUtils.js'; -import { Emitter } from '../../../../base/common/event.js'; import { ChatAgentLocation } from '../../chat/common/constants.js'; import { INSTRUCTIONS_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../../chat/common/promptSyntax/constants.js'; import { MODE_FILE_EXTENSION } from '../../../../platform/prompts/common/prompts.js'; @@ -242,7 +241,7 @@ export class InlineChatHintsController extends Disposable implements IEditorCont const ghostState = ghostCtrl?.model.read(r)?.state.read(r); const textFocus = editorObs.isTextFocused.read(r); - let position = editorObs.cursorPosition.read(r); + const position = editorObs.cursorPosition.read(r); const model = editorObs.model.read(r); const kb = keyObs.read(r); @@ -255,14 +254,7 @@ export class InlineChatHintsController extends Disposable implements IEditorCont return undefined; } - // DEBT - I cannot use `model.onDidChangeContent` directly here - // https://github.com/microsoft/vscode/issues/242059 - const emitter = r.store.add(new Emitter()); - r.store.add(model.onDidChangeContent(() => emitter.fire())); - observableFromEvent(emitter.event, () => model.getVersionId()).read(r); - - // position can be wrong - position = model.validatePosition(position); + editorObs.versionId.read(r); const visible = this._visibilityObs.read(r); const isEol = model.getLineMaxColumn(position.lineNumber) === position.column; From 5457a12c4a409184e712d65f294cae1de71d602f Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 6 Jun 2025 13:55:50 +0200 Subject: [PATCH 070/236] Add setting autoIndentOnPasteWithinString (#250465) * add setting autoindent on paste * setting value to false * autoindentonpastewithinstring --- src/vs/editor/common/config/editorOptions.ts | 9 + .../common/standalone/standaloneEnums.ts | 291 ++++++++--------- .../indentation/browser/indentation.ts | 2 +- src/vs/monaco.d.ts | 294 +++++++++--------- 4 files changed, 306 insertions(+), 290 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index d619e9f26fa..1c2b54f46f9 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -511,6 +511,10 @@ export interface IEditorOptions { * Boolean which controls whether to autoindent on paste */ autoIndentOnPaste?: boolean; + /** + * Boolean which controls whether to autoindent on paste within a string when autoIndentOnPaste is enabled. + */ + autoIndentOnPasteWithinString?: boolean; /** * Emulate selection behaviour of tab characters when using spaces for indentation. * This means selection will stick to tab stops. @@ -5508,6 +5512,7 @@ export const enum EditorOption { autoClosingQuotes, autoIndent, autoIndentOnPaste, + autoIndentOnPasteWithinString, automaticLayout, autoSurround, bracketPairColorization, @@ -5783,6 +5788,10 @@ export const EditorOptions = { EditorOption.autoIndentOnPaste, 'autoIndentOnPaste', false, { description: nls.localize('autoIndentOnPaste', "Controls whether the editor should automatically auto-indent the pasted content.") } )), + autoIndentOnPasteWithinString: register(new EditorBooleanOption( + EditorOption.autoIndentOnPasteWithinString, 'autoIndentOnPasteWithinString', true, + { description: nls.localize('autoIndentOnPasteWithinString', "Controls whether the editor should automatically auto-indent the pasted content when pasted within a string. This takes effect when autoIndentOnPaste is true.") } + )), automaticLayout: register(new EditorBooleanOption( EditorOption.automaticLayout, 'automaticLayout', false, )), diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 0e6925acf49..b0aa004c999 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -189,150 +189,151 @@ export enum EditorOption { autoClosingQuotes = 12, autoIndent = 13, autoIndentOnPaste = 14, - automaticLayout = 15, - autoSurround = 16, - bracketPairColorization = 17, - guides = 18, - codeLens = 19, - codeLensFontFamily = 20, - codeLensFontSize = 21, - colorDecorators = 22, - colorDecoratorsLimit = 23, - columnSelection = 24, - comments = 25, - contextmenu = 26, - copyWithSyntaxHighlighting = 27, - cursorBlinking = 28, - cursorSmoothCaretAnimation = 29, - cursorStyle = 30, - cursorSurroundingLines = 31, - cursorSurroundingLinesStyle = 32, - cursorWidth = 33, - disableLayerHinting = 34, - disableMonospaceOptimizations = 35, - domReadOnly = 36, - dragAndDrop = 37, - dropIntoEditor = 38, - experimentalEditContextEnabled = 39, - emptySelectionClipboard = 40, - experimentalGpuAcceleration = 41, - experimentalWhitespaceRendering = 42, - extraEditorClassName = 43, - fastScrollSensitivity = 44, - find = 45, - fixedOverflowWidgets = 46, - folding = 47, - foldingStrategy = 48, - foldingHighlight = 49, - foldingImportsByDefault = 50, - foldingMaximumRegions = 51, - unfoldOnClickAfterEndOfLine = 52, - fontFamily = 53, - fontInfo = 54, - fontLigatures = 55, - fontSize = 56, - fontWeight = 57, - fontVariations = 58, - formatOnPaste = 59, - formatOnType = 60, - glyphMargin = 61, - gotoLocation = 62, - hideCursorInOverviewRuler = 63, - hover = 64, - inDiffEditor = 65, - inlineSuggest = 66, - letterSpacing = 67, - lightbulb = 68, - lineDecorationsWidth = 69, - lineHeight = 70, - lineNumbers = 71, - lineNumbersMinChars = 72, - linkedEditing = 73, - links = 74, - matchBrackets = 75, - minimap = 76, - mouseStyle = 77, - mouseWheelScrollSensitivity = 78, - mouseWheelZoom = 79, - multiCursorMergeOverlapping = 80, - multiCursorModifier = 81, - multiCursorPaste = 82, - multiCursorLimit = 83, - occurrencesHighlight = 84, - occurrencesHighlightDelay = 85, - overtypeCursorStyle = 86, - overtypeOnPaste = 87, - overviewRulerBorder = 88, - overviewRulerLanes = 89, - padding = 90, - pasteAs = 91, - parameterHints = 92, - peekWidgetDefaultFocus = 93, - placeholder = 94, - definitionLinkOpensInPeek = 95, - quickSuggestions = 96, - quickSuggestionsDelay = 97, - readOnly = 98, - readOnlyMessage = 99, - renameOnType = 100, - renderControlCharacters = 101, - renderFinalNewline = 102, - renderLineHighlight = 103, - renderLineHighlightOnlyWhenFocus = 104, - renderValidationDecorations = 105, - renderWhitespace = 106, - revealHorizontalRightPadding = 107, - roundedSelection = 108, - rulers = 109, - scrollbar = 110, - scrollBeyondLastColumn = 111, - scrollBeyondLastLine = 112, - scrollPredominantAxis = 113, - selectionClipboard = 114, - selectionHighlight = 115, - selectOnLineNumbers = 116, - showFoldingControls = 117, - showUnused = 118, - snippetSuggestions = 119, - smartSelect = 120, - smoothScrolling = 121, - stickyScroll = 122, - stickyTabStops = 123, - stopRenderingLineAfter = 124, - suggest = 125, - suggestFontSize = 126, - suggestLineHeight = 127, - suggestOnTriggerCharacters = 128, - suggestSelection = 129, - tabCompletion = 130, - tabIndex = 131, - unicodeHighlighting = 132, - unusualLineTerminators = 133, - useShadowDOM = 134, - useTabStops = 135, - wordBreak = 136, - wordSegmenterLocales = 137, - wordSeparators = 138, - wordWrap = 139, - wordWrapBreakAfterCharacters = 140, - wordWrapBreakBeforeCharacters = 141, - wordWrapColumn = 142, - wordWrapOverride1 = 143, - wordWrapOverride2 = 144, - wrappingIndent = 145, - wrappingStrategy = 146, - showDeprecated = 147, - inlayHints = 148, - effectiveCursorStyle = 149, - editorClassName = 150, - pixelRatio = 151, - tabFocusMode = 152, - layoutInfo = 153, - wrappingInfo = 154, - defaultColorDecorators = 155, - colorDecoratorsActivatedOn = 156, - inlineCompletionsAccessibilityVerbose = 157, - effectiveExperimentalEditContextEnabled = 158 + autoIndentOnPasteWithinString = 15, + automaticLayout = 16, + autoSurround = 17, + bracketPairColorization = 18, + guides = 19, + codeLens = 20, + codeLensFontFamily = 21, + codeLensFontSize = 22, + colorDecorators = 23, + colorDecoratorsLimit = 24, + columnSelection = 25, + comments = 26, + contextmenu = 27, + copyWithSyntaxHighlighting = 28, + cursorBlinking = 29, + cursorSmoothCaretAnimation = 30, + cursorStyle = 31, + cursorSurroundingLines = 32, + cursorSurroundingLinesStyle = 33, + cursorWidth = 34, + disableLayerHinting = 35, + disableMonospaceOptimizations = 36, + domReadOnly = 37, + dragAndDrop = 38, + dropIntoEditor = 39, + experimentalEditContextEnabled = 40, + emptySelectionClipboard = 41, + experimentalGpuAcceleration = 42, + experimentalWhitespaceRendering = 43, + extraEditorClassName = 44, + fastScrollSensitivity = 45, + find = 46, + fixedOverflowWidgets = 47, + folding = 48, + foldingStrategy = 49, + foldingHighlight = 50, + foldingImportsByDefault = 51, + foldingMaximumRegions = 52, + unfoldOnClickAfterEndOfLine = 53, + fontFamily = 54, + fontInfo = 55, + fontLigatures = 56, + fontSize = 57, + fontWeight = 58, + fontVariations = 59, + formatOnPaste = 60, + formatOnType = 61, + glyphMargin = 62, + gotoLocation = 63, + hideCursorInOverviewRuler = 64, + hover = 65, + inDiffEditor = 66, + inlineSuggest = 67, + letterSpacing = 68, + lightbulb = 69, + lineDecorationsWidth = 70, + lineHeight = 71, + lineNumbers = 72, + lineNumbersMinChars = 73, + linkedEditing = 74, + links = 75, + matchBrackets = 76, + minimap = 77, + mouseStyle = 78, + mouseWheelScrollSensitivity = 79, + mouseWheelZoom = 80, + multiCursorMergeOverlapping = 81, + multiCursorModifier = 82, + multiCursorPaste = 83, + multiCursorLimit = 84, + occurrencesHighlight = 85, + occurrencesHighlightDelay = 86, + overtypeCursorStyle = 87, + overtypeOnPaste = 88, + overviewRulerBorder = 89, + overviewRulerLanes = 90, + padding = 91, + pasteAs = 92, + parameterHints = 93, + peekWidgetDefaultFocus = 94, + placeholder = 95, + definitionLinkOpensInPeek = 96, + quickSuggestions = 97, + quickSuggestionsDelay = 98, + readOnly = 99, + readOnlyMessage = 100, + renameOnType = 101, + renderControlCharacters = 102, + renderFinalNewline = 103, + renderLineHighlight = 104, + renderLineHighlightOnlyWhenFocus = 105, + renderValidationDecorations = 106, + renderWhitespace = 107, + revealHorizontalRightPadding = 108, + roundedSelection = 109, + rulers = 110, + scrollbar = 111, + scrollBeyondLastColumn = 112, + scrollBeyondLastLine = 113, + scrollPredominantAxis = 114, + selectionClipboard = 115, + selectionHighlight = 116, + selectOnLineNumbers = 117, + showFoldingControls = 118, + showUnused = 119, + snippetSuggestions = 120, + smartSelect = 121, + smoothScrolling = 122, + stickyScroll = 123, + stickyTabStops = 124, + stopRenderingLineAfter = 125, + suggest = 126, + suggestFontSize = 127, + suggestLineHeight = 128, + suggestOnTriggerCharacters = 129, + suggestSelection = 130, + tabCompletion = 131, + tabIndex = 132, + unicodeHighlighting = 133, + unusualLineTerminators = 134, + useShadowDOM = 135, + useTabStops = 136, + wordBreak = 137, + wordSegmenterLocales = 138, + wordSeparators = 139, + wordWrap = 140, + wordWrapBreakAfterCharacters = 141, + wordWrapBreakBeforeCharacters = 142, + wordWrapColumn = 143, + wordWrapOverride1 = 144, + wordWrapOverride2 = 145, + wrappingIndent = 146, + wrappingStrategy = 147, + showDeprecated = 148, + inlayHints = 149, + effectiveCursorStyle = 150, + editorClassName = 151, + pixelRatio = 152, + tabFocusMode = 153, + layoutInfo = 154, + wrappingInfo = 155, + defaultColorDecorators = 156, + colorDecoratorsActivatedOn = 157, + inlineCompletionsAccessibilityVerbose = 158, + effectiveExperimentalEditContextEnabled = 159 } /** @@ -991,4 +992,4 @@ export enum WrappingIndent { * DeepIndent => wrapped lines get +2 indentation toward the parent. */ DeepIndent = 3 -} \ No newline at end of file +} diff --git a/src/vs/editor/contrib/indentation/browser/indentation.ts b/src/vs/editor/contrib/indentation/browser/indentation.ts index 46e4374208f..d01770a81cd 100644 --- a/src/vs/editor/contrib/indentation/browser/indentation.ts +++ b/src/vs/editor/contrib/indentation/browser/indentation.ts @@ -414,7 +414,7 @@ export class AutoIndentOnPaste implements IEditorContribution { if (containsOnlyWhitespace) { return; } - if (isStartOrEndInString(model, range)) { + if (!this.editor.getOption(EditorOption.autoIndentOnPasteWithinString) && isStartOrEndInString(model, range)) { return; } if (!model.tokenization.isCheapToTokenize(range.getStartPosition().lineNumber)) { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index b0008b0ff59..ed45b5fbbea 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3572,6 +3572,10 @@ declare namespace monaco.editor { * Boolean which controls whether to autoindent on paste */ autoIndentOnPaste?: boolean; + /** + * Boolean which controls whether to autoindent on paste within a string when autoIndentOnPaste is enabled. + */ + autoIndentOnPasteWithinString?: boolean; /** * Emulate selection behaviour of tab characters when using spaces for indentation. * This means selection will stick to tab stops. @@ -4930,150 +4934,151 @@ declare namespace monaco.editor { autoClosingQuotes = 12, autoIndent = 13, autoIndentOnPaste = 14, - automaticLayout = 15, - autoSurround = 16, - bracketPairColorization = 17, - guides = 18, - codeLens = 19, - codeLensFontFamily = 20, - codeLensFontSize = 21, - colorDecorators = 22, - colorDecoratorsLimit = 23, - columnSelection = 24, - comments = 25, - contextmenu = 26, - copyWithSyntaxHighlighting = 27, - cursorBlinking = 28, - cursorSmoothCaretAnimation = 29, - cursorStyle = 30, - cursorSurroundingLines = 31, - cursorSurroundingLinesStyle = 32, - cursorWidth = 33, - disableLayerHinting = 34, - disableMonospaceOptimizations = 35, - domReadOnly = 36, - dragAndDrop = 37, - dropIntoEditor = 38, - experimentalEditContextEnabled = 39, - emptySelectionClipboard = 40, - experimentalGpuAcceleration = 41, - experimentalWhitespaceRendering = 42, - extraEditorClassName = 43, - fastScrollSensitivity = 44, - find = 45, - fixedOverflowWidgets = 46, - folding = 47, - foldingStrategy = 48, - foldingHighlight = 49, - foldingImportsByDefault = 50, - foldingMaximumRegions = 51, - unfoldOnClickAfterEndOfLine = 52, - fontFamily = 53, - fontInfo = 54, - fontLigatures = 55, - fontSize = 56, - fontWeight = 57, - fontVariations = 58, - formatOnPaste = 59, - formatOnType = 60, - glyphMargin = 61, - gotoLocation = 62, - hideCursorInOverviewRuler = 63, - hover = 64, - inDiffEditor = 65, - inlineSuggest = 66, - letterSpacing = 67, - lightbulb = 68, - lineDecorationsWidth = 69, - lineHeight = 70, - lineNumbers = 71, - lineNumbersMinChars = 72, - linkedEditing = 73, - links = 74, - matchBrackets = 75, - minimap = 76, - mouseStyle = 77, - mouseWheelScrollSensitivity = 78, - mouseWheelZoom = 79, - multiCursorMergeOverlapping = 80, - multiCursorModifier = 81, - multiCursorPaste = 82, - multiCursorLimit = 83, - occurrencesHighlight = 84, - occurrencesHighlightDelay = 85, - overtypeCursorStyle = 86, - overtypeOnPaste = 87, - overviewRulerBorder = 88, - overviewRulerLanes = 89, - padding = 90, - pasteAs = 91, - parameterHints = 92, - peekWidgetDefaultFocus = 93, - placeholder = 94, - definitionLinkOpensInPeek = 95, - quickSuggestions = 96, - quickSuggestionsDelay = 97, - readOnly = 98, - readOnlyMessage = 99, - renameOnType = 100, - renderControlCharacters = 101, - renderFinalNewline = 102, - renderLineHighlight = 103, - renderLineHighlightOnlyWhenFocus = 104, - renderValidationDecorations = 105, - renderWhitespace = 106, - revealHorizontalRightPadding = 107, - roundedSelection = 108, - rulers = 109, - scrollbar = 110, - scrollBeyondLastColumn = 111, - scrollBeyondLastLine = 112, - scrollPredominantAxis = 113, - selectionClipboard = 114, - selectionHighlight = 115, - selectOnLineNumbers = 116, - showFoldingControls = 117, - showUnused = 118, - snippetSuggestions = 119, - smartSelect = 120, - smoothScrolling = 121, - stickyScroll = 122, - stickyTabStops = 123, - stopRenderingLineAfter = 124, - suggest = 125, - suggestFontSize = 126, - suggestLineHeight = 127, - suggestOnTriggerCharacters = 128, - suggestSelection = 129, - tabCompletion = 130, - tabIndex = 131, - unicodeHighlighting = 132, - unusualLineTerminators = 133, - useShadowDOM = 134, - useTabStops = 135, - wordBreak = 136, - wordSegmenterLocales = 137, - wordSeparators = 138, - wordWrap = 139, - wordWrapBreakAfterCharacters = 140, - wordWrapBreakBeforeCharacters = 141, - wordWrapColumn = 142, - wordWrapOverride1 = 143, - wordWrapOverride2 = 144, - wrappingIndent = 145, - wrappingStrategy = 146, - showDeprecated = 147, - inlayHints = 148, - effectiveCursorStyle = 149, - editorClassName = 150, - pixelRatio = 151, - tabFocusMode = 152, - layoutInfo = 153, - wrappingInfo = 154, - defaultColorDecorators = 155, - colorDecoratorsActivatedOn = 156, - inlineCompletionsAccessibilityVerbose = 157, - effectiveExperimentalEditContextEnabled = 158 + autoIndentOnPasteWithinString = 15, + automaticLayout = 16, + autoSurround = 17, + bracketPairColorization = 18, + guides = 19, + codeLens = 20, + codeLensFontFamily = 21, + codeLensFontSize = 22, + colorDecorators = 23, + colorDecoratorsLimit = 24, + columnSelection = 25, + comments = 26, + contextmenu = 27, + copyWithSyntaxHighlighting = 28, + cursorBlinking = 29, + cursorSmoothCaretAnimation = 30, + cursorStyle = 31, + cursorSurroundingLines = 32, + cursorSurroundingLinesStyle = 33, + cursorWidth = 34, + disableLayerHinting = 35, + disableMonospaceOptimizations = 36, + domReadOnly = 37, + dragAndDrop = 38, + dropIntoEditor = 39, + experimentalEditContextEnabled = 40, + emptySelectionClipboard = 41, + experimentalGpuAcceleration = 42, + experimentalWhitespaceRendering = 43, + extraEditorClassName = 44, + fastScrollSensitivity = 45, + find = 46, + fixedOverflowWidgets = 47, + folding = 48, + foldingStrategy = 49, + foldingHighlight = 50, + foldingImportsByDefault = 51, + foldingMaximumRegions = 52, + unfoldOnClickAfterEndOfLine = 53, + fontFamily = 54, + fontInfo = 55, + fontLigatures = 56, + fontSize = 57, + fontWeight = 58, + fontVariations = 59, + formatOnPaste = 60, + formatOnType = 61, + glyphMargin = 62, + gotoLocation = 63, + hideCursorInOverviewRuler = 64, + hover = 65, + inDiffEditor = 66, + inlineSuggest = 67, + letterSpacing = 68, + lightbulb = 69, + lineDecorationsWidth = 70, + lineHeight = 71, + lineNumbers = 72, + lineNumbersMinChars = 73, + linkedEditing = 74, + links = 75, + matchBrackets = 76, + minimap = 77, + mouseStyle = 78, + mouseWheelScrollSensitivity = 79, + mouseWheelZoom = 80, + multiCursorMergeOverlapping = 81, + multiCursorModifier = 82, + multiCursorPaste = 83, + multiCursorLimit = 84, + occurrencesHighlight = 85, + occurrencesHighlightDelay = 86, + overtypeCursorStyle = 87, + overtypeOnPaste = 88, + overviewRulerBorder = 89, + overviewRulerLanes = 90, + padding = 91, + pasteAs = 92, + parameterHints = 93, + peekWidgetDefaultFocus = 94, + placeholder = 95, + definitionLinkOpensInPeek = 96, + quickSuggestions = 97, + quickSuggestionsDelay = 98, + readOnly = 99, + readOnlyMessage = 100, + renameOnType = 101, + renderControlCharacters = 102, + renderFinalNewline = 103, + renderLineHighlight = 104, + renderLineHighlightOnlyWhenFocus = 105, + renderValidationDecorations = 106, + renderWhitespace = 107, + revealHorizontalRightPadding = 108, + roundedSelection = 109, + rulers = 110, + scrollbar = 111, + scrollBeyondLastColumn = 112, + scrollBeyondLastLine = 113, + scrollPredominantAxis = 114, + selectionClipboard = 115, + selectionHighlight = 116, + selectOnLineNumbers = 117, + showFoldingControls = 118, + showUnused = 119, + snippetSuggestions = 120, + smartSelect = 121, + smoothScrolling = 122, + stickyScroll = 123, + stickyTabStops = 124, + stopRenderingLineAfter = 125, + suggest = 126, + suggestFontSize = 127, + suggestLineHeight = 128, + suggestOnTriggerCharacters = 129, + suggestSelection = 130, + tabCompletion = 131, + tabIndex = 132, + unicodeHighlighting = 133, + unusualLineTerminators = 134, + useShadowDOM = 135, + useTabStops = 136, + wordBreak = 137, + wordSegmenterLocales = 138, + wordSeparators = 139, + wordWrap = 140, + wordWrapBreakAfterCharacters = 141, + wordWrapBreakBeforeCharacters = 142, + wordWrapColumn = 143, + wordWrapOverride1 = 144, + wordWrapOverride2 = 145, + wrappingIndent = 146, + wrappingStrategy = 147, + showDeprecated = 148, + inlayHints = 149, + effectiveCursorStyle = 150, + editorClassName = 151, + pixelRatio = 152, + tabFocusMode = 153, + layoutInfo = 154, + wrappingInfo = 155, + defaultColorDecorators = 156, + colorDecoratorsActivatedOn = 157, + inlineCompletionsAccessibilityVerbose = 158, + effectiveExperimentalEditContextEnabled = 159 } export const EditorOptions: { @@ -5092,6 +5097,7 @@ declare namespace monaco.editor { autoClosingQuotes: IEditorOption; autoIndent: IEditorOption; autoIndentOnPaste: IEditorOption; + autoIndentOnPasteWithinString: IEditorOption; automaticLayout: IEditorOption; autoSurround: IEditorOption; bracketPairColorization: IEditorOption>>; From 796eeff9c2de0e9d1f1605ba1d915a542bc3dbac Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 6 Jun 2025 13:58:41 +0200 Subject: [PATCH 071/236] move prompt file actions under vs/workbench/contrib/chat/browser/promptSyntax (#250836) * Move promptfile actions/pickers under workbench/contrib/chat/browser/promptSyntax * fix * renames --- .../chat/browser/actions/chatContext.ts | 2 +- .../browser/actions/chatContextActions.ts | 2 +- .../utils/attachInstructions.ts | 91 -------------- .../askToSelectPrompt/utils/detachPrompt.ts | 34 ------ .../askToSelectPrompt/utils/runPrompt.ts | 54 --------- .../contrib/chat/browser/chat.contribution.ts | 3 +- .../attachInstructionsAction.ts} | 85 ++++++-------- .../chatModeActions.ts | 26 ++-- .../createPromptCommand/errors.ts | 38 ------ .../utils/createPromptFile.ts | 76 ------------ ...omptCommand.ts => newPromptFileActions.ts} | 79 +++++++------ .../dialogs => pickers}/askForPromptName.ts | 16 +-- .../askForPromptSourceFolder.ts | 23 ++-- .../pickers}/promptFilePickers.ts | 46 ++++---- .../promptFileActions.ts} | 13 +- .../runPromptAction.ts} | 111 +++++++++--------- .../saveToPromptAction.ts} | 33 +++--- 17 files changed, 215 insertions(+), 517 deletions(-) delete mode 100644 src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/attachInstructions.ts delete mode 100644 src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/detachPrompt.ts delete mode 100644 src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/runPrompt.ts rename src/vs/workbench/contrib/chat/browser/{actions/promptActions/chatAttachInstructionsAction.ts => promptSyntax/attachInstructionsAction.ts} (71%) rename src/vs/workbench/contrib/chat/browser/{actions/promptActions => promptSyntax}/chatModeActions.ts (66%) delete mode 100644 src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/errors.ts delete mode 100644 src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/utils/createPromptFile.ts rename src/vs/workbench/contrib/chat/browser/promptSyntax/{contributions/createPromptCommand/createPromptCommand.ts => newPromptFileActions.ts} (65%) rename src/vs/workbench/contrib/chat/browser/promptSyntax/{contributions/createPromptCommand/dialogs => pickers}/askForPromptName.ts (83%) rename src/vs/workbench/contrib/chat/browser/promptSyntax/{contributions/createPromptCommand/dialogs => pickers}/askForPromptSourceFolder.ts (88%) rename src/vs/workbench/contrib/chat/browser/{actions/promptActions/dialogs/askToSelectPrompt => promptSyntax/pickers}/promptFilePickers.ts (87%) rename src/vs/workbench/contrib/chat/browser/{actions/promptActions/index.ts => promptSyntax/promptFileActions.ts} (62%) rename src/vs/workbench/contrib/chat/browser/{actions/promptActions/chatRunPromptAction.ts => promptSyntax/runPromptAction.ts} (71%) rename src/vs/workbench/contrib/chat/browser/{actions/promptActions/chatSaveToPromptAction.ts => promptSyntax/saveToPromptAction.ts} (84%) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts index 0f42bb1d7b3..24391e9596d 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts @@ -28,7 +28,7 @@ import { IToolData, ToolDataSource, ToolSet } from '../../common/languageModelTo import { IChatWidget } from '../chat.js'; import { imageToHash, isImage } from '../chatPasteProviders.js'; import { convertBufferToScreenshotVariable } from '../contrib/screenshot.js'; -import { ChatInstructionsPickerPick } from './promptActions/chatAttachInstructionsAction.js'; +import { ChatInstructionsPickerPick } from '../promptSyntax/attachInstructionsAction.js'; export class ChatContextContributions extends Disposable implements IWorkbenchContribution { diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index 1f1efb69a07..ec16a17ef53 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -43,8 +43,8 @@ import { IChatWidget, IChatWidgetService, IQuickChatService, showChatView } from import { IChatContextPickerItem, IChatContextPickService, IChatContextValueItem, isChatContextPickerPickItem } from '../chatContextPickService.js'; import { isQuickChat } from '../chatWidget.js'; import { resizeImage } from '../imageUtils.js'; +import { registerPromptActions } from '../promptSyntax/promptFileActions.js'; import { CHAT_CATEGORY } from './chatActions.js'; -import { registerPromptActions } from './promptActions/index.js'; export function registerChatContextActions() { registerAction2(AttachContextAction); diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/attachInstructions.ts b/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/attachInstructions.ts deleted file mode 100644 index 6f3e213326a..00000000000 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/attachInstructions.ts +++ /dev/null @@ -1,91 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { assertDefined } from '../../../../../../../../../base/common/types.js'; -import { URI } from '../../../../../../../../../base/common/uri.js'; -import { ICommandService } from '../../../../../../../../../platform/commands/common/commands.js'; -import { IViewsService } from '../../../../../../../../services/views/common/viewsService.js'; -import { IChatWidget, showChatView } from '../../../../../chat.js'; -import { ACTION_ID_NEW_CHAT } from '../../../../chatActions.js'; -import { IAttachInstructionsActionOptions } from '../../../chatAttachInstructionsAction.js'; - -/** - * Options for the {@link attachInstructionsFiles} function. - */ -export interface IAttachOptions { - /** - * Chat widget instance to attach the prompt to. - */ - readonly widget?: IChatWidget; - /** - * Whether to create a new chat session and - * attach the prompt to it. - */ - readonly inNewChat?: boolean; - - readonly viewsService: IViewsService; - readonly commandService: ICommandService; -} - -/** - * Attaches provided instructions to a chat input. - */ -export const attachInstructionsFiles = async ( - files: URI[], - options: IAttachOptions, -): Promise => { - const widget = await getChatWidgetObject(options); - - for (const file of files) { - widget.attachmentModel.promptInstructions.add(file); - } - - return widget; -}; - -/** - * Gets a chat widget based on the provided {@link IAttachInstructionsActionOptions.widget widget} - * reference and the `inNewChat` flag. - * - * @throws if failed to reveal a chat widget. - */ -export const getChatWidgetObject = async ( - options: IAttachOptions, -): Promise => { - const { widget, inNewChat } = options; - - // if a new chat sessions needs to be created, or there is no - // chat widget reference provided, show a chat view, otherwise - // re-use the existing chat widget - if ((inNewChat === true) || (widget === undefined)) { - return await showChat(options, inNewChat); - } - - return widget; -}; - -/** - * Reveals an existing one or creates a new one based on - * the provided `createNew` flag. - */ -const showChat = async ( - options: IAttachOptions, - createNew: boolean = false, -): Promise => { - const { commandService, viewsService } = options; - - if (createNew === true) { - await commandService.executeCommand(ACTION_ID_NEW_CHAT); - } - - const widget = await showChatView(viewsService); - - assertDefined( - widget, - 'Chat widget must be defined.', - ); - - return widget; -}; diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/detachPrompt.ts b/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/detachPrompt.ts deleted file mode 100644 index 4f56b99be1b..00000000000 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/detachPrompt.ts +++ /dev/null @@ -1,34 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IChatWidget } from '../../../../../chat.js'; -import { URI } from '../../../../../../../../../base/common/uri.js'; - -/** - * Options for the {@link detachPrompt} function. - */ -export interface IDetachPromptOptions { - /** - * Chat widget instance to attach the prompt to. - */ - readonly widget: IChatWidget; -} - -/** - * Detaches provided prompts to a chat input. - */ -export const detachPrompt = async ( - file: URI, - options: IDetachPromptOptions, -): Promise => { - const { widget } = options; - - widget - .attachmentModel - .promptInstructions - .remove(file); - - return widget; -}; diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/runPrompt.ts b/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/runPrompt.ts deleted file mode 100644 index f3a49ad2f3d..00000000000 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/utils/runPrompt.ts +++ /dev/null @@ -1,54 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IChatWidget } from '../../../../../chat.js'; -import { getChatWidgetObject } from './attachInstructions.js'; -import { URI } from '../../../../../../../../../base/common/uri.js'; -import { IViewsService } from '../../../../../../../../services/views/common/viewsService.js'; -import { ICommandService } from '../../../../../../../../../platform/commands/common/commands.js'; -import { getPromptCommandName } from '../../../../../../common/promptSyntax/service/promptsService.js'; - -/** - * Options for the {@link runPromptFile} function. - */ -export interface IRunPromptOptions { - /** - * Chat widget instance to attach the prompt to. - */ - readonly widget?: IChatWidget; - /** - * Whether to create a new chat session and - * attach the instructions file to it. - */ - readonly inNewChat?: boolean; - - readonly viewsService: IViewsService; - readonly commandService: ICommandService; -} - -/** - * Return value of the {@link runPromptFile} function. - */ -interface IRunPromptResult { - readonly widget: IChatWidget; -} - -/** - * Runs the prompt file. - */ -export const runPromptFile = async ( - file: URI, - options: IRunPromptOptions, -): Promise => { - - const widget = await getChatWidgetObject(options); - - widget.setInput(`/${getPromptCommandName(file.path)}`); - // submit the prompt immediately - await widget.acceptInput(); - - - return { widget }; -}; diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 705ee660983..359dc97c4df 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -73,7 +73,6 @@ import { registerQuickChatActions } from './actions/chatQuickInputActions.js'; import { registerChatTitleActions } from './actions/chatTitleActions.js'; import { registerChatToolActions } from './actions/chatToolActions.js'; import { ChatTransferContribution } from './actions/chatTransfer.js'; -import { SAVE_TO_PROMPT_SLASH_COMMAND_NAME, runSaveToPromptAction } from './actions/promptActions/chatSaveToPromptAction.js'; import { IChatAccessibilityService, IChatCodeBlockContextProviderService, IChatWidgetService, IQuickChatService } from './chat.js'; import { ChatAccessibilityService } from './chatAccessibilityService.js'; import './chatAttachmentModel.js'; @@ -105,12 +104,12 @@ import './contrib/chatInputEditorContrib.js'; import './contrib/chatInputEditorHover.js'; import { ChatRelatedFilesContribution } from './contrib/chatInputRelatedFilesContrib.js'; import { LanguageModelToolsService } from './languageModelToolsService.js'; -import './promptSyntax/contributions/createPromptCommand/createPromptCommand.js'; import { ChatViewsWelcomeHandler } from './viewsWelcome/chatViewsWelcomeHandler.js'; import { registerAction2 } from '../../../../platform/actions/common/actions.js'; import product from '../../../../platform/product/common/product.js'; import { ChatModeService, IChatModeService } from '../common/chatModes.js'; import { ChatResponseResourceFileSystemProvider } from '../common/chatResponseResourceFileSystemProvider.js'; +import { runSaveToPromptAction, SAVE_TO_PROMPT_SLASH_COMMAND_NAME } from './promptSyntax/saveToPromptAction.js'; // Register configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatAttachInstructionsAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts similarity index 71% rename from src/vs/workbench/contrib/chat/browser/actions/promptActions/chatAttachInstructionsAction.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts index 52432186bc9..3994c454e7f 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatAttachInstructionsAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts @@ -3,36 +3,33 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ChatViewId, IChatWidget, IChatWidgetService } from '../../chat.js'; -import { CHAT_CATEGORY } from '../chatActions.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import { localize, localize2 } from '../../../../../../nls.js'; -import { ChatContextKeys } from '../../../common/chatContextKeys.js'; -import { assertDefined } from '../../../../../../base/common/types.js'; -import { IPromptsService } from '../../../common/promptSyntax/service/types.js'; -import { PromptsConfig } from '../../../../../../platform/prompts/common/config.js'; -import { IViewsService } from '../../../../../services/views/common/viewsService.js'; -import { PromptFilePickers } from './dialogs/askToSelectPrompt/promptFilePickers.js'; -import { ServicesAccessor } from '../../../../../../editor/browser/editorExtensions.js'; -import { ICommandService } from '../../../../../../platform/commands/common/commands.js'; -import { ContextKeyExpr } from '../../../../../../platform/contextkey/common/contextkey.js'; -import { Action2, MenuId, registerAction2 } from '../../../../../../platform/actions/common/actions.js'; -import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { attachInstructionsFiles, IAttachOptions } from './dialogs/askToSelectPrompt/utils/attachInstructions.js'; -import { ChatContextPick, IChatContextPickerItem, IChatContextPickerPickItem } from '../../chatContextPickService.js'; -import { IQuickPickSeparator } from '../../../../../../platform/quickinput/common/quickInput.js'; -import { Codicon } from '../../../../../../base/common/codicons.js'; -import { getCleanPromptName, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { compare } from '../../../../../../base/common/strings.js'; -import { ILabelService } from '../../../../../../platform/label/common/label.js'; -import { dirname } from '../../../../../../base/common/resources.js'; -import { IPromptFileVariableEntry } from '../../../common/chatModel.js'; -import { KeyMod, KeyCode } from '../../../../../../base/common/keyCodes.js'; -import { KeybindingWeight } from '../../../../../../platform/keybinding/common/keybindingsRegistry.js'; -import { ICodeEditorService } from '../../../../../../editor/browser/services/codeEditorService.js'; -import { INSTRUCTIONS_LANGUAGE_ID } from '../../../common/promptSyntax/constants.js'; -import { CancellationToken } from '../../../../../../base/common/cancellation.js'; -import { IOpenerService } from '../../../../../../platform/opener/common/opener.js'; +import { ChatViewId, IChatWidget, IChatWidgetService, showChatView } from '../chat.js'; +import { CHAT_CATEGORY } from '../actions/chatActions.js'; +import { URI } from '../../../../../base/common/uri.js'; +import { localize, localize2 } from '../../../../../nls.js'; +import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { IPromptsService } from '../../common/promptSyntax/service/types.js'; +import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { IViewsService } from '../../../../services/views/common/viewsService.js'; +import { PromptFilePickers } from './pickers/promptFilePickers.js'; +import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; +import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; +import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; +import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; +import { ChatContextPick, IChatContextPickerItem, IChatContextPickerPickItem } from '../chatContextPickService.js'; +import { IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js'; +import { Codicon } from '../../../../../base/common/codicons.js'; +import { getCleanPromptName, PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { compare } from '../../../../../base/common/strings.js'; +import { ILabelService } from '../../../../../platform/label/common/label.js'; +import { dirname } from '../../../../../base/common/resources.js'; +import { IPromptFileVariableEntry } from '../../common/chatModel.js'; +import { KeyMod, KeyCode } from '../../../../../base/common/keyCodes.js'; +import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; +import { INSTRUCTIONS_LANGUAGE_ID } from '../../common/promptSyntax/constants.js'; +import { CancellationToken } from '../../../../../base/common/cancellation.js'; +import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; /** * Action ID for the `Attach Instruction` action. @@ -100,7 +97,6 @@ class AttachInstructionsAction extends Action2 { options?: IAttachInstructionsActionOptions, ): Promise { const viewsService = accessor.get(IViewsService); - const commandService = accessor.get(ICommandService); const instaService = accessor.get(IInstantiationService); if (!options) { @@ -114,25 +110,15 @@ class AttachInstructionsAction extends Action2 { const { skipSelectionDialog, resource } = options; - const attachOptions: IAttachOptions = { - widget: options.widget, - viewsService, - commandService, - }; - if (skipSelectionDialog) { - assertDefined( - resource, - 'Resource must be defined when skipping prompt selection dialog.', - ); - - const widget = await attachInstructionsFiles( - [resource], - attachOptions, - ); + const widget = options.widget ?? (await showChatView(viewsService)); + if (!widget) { + return; + } + if (skipSelectionDialog && resource) { + widget.attachmentModel.promptInstructions.add(resource); widget.focusInput(); - return; } @@ -144,10 +130,7 @@ class AttachInstructionsAction extends Action2 { const result = await pickers.selectPromptFile({ resource, placeholder, type: PromptsType.instructions }); if (result !== undefined) { - const widget = await attachInstructionsFiles( - [result.promptFile], - attachOptions, - ); + widget.attachmentModel.promptInstructions.add(result.promptFile); widget.focusInput(); } } diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatModeActions.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts similarity index 66% rename from src/vs/workbench/contrib/chat/browser/actions/promptActions/chatModeActions.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts index a8df9776fc7..8ff2232a697 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatModeActions.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts @@ -3,19 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CHAT_CATEGORY } from '../chatActions.js'; -import { Codicon } from '../../../../../../base/common/codicons.js'; -import { ChatContextKeys } from '../../../common/chatContextKeys.js'; -import { localize, localize2 } from '../../../../../../nls.js'; -import { PromptsConfig } from '../../../../../../platform/prompts/common/config.js'; -import { PromptFilePickers } from './dialogs/askToSelectPrompt/promptFilePickers.js'; -import { ServicesAccessor } from '../../../../../../editor/browser/editorExtensions.js'; -import { ContextKeyExpr } from '../../../../../../platform/contextkey/common/contextkey.js'; -import { Action2, MenuId, registerAction2 } from '../../../../../../platform/actions/common/actions.js'; -import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { IOpenerService } from '../../../../../../platform/opener/common/opener.js'; -import { ChatViewId } from '../../chat.js'; +import { CHAT_CATEGORY } from '../actions/chatActions.js'; +import { Codicon } from '../../../../../base/common/codicons.js'; +import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { localize, localize2 } from '../../../../../nls.js'; +import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { PromptFilePickers } from './pickers/promptFilePickers.js'; +import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; +import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; +import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; +import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; +import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; +import { ChatViewId } from '../chat.js'; /** * Action ID for the `Configure Custom Chat Mode` action. diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/errors.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/errors.ts deleted file mode 100644 index 5d7ed5c8416..00000000000 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/errors.ts +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { localize } from '../../../../../../../nls.js'; - -/** - * Base class for all prompt creation errors. - */ -class BaseCreatePromptError extends Error { } - -/** - * Error for when a folder already exists at the provided - * prompt file path. - */ -export class FolderExists extends BaseCreatePromptError { - constructor(path: string) { - super(localize( - 'workbench.command.prompts.create.error.folder-exists', - "Folder already exists at '{0}'.", - path, - )); - } -} - -/** - * Error for when an invalid prompt file name is provided. - */ -export class InvalidPromptName extends BaseCreatePromptError { - constructor(name: string) { - super(localize( - 'workbench.command.prompts.create.error.invalid-prompt-name', - "Invalid prompt file name '{0}'.", - name, - )); - } -} diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/utils/createPromptFile.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/utils/createPromptFile.ts deleted file mode 100644 index 790ec76fad8..00000000000 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/utils/createPromptFile.ts +++ /dev/null @@ -1,76 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { FolderExists, InvalidPromptName } from '../errors.js'; -import { URI } from '../../../../../../../../base/common/uri.js'; -import { assert } from '../../../../../../../../base/common/assert.js'; -import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; -import { dirname } from '../../../../../../../../base/common/resources.js'; -import { IFileService } from '../../../../../../../../platform/files/common/files.js'; -import { isPromptOrInstructionsFile, PROMPT_FILE_EXTENSION } from '../../../../../../../../platform/prompts/common/prompts.js'; - -/** - * Options for the {@link createPromptFile} utility. - */ -interface ICreatePromptFileOptions { - /** - * Name of the prompt file including file extension. - * The file extension must be {@link PROMPT_FILE_EXTENSION}. - */ - readonly fileName: string; - - /** - * Destination folder of the prompt file. - */ - readonly folder: URI; - - /** - * Initial contents of the prompt file. - */ - readonly content: string; -} - -/** - * Create a prompt file at the provided folder and with - * the provided file content. - * - * @throws in the following cases: - * - if the `fileName` does not end with {@link PROMPT_FILE_EXTENSION} - * - if a folder or file with the same already name exists in the destination folder - */ -export async function createPromptFile( - fileService: IFileService, - options: ICreatePromptFileOptions, -): Promise { - const { fileName, folder, content } = options; - - const promptUri = URI.joinPath(folder, fileName); - - assert( - isPromptOrInstructionsFile(promptUri), - new InvalidPromptName(fileName), - ); - - // if a folder or file with the same name exists, throw an error - if (await fileService.exists(promptUri)) { - const promptInfo = await fileService.resolve(promptUri); - - // if existing object is a folder, throw an error - assert( - !promptInfo.isDirectory, - new FolderExists(promptUri.fsPath), - ); - - return promptUri; - } - - // ensure the parent folder of the prompt file exists - await fileService.createFolder(dirname(promptUri)); - - // create the prompt file with the provided text content - await fileService.createFile(promptUri, VSBuffer.fromString(content)); - - return promptUri; -} diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/createPromptCommand.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/newPromptFileActions.ts similarity index 65% rename from src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/createPromptCommand.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/newPromptFileActions.ts index 61919616c16..44242df33bb 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/createPromptCommand.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/newPromptFileActions.ts @@ -3,34 +3,34 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { isEqual } from '../../../../../../../base/common/resources.js'; -import { URI } from '../../../../../../../base/common/uri.js'; -import { getCodeEditor } from '../../../../../../../editor/browser/editorBrowser.js'; -import { SnippetController2 } from '../../../../../../../editor/contrib/snippet/browser/snippetController2.js'; -import { localize } from '../../../../../../../nls.js'; -import { Action2, MenuId, registerAction2 } from '../../../../../../../platform/actions/common/actions.js'; -import { ICommandService } from '../../../../../../../platform/commands/common/commands.js'; -import { ContextKeyExpr } from '../../../../../../../platform/contextkey/common/contextkey.js'; -import { IFileService } from '../../../../../../../platform/files/common/files.js'; -import { IInstantiationService, ServicesAccessor } from '../../../../../../../platform/instantiation/common/instantiation.js'; -import { KeybindingWeight } from '../../../../../../../platform/keybinding/common/keybindingsRegistry.js'; -import { ILogService } from '../../../../../../../platform/log/common/log.js'; -import { INotificationService, NeverShowAgainScope, Severity } from '../../../../../../../platform/notification/common/notification.js'; -import { IOpenerService } from '../../../../../../../platform/opener/common/opener.js'; -import { PromptsConfig } from '../../../../../../../platform/prompts/common/config.js'; -import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; -import { IUserDataSyncEnablementService, SyncResource } from '../../../../../../../platform/userDataSync/common/userDataSync.js'; -import { IEditorService } from '../../../../../../services/editor/common/editorService.js'; -import { CONFIGURE_SYNC_COMMAND_ID } from '../../../../../../services/userDataSync/common/userDataSync.js'; -import { ISnippetsService } from '../../../../../snippets/browser/snippets.js'; -import { ChatContextKeys } from '../../../../common/chatContextKeys.js'; -import { getLanguageIdForPromptsType } from '../../../../common/promptSyntax/constants.js'; -import { CHAT_CATEGORY } from '../../../actions/chatActions.js'; -import { askForPromptFileName } from './dialogs/askForPromptName.js'; -import { askForPromptSourceFolder } from './dialogs/askForPromptSourceFolder.js'; -import { createPromptFile } from './utils/createPromptFile.js'; +import { isEqual } from '../../../../../base/common/resources.js'; +import { URI } from '../../../../../base/common/uri.js'; +import { getCodeEditor } from '../../../../../editor/browser/editorBrowser.js'; +import { SnippetController2 } from '../../../../../editor/contrib/snippet/browser/snippetController2.js'; +import { localize } from '../../../../../nls.js'; +import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; +import { ICommandService } from '../../../../../platform/commands/common/commands.js'; +import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; +import { IFileService } from '../../../../../platform/files/common/files.js'; +import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; +import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { ILogService } from '../../../../../platform/log/common/log.js'; +import { INotificationService, NeverShowAgainScope, Severity } from '../../../../../platform/notification/common/notification.js'; +import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; +import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { IUserDataSyncEnablementService, SyncResource } from '../../../../../platform/userDataSync/common/userDataSync.js'; +import { IEditorService } from '../../../../services/editor/common/editorService.js'; +import { CONFIGURE_SYNC_COMMAND_ID } from '../../../../services/userDataSync/common/userDataSync.js'; +import { ISnippetsService } from '../../../snippets/browser/snippets.js'; +import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { getLanguageIdForPromptsType } from '../../common/promptSyntax/constants.js'; +import { CHAT_CATEGORY } from '../actions/chatActions.js'; +import { askForPromptFileName } from './pickers/askForPromptName.js'; +import { askForPromptSourceFolder } from './pickers/askForPromptSourceFolder.js'; -class AbstractNewPromptOrInstructionsFileAction extends Action2 { + +class AbstractNewPromptFileAction extends Action2 { constructor(id: string, title: string, private readonly type: PromptsType) { super({ @@ -70,11 +70,12 @@ class AbstractNewPromptOrInstructionsFileAction extends Action2 { return; } - const promptUri = await createPromptFile(fileService, { - fileName, - folder: selectedFolder.uri, - content: '' - }); + // create the prompt file + + await fileService.createFolder(selectedFolder.uri); + + const promptUri = URI.joinPath(selectedFolder.uri, fileName); + await fileService.createFile(promptUri); await openerService.open(promptUri); @@ -150,24 +151,26 @@ export const NEW_PROMPT_COMMAND_ID = 'workbench.command.new.prompt'; export const NEW_INSTRUCTIONS_COMMAND_ID = 'workbench.command.new.instructions'; export const NEW_MODE_COMMAND_ID = 'workbench.command.new.mode'; -class NewPromptFileAction extends AbstractNewPromptOrInstructionsFileAction { +class NewPromptFileAction extends AbstractNewPromptFileAction { constructor() { super(NEW_PROMPT_COMMAND_ID, localize('commands.new.prompt.local.title', "New Prompt File..."), PromptsType.prompt); } } -class NewInstructionsFileAction extends AbstractNewPromptOrInstructionsFileAction { +class NewInstructionsFileAction extends AbstractNewPromptFileAction { constructor() { super(NEW_INSTRUCTIONS_COMMAND_ID, localize('commands.new.instructions.local.title', "New Instructions File..."), PromptsType.instructions); } } -class NewModeFileAction extends AbstractNewPromptOrInstructionsFileAction { +class NewModeFileAction extends AbstractNewPromptFileAction { constructor() { super(NEW_MODE_COMMAND_ID, localize('commands.new.mode.local.title', "New Mode File..."), PromptsType.mode); } } -registerAction2(NewPromptFileAction); -registerAction2(NewInstructionsFileAction); -registerAction2(NewModeFileAction); +export function registerNewPromptFileActions(): void { + registerAction2(NewPromptFileAction); + registerAction2(NewInstructionsFileAction); + registerAction2(NewModeFileAction); +} diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptName.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptName.ts similarity index 83% rename from src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptName.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptName.ts index cdab1994fda..b0a3210efbe 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptName.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptName.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from '../../../../../../../../nls.js'; -import { getPromptFileExtension, PromptsType } from '../../../../../../../../platform/prompts/common/prompts.js'; -import { IQuickInputService } from '../../../../../../../../platform/quickinput/common/quickInput.js'; -import { URI } from '../../../../../../../../base/common/uri.js'; -import { IFileService } from '../../../../../../../../platform/files/common/files.js'; -import Severity from '../../../../../../../../base/common/severity.js'; -import { isValidBasename } from '../../../../../../../../base/common/extpath.js'; -import { ServicesAccessor } from '../../../../../../../../editor/browser/editorExtensions.js'; +import { localize } from '../../../../../../nls.js'; +import { getPromptFileExtension, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { IQuickInputService } from '../../../../../../platform/quickinput/common/quickInput.js'; +import { URI } from '../../../../../../base/common/uri.js'; +import { IFileService } from '../../../../../../platform/files/common/files.js'; +import Severity from '../../../../../../base/common/severity.js'; +import { isValidBasename } from '../../../../../../base/common/extpath.js'; +import { ServicesAccessor } from '../../../../../../editor/browser/editorExtensions.js'; /** * Asks the user for a file name. diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptSourceFolder.ts similarity index 88% rename from src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptSourceFolder.ts index 86ddd6733ae..b488f643466 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptSourceFolder.ts @@ -3,17 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from '../../../../../../../../nls.js'; -import { URI } from '../../../../../../../../base/common/uri.js'; -import { basename, extUri, isEqual } from '../../../../../../../../base/common/resources.js'; -import { ILabelService } from '../../../../../../../../platform/label/common/label.js'; -import { IOpenerService } from '../../../../../../../../platform/opener/common/opener.js'; -import { PROMPT_DOCUMENTATION_URL } from '../../../../../common/promptSyntax/constants.js'; -import { IWorkspaceContextService } from '../../../../../../../../platform/workspace/common/workspace.js'; -import { IPromptPath, IPromptsService } from '../../../../../common/promptSyntax/service/types.js'; -import { IPickOptions, IQuickInputService, IQuickPickItem } from '../../../../../../../../platform/quickinput/common/quickInput.js'; -import { ServicesAccessor } from '../../../../../../../../platform/instantiation/common/instantiation.js'; -import { PromptsType } from '../../../../../../../../platform/prompts/common/prompts.js'; +import { basename, extUri, isEqual } from '../../../../../../base/common/resources.js'; +import { URI } from '../../../../../../base/common/uri.js'; +import { ServicesAccessor } from '../../../../../../editor/browser/editorExtensions.js'; +import { localize } from '../../../../../../nls.js'; +import { ILabelService } from '../../../../../../platform/label/common/label.js'; +import { IOpenerService } from '../../../../../../platform/opener/common/opener.js'; +import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { IPickOptions, IQuickInputService, IQuickPickItem } from '../../../../../../platform/quickinput/common/quickInput.js'; +import { IWorkspaceContextService } from '../../../../../../platform/workspace/common/workspace.js'; +import { PROMPT_DOCUMENTATION_URL } from '../../../common/promptSyntax/constants.js'; +import { IPromptPath, IPromptsService } from '../../../common/promptSyntax/service/types.js'; + interface IFolderQuickPickItem extends IQuickPickItem { readonly folder: IPromptPath; diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/promptFilePickers.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/promptFilePickers.ts similarity index 87% rename from src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/promptFilePickers.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/promptFilePickers.ts index 95dd2fd5d36..cc93b1d078b 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/dialogs/askToSelectPrompt/promptFilePickers.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/promptFilePickers.ts @@ -3,29 +3,29 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from '../../../../../../../../nls.js'; -import { URI } from '../../../../../../../../base/common/uri.js'; -import { assert } from '../../../../../../../../base/common/assert.js'; -import { Codicon } from '../../../../../../../../base/common/codicons.js'; -import { ThemeIcon } from '../../../../../../../../base/common/themables.js'; -import { IPromptPath, IPromptsService } from '../../../../../common/promptSyntax/service/types.js'; -import { dirname, extUri, joinPath } from '../../../../../../../../base/common/resources.js'; -import { DisposableStore } from '../../../../../../../../base/common/lifecycle.js'; -import { IFileService } from '../../../../../../../../platform/files/common/files.js'; -import { ILabelService } from '../../../../../../../../platform/label/common/label.js'; -import { IOpenerService } from '../../../../../../../../platform/opener/common/opener.js'; -import { IDialogService } from '../../../../../../../../platform/dialogs/common/dialogs.js'; -import { ICommandService } from '../../../../../../../../platform/commands/common/commands.js'; -import { getCleanPromptName, PromptsType } from '../../../../../../../../platform/prompts/common/prompts.js'; -import { INSTRUCTIONS_DOCUMENTATION_URL, MODE_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../../../../../common/promptSyntax/constants.js'; -import { NEW_PROMPT_COMMAND_ID, NEW_INSTRUCTIONS_COMMAND_ID, NEW_MODE_COMMAND_ID } from '../../../../promptSyntax/contributions/createPromptCommand/createPromptCommand.js'; -import { IKeyMods, IQuickInputButton, IQuickInputService, IQuickPick, IQuickPickItem, IQuickPickItemButtonEvent } from '../../../../../../../../platform/quickinput/common/quickInput.js'; -import { askForPromptFileName } from '../../../../promptSyntax/contributions/createPromptCommand/dialogs/askForPromptName.js'; -import { IInstantiationService } from '../../../../../../../../platform/instantiation/common/instantiation.js'; -import { CancellationToken } from '../../../../../../../../base/common/cancellation.js'; -import { askForPromptSourceFolder } from '../../../../promptSyntax/contributions/createPromptCommand/dialogs/askForPromptSourceFolder.js'; -import { UILabelProvider } from '../../../../../../../../base/common/keybindingLabels.js'; -import { OS } from '../../../../../../../../base/common/platform.js'; +import { localize } from '../../../../../../nls.js'; +import { URI } from '../../../../../../base/common/uri.js'; +import { assert } from '../../../../../../base/common/assert.js'; +import { Codicon } from '../../../../../../base/common/codicons.js'; +import { ThemeIcon } from '../../../../../../base/common/themables.js'; +import { IPromptPath, IPromptsService } from '../../../common/promptSyntax/service/types.js'; +import { dirname, extUri, joinPath } from '../../../../../../base/common/resources.js'; +import { DisposableStore } from '../../../../../../base/common/lifecycle.js'; +import { IFileService } from '../../../../../../platform/files/common/files.js'; +import { ILabelService } from '../../../../../../platform/label/common/label.js'; +import { IOpenerService } from '../../../../../../platform/opener/common/opener.js'; +import { IDialogService } from '../../../../../../platform/dialogs/common/dialogs.js'; +import { ICommandService } from '../../../../../../platform/commands/common/commands.js'; +import { getCleanPromptName, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { INSTRUCTIONS_DOCUMENTATION_URL, MODE_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../../../common/promptSyntax/constants.js'; +import { NEW_PROMPT_COMMAND_ID, NEW_INSTRUCTIONS_COMMAND_ID, NEW_MODE_COMMAND_ID } from '../newPromptFileActions.js'; +import { IKeyMods, IQuickInputButton, IQuickInputService, IQuickPick, IQuickPickItem, IQuickPickItemButtonEvent } from '../../../../../../platform/quickinput/common/quickInput.js'; +import { askForPromptFileName } from './askForPromptName.js'; +import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; +import { CancellationToken } from '../../../../../../base/common/cancellation.js'; +import { UILabelProvider } from '../../../../../../base/common/keybindingLabels.js'; +import { OS } from '../../../../../../base/common/platform.js'; +import { askForPromptSourceFolder } from './askForPromptSourceFolder.js'; /** * Options for the {@link askToSelectInstructions} function. diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/index.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/promptFileActions.ts similarity index 62% rename from src/vs/workbench/contrib/chat/browser/actions/promptActions/index.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/promptFileActions.ts index a7f07d314d2..46b22c19fef 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/index.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/promptFileActions.ts @@ -3,17 +3,20 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerRunPromptActions } from './chatRunPromptAction.js'; -import { registerSaveToPromptActions } from './chatSaveToPromptAction.js'; -import { registerAttachPromptActions } from './chatAttachInstructionsAction.js'; +import { registerAttachPromptActions } from './attachInstructionsAction.js'; import { registerChatModeActions } from './chatModeActions.js'; +import { registerRunPromptActions } from './runPromptAction.js'; +import { registerSaveToPromptActions } from './saveToPromptAction.js'; +import { registerNewPromptFileActions } from './newPromptFileActions.js'; + /** * Helper to register all actions related to reusable prompt files. */ -export const registerPromptActions = () => { +export function registerPromptActions(): void { registerRunPromptActions(); registerAttachPromptActions(); registerSaveToPromptActions(); registerChatModeActions(); -}; + registerNewPromptFileActions(); +} diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatRunPromptAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.ts similarity index 71% rename from src/vs/workbench/contrib/chat/browser/actions/promptActions/chatRunPromptAction.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.ts index b4e5b938af8..d58eddbcd61 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatRunPromptAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.ts @@ -3,34 +3,34 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ChatViewId, IChatWidget } from '../../chat.js'; -import { CHAT_CATEGORY } from '../chatActions.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import { OS } from '../../../../../../base/common/platform.js'; -import { Codicon } from '../../../../../../base/common/codicons.js'; -import { ChatContextKeys } from '../../../common/chatContextKeys.js'; -import { assertDefined } from '../../../../../../base/common/types.js'; -import { ThemeIcon } from '../../../../../../base/common/themables.js'; -import { ResourceContextKey } from '../../../../../common/contextkeys.js'; -import { KeyCode, KeyMod } from '../../../../../../base/common/keyCodes.js'; -import { PROMPT_LANGUAGE_ID } from '../../../common/promptSyntax/constants.js'; -import { ILocalizedString, localize, localize2 } from '../../../../../../nls.js'; -import { UILabelProvider } from '../../../../../../base/common/keybindingLabels.js'; -import { ICommandAction } from '../../../../../../platform/action/common/action.js'; -import { PromptsConfig } from '../../../../../../platform/prompts/common/config.js'; -import { IViewsService } from '../../../../../services/views/common/viewsService.js'; -import { PromptFilePickers } from './dialogs/askToSelectPrompt/promptFilePickers.js'; -import { ServicesAccessor } from '../../../../../../editor/browser/editorExtensions.js'; -import { EditorContextKeys } from '../../../../../../editor/common/editorContextKeys.js'; -import { ICommandService } from '../../../../../../platform/commands/common/commands.js'; -import { ContextKeyExpr } from '../../../../../../platform/contextkey/common/contextkey.js'; -import { IRunPromptOptions, runPromptFile } from './dialogs/askToSelectPrompt/utils/runPrompt.js'; -import { ICodeEditorService } from '../../../../../../editor/browser/services/codeEditorService.js'; -import { KeybindingWeight } from '../../../../../../platform/keybinding/common/keybindingsRegistry.js'; -import { Action2, MenuId, registerAction2 } from '../../../../../../platform/actions/common/actions.js'; -import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { IOpenerService } from '../../../../../../platform/opener/common/opener.js'; +import { ChatViewId, IChatWidget, showChatView } from '../chat.js'; +import { ACTION_ID_NEW_CHAT, CHAT_CATEGORY } from '../actions/chatActions.js'; +import { URI } from '../../../../../base/common/uri.js'; +import { OS } from '../../../../../base/common/platform.js'; +import { Codicon } from '../../../../../base/common/codicons.js'; +import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { assertDefined } from '../../../../../base/common/types.js'; +import { ThemeIcon } from '../../../../../base/common/themables.js'; +import { ResourceContextKey } from '../../../../common/contextkeys.js'; +import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js'; +import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/constants.js'; +import { ILocalizedString, localize, localize2 } from '../../../../../nls.js'; +import { UILabelProvider } from '../../../../../base/common/keybindingLabels.js'; +import { ICommandAction } from '../../../../../platform/action/common/action.js'; +import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { IViewsService } from '../../../../services/views/common/viewsService.js'; +import { PromptFilePickers } from './pickers/promptFilePickers.js'; +import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; +import { EditorContextKeys } from '../../../../../editor/common/editorContextKeys.js'; +import { ICommandService } from '../../../../../platform/commands/common/commands.js'; +import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; +import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; +import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; +import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; +import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; +import { getPromptCommandName } from '../../common/promptSyntax/service/promptsService.js'; /** * Condition for the `Run Current Prompt` action. @@ -132,7 +132,7 @@ abstract class RunPromptBaseAction extends Action2 { resource: URI | undefined, inNewChat: boolean, accessor: ServicesAccessor, - ): Promise { + ): Promise { const viewsService = accessor.get(IViewsService); const commandService = accessor.get(ICommandService); @@ -142,15 +142,16 @@ abstract class RunPromptBaseAction extends Action2 { 'Cannot find URI resource for an active text editor.', ); - const { widget } = await runPromptFile( - resource, - { - inNewChat, - commandService, - viewsService, - }, - ); + if (inNewChat === true) { + await commandService.executeCommand(ACTION_ID_NEW_CHAT); + } + const widget = await showChatView(viewsService); + if (widget) { + widget.setInput(`/${getPromptCommandName(resource.path)}`); + // submit the prompt immediately + await widget.acceptInput(); + } return widget; } } @@ -177,7 +178,7 @@ class RunCurrentPromptAction extends RunPromptBaseAction { public override async run( accessor: ServicesAccessor, resource: URI | undefined, - ): Promise { + ): Promise { return await super.execute( resource, false, @@ -225,16 +226,18 @@ class RunSelectedPromptAction extends Action2 { } const { promptFile, keyMods } = result; - const runPromptOptions: IRunPromptOptions = { - inNewChat: keyMods.ctrlCmd, - viewsService, - commandService, - }; - const { widget } = await runPromptFile( - promptFile, - runPromptOptions, - ); - widget.focusInput(); + + if (keyMods.ctrlCmd === true) { + await commandService.executeCommand(ACTION_ID_NEW_CHAT); + } + + const widget = await showChatView(viewsService); + if (widget) { + widget.setInput(`/${getPromptCommandName(promptFile.path)}`); + // submit the prompt immediately + await widget.acceptInput(); + widget.focusInput(); + } } } @@ -281,16 +284,14 @@ class ManagePromptFilesAction extends Action2 { /** * Gets `URI` of a prompt file open in an active editor instance, if any. */ -export const getActivePromptFileUri = ( - accessor: ServicesAccessor, -): URI | undefined => { +function getActivePromptFileUri(accessor: ServicesAccessor): URI | undefined { const codeEditorService = accessor.get(ICodeEditorService); const model = codeEditorService.getActiveCodeEditor()?.getModel(); if (model?.getLanguageId() === PROMPT_LANGUAGE_ID) { return model.uri; } return undefined; -}; +} /** @@ -329,7 +330,7 @@ class RunCurrentPromptInNewChatAction extends RunPromptBaseAction { public override async run( accessor: ServicesAccessor, resource: URI, - ): Promise { + ): Promise { return await super.execute( resource, true, @@ -341,9 +342,9 @@ class RunCurrentPromptInNewChatAction extends RunPromptBaseAction { /** * Helper to register all the `Run Current Prompt` actions. */ -export const registerRunPromptActions = () => { +export function registerRunPromptActions(): void { registerAction2(RunCurrentPromptInNewChatAction); registerAction2(RunCurrentPromptAction); registerAction2(RunSelectedPromptAction); registerAction2(ManagePromptFilesAction); -}; +} diff --git a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatSaveToPromptAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts similarity index 84% rename from src/vs/workbench/contrib/chat/browser/actions/promptActions/chatSaveToPromptAction.ts rename to src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts index 52a38b7ed80..1a95f50de6c 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/promptActions/chatSaveToPromptAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts @@ -3,22 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChatWidget } from '../../chat.js'; -import { CHAT_CATEGORY } from '../chatActions.js'; -import { localize2 } from '../../../../../../nls.js'; -import { IEditorPane } from '../../../../../common/editor.js'; -import { ChatContextKeys } from '../../../common/chatContextKeys.js'; -import { assertDefined } from '../../../../../../base/common/types.js'; -import { ILogService } from '../../../../../../platform/log/common/log.js'; -import { PROMPT_LANGUAGE_ID } from '../../../common/promptSyntax/constants.js'; -import { PromptsConfig } from '../../../../../../platform/prompts/common/config.js'; -import { ServicesAccessor } from '../../../../../../editor/browser/editorExtensions.js'; -import { IEditorService } from '../../../../../services/editor/common/editorService.js'; -import { ICommandService } from '../../../../../../platform/commands/common/commands.js'; -import { ILanguageModelToolsService } from '../../../common/languageModelToolsService.js'; -import { ContextKeyExpr } from '../../../../../../platform/contextkey/common/contextkey.js'; -import { chatSubcommandLeader, IParsedChatRequest } from '../../../common/chatParserTypes.js'; -import { Action2, registerAction2 } from '../../../../../../platform/actions/common/actions.js'; +import { assertDefined } from '../../../../../base/common/types.js'; +import { localize2 } from '../../../../../nls.js'; +import { Action2, registerAction2 } from '../../../../../platform/actions/common/actions.js'; +import { ICommandService } from '../../../../../platform/commands/common/commands.js'; +import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; +import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; +import { ILogService } from '../../../../../platform/log/common/log.js'; +import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { IEditorPane } from '../../../../common/editor.js'; +import { IEditorService } from '../../../../services/editor/common/editorService.js'; +import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { chatSubcommandLeader, IParsedChatRequest } from '../../common/chatParserTypes.js'; +import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; +import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/constants.js'; +import { CHAT_CATEGORY } from '../actions/chatActions.js'; +import { IChatWidget } from '../chat.js'; + /** * Action ID for the `Save Prompt` action. From 9463e56124310dfb17991832e5a2073eaa0e7158 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 15:15:44 +0200 Subject: [PATCH 072/236] fixes https://github.com/microsoft/vscode-copilot/issues/12412 (#250843) --- .../browser/chatEditing/chatEditingCodeEditorIntegration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts index 031262ee01d..f8d12d6a5a4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts @@ -339,7 +339,7 @@ export class ChatEditingCodeEditorIntegration implements IModifiedFileEntryEdito // Note, this is a workaround for the `LineRange.isEmpty()` in diffEntry.original being `false` for newly inserted content const isCreatedContent = decorations.length === 1 && decorations[0].range.isEmpty() && diffEntry.original.startLineNumber === 1; - if (!diffEntry.modified.isEmpty && !(isCreatedContent && (diffEntry.modified.endLineNumberExclusive - 1) === editorLineCount)) { + if (!diffEntry.modified.isEmpty) { modifiedVisualDecorations.push({ range: diffEntry.modified.toInclusiveRange()!, options: chatDiffWholeLineAddDecoration From af623e09a15b4c51f65de708835410053e693cc1 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 6 Jun 2025 15:32:24 +0200 Subject: [PATCH 073/236] move prompt codecs and utils to workbench/contrib/chat/common/promptSyntax (#250847) --- .../promptInstructionsWidget.ts | 2 +- .../chatPromptAttachmentModel.ts | 2 +- .../promptSyntax/codecs/base}/asyncDecoder.ts | 2 +- .../promptSyntax/codecs/base}/baseDecoder.ts | 12 ++--- .../promptSyntax/codecs/base}/baseToken.ts | 4 +- .../codecs/base}/compositeToken.ts | 0 .../base}/frontMatterCodec/constants.ts | 2 +- .../frontMatterCodec/frontMatterDecoder.ts | 12 ++--- .../parsers/frontMatterArray.ts | 6 +-- .../frontMatterRecord/frontMatterRecord.ts | 6 +-- .../frontMatterRecordName.ts | 2 +- .../frontMatterRecordNameWithDelimiter.ts | 4 +- .../parsers/frontMatterRecord/index.ts | 0 .../parsers/frontMatterSequence.ts | 0 .../parsers/frontMatterString.ts | 6 +-- .../parsers/frontMatterValue.ts | 2 +- .../tokens/frontMatterArray.ts | 2 +- .../tokens/frontMatterBoolean.ts | 4 +- .../tokens/frontMatterRecord.ts | 4 +- .../tokens/frontMatterSequence.ts | 3 +- .../tokens/frontMatterString.ts | 2 +- .../tokens/frontMatterToken.ts | 0 .../base}/frontMatterCodec/tokens/index.ts | 0 .../codecs/base}/linesCodec/linesDecoder.ts | 10 ++--- .../base}/linesCodec/tokens/carriageReturn.ts | 2 +- .../codecs/base}/linesCodec/tokens/line.ts | 4 +- .../codecs/base}/linesCodec/tokens/newLine.ts | 2 +- .../base}/markdownCodec/markdownDecoder.ts | 6 +-- .../markdownCodec/parsers/markdownComment.ts | 4 +- .../markdownCodec/parsers/markdownImage.ts | 0 .../markdownCodec/parsers/markdownLink.ts | 2 +- .../markdownCodec/tokens/markdownComment.ts | 4 +- .../markdownCodec/tokens/markdownImage.ts | 4 +- .../markdownCodec/tokens/markdownLink.ts | 4 +- .../markdownCodec/tokens/markdownToken.ts | 0 .../markdownExtensionsDecoder.ts | 6 +-- .../parsers/frontMatterHeader.ts | 4 +- .../tokens/frontMatterHeader.ts | 2 +- .../tokens/frontMatterMarker.ts | 2 +- .../tokens/markdownExtensionsToken.ts | 0 .../codecs/base}/simpleCodec/parserBase.ts | 2 +- .../codecs/base}/simpleCodec/simpleDecoder.ts | 8 ++-- .../base}/simpleCodec/tokens/angleBrackets.ts | 0 .../codecs/base}/simpleCodec/tokens/at.ts | 0 .../base}/simpleCodec/tokens/brackets.ts | 0 .../codecs/base}/simpleCodec/tokens/colon.ts | 0 .../codecs/base}/simpleCodec/tokens/comma.ts | 0 .../base}/simpleCodec/tokens/curlyBraces.ts | 0 .../codecs/base}/simpleCodec/tokens/dash.ts | 0 .../base}/simpleCodec/tokens/dollarSign.ts | 0 .../base}/simpleCodec/tokens/doubleQuote.ts | 0 .../simpleCodec/tokens/exclamationMark.ts | 0 .../base}/simpleCodec/tokens/formFeed.ts | 0 .../codecs/base}/simpleCodec/tokens/hash.ts | 0 .../base}/simpleCodec/tokens/parentheses.ts | 0 .../codecs/base}/simpleCodec/tokens/quote.ts | 0 .../base}/simpleCodec/tokens/simpleToken.ts | 2 +- .../codecs/base}/simpleCodec/tokens/slash.ts | 0 .../codecs/base}/simpleCodec/tokens/space.ts | 0 .../codecs/base}/simpleCodec/tokens/tab.ts | 0 .../codecs/base/simpleCodec/tokens/tokens.ts} | 0 .../base}/simpleCodec/tokens/verticalTab.ts | 0 .../codecs/base}/simpleCodec/tokens/word.ts | 2 +- .../promptSyntax/codecs/base}/textToken.ts | 0 .../codecs/base}/utils/objectStream.ts | 9 ++-- .../base}/utils/objectStreamFromTextModel.ts | 6 +-- .../promptSyntax/codecs/chatPromptDecoder.ts | 12 ++--- .../codecs/parsers/promptAtMentionParser.ts | 30 ++++++------- .../parsers/promptSlashCommandParser.ts | 32 +++++++------- .../parsers/promptTemplateVariableParser.ts | 8 ++-- .../codecs/parsers/promptVariableParser.ts | 30 ++++++------- .../codecs/tokens/promptTemplateVariable.ts | 4 +- .../promptSyntax/codecs/tokens/promptToken.ts | 2 +- .../promptContentsProviderBase.ts | 2 +- .../textModelContentsProvider.ts | 2 +- .../decorations/frontMatterDecoration.ts | 4 +- .../frontMatterMarkerDecoration.ts | 2 +- .../decorations/utils/decorationBase.ts | 2 +- .../utils/reactiveDecorationBase.ts | 2 +- .../promptDecorationsProvider.ts | 4 +- .../providers/providerInstanceBase.ts | 2 +- .../providers/providerInstanceManagerBase.ts | 2 +- .../promptSyntax/parsers/basePromptParser.ts | 12 ++--- .../parsers/promptHeader/headerBase.ts | 10 ++--- .../promptHeader/instructionsHeader.ts | 2 +- .../parsers/promptHeader/metadata/applyTo.ts | 2 +- .../promptHeader/metadata/base/enum.ts | 4 +- .../promptHeader/metadata/base/record.ts | 2 +- .../promptHeader/metadata/base/string.ts | 4 +- .../promptHeader/metadata/description.ts | 2 +- .../parsers/promptHeader/metadata/mode.ts | 2 +- .../parsers/promptHeader/metadata/tools.ts | 4 +- .../parsers/promptHeader/promptHeader.ts | 2 +- .../promptSyntax/service/promptsService.ts | 2 +- .../common/promptSyntax/utils}/objectCache.ts | 2 +- .../utils}/observableDisposable.ts | 2 +- .../frontMatterBoolean.test.ts | 12 ++--- .../frontMatterDecoder.test.ts | 26 +++++------ .../frontMatterRecord.test.ts | 10 ++--- .../frontMatterSequence.test.ts | 10 ++--- .../codecs/base}/linesDecoder.test.ts | 20 ++++----- .../codecs/base}/markdownDecoder.test.ts | 44 +++++++++---------- .../codecs/base}/simpleDecoder.test.ts | 18 ++++---- .../codecs/base}/testUtils/randomRange.ts | 6 +-- .../codecs/base}/testUtils/randomTokens.ts | 12 ++--- .../codecs/base}/tokens/baseToken.test.ts | 22 +++++----- .../base}/tokens/compositeToken.test.ts | 14 +++--- .../codecs/base}/tokens/simpleToken.test.ts | 6 +-- .../codecs/base}/utils/objectStream.test.ts | 20 ++++----- .../codecs/base}/utils/testDecoder.ts | 17 +++---- .../codecs/chatPromptCodec.test.ts | 6 +-- .../codecs/chatPromptDecoder.test.ts | 8 ++-- .../codecs/markdownExtensionsDecoder.test.ts | 20 ++++----- .../codecs/tokens/fileReference.test.ts | 2 +- .../codecs/tokens/markdownLink.test.ts | 6 +-- .../filePromptContentsProvider.test.ts | 4 +- .../promptSyntax/promptFileReference.test.ts | 2 +- .../promptSyntax/utils}/objectCache.test.ts | 8 ++-- .../utils}/observableDisposable.test.ts | 10 ++--- .../promptSyntax/utils/treeUtils.test.ts | 6 +-- 120 files changed, 333 insertions(+), 330 deletions(-) rename src/vs/{base/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/asyncDecoder.ts (97%) rename src/vs/{base/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/baseDecoder.ts (95%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/baseToken.ts (96%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/compositeToken.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/constants.ts (90%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/frontMatterDecoder.ts (92%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterArray.ts (96%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts (96%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordName.ts (98%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.ts (97%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterRecord/index.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterSequence.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterString.ts (90%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/parsers/frontMatterValue.ts (99%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/tokens/frontMatterArray.ts (98%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/tokens/frontMatterBoolean.ts (93%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/tokens/frontMatterRecord.ts (97%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/tokens/frontMatterSequence.ts (97%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/tokens/frontMatterString.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/tokens/frontMatterToken.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/frontMatterCodec/tokens/index.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/linesCodec/linesDecoder.ts (95%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/linesCodec/tokens/carriageReturn.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/linesCodec/tokens/line.ts (87%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/linesCodec/tokens/newLine.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/markdownDecoder.ts (95%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/parsers/markdownComment.ts (97%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/parsers/markdownImage.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/parsers/markdownLink.ts (99%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/tokens/markdownComment.ts (87%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/tokens/markdownImage.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/tokens/markdownLink.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownCodec/tokens/markdownToken.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownExtensionsCodec/markdownExtensionsDecoder.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownExtensionsCodec/parsers/frontMatterHeader.ts (98%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownExtensionsCodec/tokens/frontMatterHeader.ts (96%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownExtensionsCodec/tokens/frontMatterMarker.ts (95%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/markdownExtensionsCodec/tokens/markdownExtensionsToken.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/parserBase.ts (98%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/simpleDecoder.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/angleBrackets.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/at.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/brackets.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/colon.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/comma.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/curlyBraces.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/dash.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/dollarSign.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/doubleQuote.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/exclamationMark.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/formFeed.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/hash.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/parentheses.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/quote.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/simpleToken.ts (95%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/slash.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/space.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/tab.ts (100%) rename src/vs/{editor/common/codecs/simpleCodec/tokens/index.ts => workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.ts} (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/verticalTab.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/simpleCodec/tokens/word.ts (94%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/textToken.ts (100%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/utils/objectStream.ts (93%) rename src/vs/{editor/common/codecs => workbench/contrib/chat/common/promptSyntax/codecs/base}/utils/objectStreamFromTextModel.ts (83%) rename src/vs/{base/common => workbench/contrib/chat/common/promptSyntax/utils}/objectCache.ts (98%) rename src/vs/{base/common => workbench/contrib/chat/common/promptSyntax/utils}/observableDisposable.ts (97%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/frontMatterDecoder/frontMatterBoolean.test.ts (91%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/frontMatterDecoder/frontMatterDecoder.test.ts (90%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/frontMatterDecoder/frontMatterRecord.test.ts (91%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/frontMatterDecoder/frontMatterSequence.test.ts (84%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/linesDecoder.test.ts (89%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/markdownDecoder.test.ts (93%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/simpleDecoder.test.ts (90%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/testUtils/randomRange.ts (86%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/testUtils/randomTokens.ts (84%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/tokens/baseToken.test.ts (92%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/tokens/compositeToken.test.ts (91%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/tokens/simpleToken.test.ts (89%) rename src/vs/{editor/test/common/codecs => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/utils/objectStream.test.ts (83%) rename src/vs/{editor/test/common => workbench/contrib/chat/test/common/promptSyntax/codecs/base}/utils/testDecoder.ts (91%) rename src/vs/{base/test/common => workbench/contrib/chat/test/common/promptSyntax/utils}/objectCache.test.ts (96%) rename src/vs/{base/test/common => workbench/contrib/chat/test/common/promptSyntax/utils}/observableDisposable.test.ts (95%) diff --git a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts index f8612294ad9..2282a3f6a4c 100644 --- a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts @@ -21,7 +21,7 @@ import { ILanguageService } from '../../../../../../editor/common/languages/lang import { FileKind, IFileService } from '../../../../../../platform/files/common/files.js'; import { IMenuService, MenuId } from '../../../../../../platform/actions/common/actions.js'; import { getCleanPromptName } from '../../../../../../platform/prompts/common/prompts.js'; -import { ObservableDisposable } from '../../../../../../base/common/observableDisposable.js'; +import { ObservableDisposable } from '../../../common/promptSyntax/utils/observableDisposable.js'; import { IContextKeyService } from '../../../../../../platform/contextkey/common/contextkey.js'; import { ChatPromptAttachmentModel } from '../../chatAttachmentModel/chatPromptAttachmentModel.js'; import { IContextMenuService } from '../../../../../../platform/contextview/browser/contextView.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts index 28b4f61e623..4cfa1311c62 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts @@ -7,7 +7,7 @@ import { URI } from '../../../../../base/common/uri.js'; import { Emitter } from '../../../../../base/common/event.js'; import { PromptParser } from '../../common/promptSyntax/parsers/promptParser.js'; import { BasePromptParser } from '../../common/promptSyntax/parsers/basePromptParser.js'; -import { ObservableDisposable } from '../../../../../base/common/observableDisposable.js'; +import { ObservableDisposable } from '../../common/promptSyntax/utils/observableDisposable.js'; import { IPromptContentsProvider } from '../../common/promptSyntax/contentProviders/types.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; diff --git a/src/vs/base/common/codecs/asyncDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/asyncDecoder.ts similarity index 97% rename from src/vs/base/common/codecs/asyncDecoder.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/asyncDecoder.ts index baf3c6eacf7..be10b50ebba 100644 --- a/src/vs/base/common/codecs/asyncDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/asyncDecoder.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from '../lifecycle.js'; +import { Disposable } from '../../../../../../../base/common/lifecycle.js'; import { BaseDecoder } from './baseDecoder.js'; /** diff --git a/src/vs/base/common/codecs/baseDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/baseDecoder.ts similarity index 95% rename from src/vs/base/common/codecs/baseDecoder.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/baseDecoder.ts index 89e16680383..2d0780e7d7c 100644 --- a/src/vs/base/common/codecs/baseDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/baseDecoder.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter } from '../event.js'; -import { ReadableStream } from '../stream.js'; -import { DeferredPromise } from '../async.js'; +import { Emitter } from '../../../../../../../base/common/event.js'; +import { ReadableStream } from '../../../../../../../base/common/stream.js'; +import { DeferredPromise } from '../../../../../../../base/common/async.js'; import { AsyncDecoder } from './asyncDecoder.js'; -import { assert, assertNever } from '../assert.js'; -import { DisposableMap, IDisposable } from '../lifecycle.js'; -import { ObservableDisposable } from '../observableDisposable.js'; +import { assert, assertNever } from '../../../../../../../base/common/assert.js'; +import { DisposableMap, IDisposable } from '../../../../../../../base/common/lifecycle.js'; +import { ObservableDisposable } from '../../utils/observableDisposable.js'; /** * Event names of {@link ReadableStream} stream. diff --git a/src/vs/editor/common/codecs/baseToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/baseToken.ts similarity index 96% rename from src/vs/editor/common/codecs/baseToken.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/baseToken.ts index 7f4e138bb36..ba81a78738e 100644 --- a/src/vs/editor/common/codecs/baseToken.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/baseToken.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assert } from '../../../base/common/assert.js'; -import { IRange, Range } from '../../../editor/common/core/range.js'; +import { assert } from '../../../../../../../base/common/assert.js'; +import { IRange, Range } from '../../../../../../../editor/common/core/range.js'; /** * Base class for all tokens with a `range` that reflects diff --git a/src/vs/editor/common/codecs/compositeToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/compositeToken.ts similarity index 100% rename from src/vs/editor/common/codecs/compositeToken.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/compositeToken.ts diff --git a/src/vs/editor/common/codecs/frontMatterCodec/constants.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/constants.ts similarity index 90% rename from src/vs/editor/common/codecs/frontMatterCodec/constants.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/constants.ts index c72dddf085c..779e53a1ef1 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/constants.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/constants.ts @@ -5,7 +5,7 @@ import { NewLine } from '../linesCodec/tokens/newLine.js'; import { CarriageReturn } from '../linesCodec/tokens/carriageReturn.js'; -import { FormFeed, SpacingToken } from '../simpleCodec/tokens/index.js'; +import { FormFeed, SpacingToken } from '../simpleCodec/tokens/tokens.js'; /** * List of valid "space" tokens that are valid between different diff --git a/src/vs/editor/common/codecs/frontMatterCodec/frontMatterDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.ts similarity index 92% rename from src/vs/editor/common/codecs/frontMatterCodec/frontMatterDecoder.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.ts index 3eb7369f17b..89a6517e5f9 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/frontMatterDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.ts @@ -3,16 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Word } from '../simpleCodec/tokens/index.js'; -import { ObjectStream } from '../utils/objectStream.js'; -import { assert } from '../../../../base/common/assert.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; +import { Word } from '../simpleCodec/tokens/tokens.js'; +import { assert } from '../../../../../../../../base/common/assert.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; import { VALID_INTER_RECORD_SPACING_TOKENS } from './constants.js'; -import { ReadableStream } from '../../../../base/common/stream.js'; +import { ReadableStream } from '../../../../../../../../base/common/stream.js'; import { FrontMatterToken, FrontMatterRecord } from './tokens/index.js'; -import { BaseDecoder } from '../../../../base/common/codecs/baseDecoder.js'; +import { BaseDecoder } from '../baseDecoder.js'; import { SimpleDecoder, type TSimpleDecoderToken } from '../simpleCodec/simpleDecoder.js'; import { PartialFrontMatterRecord, PartialFrontMatterRecordName, PartialFrontMatterRecordNameWithDelimiter } from './parsers/frontMatterRecord/index.js'; +import { ObjectStream } from '../utils/objectStream.js'; /** * Tokens produced by this decoder. diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterArray.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterArray.ts similarity index 96% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterArray.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterArray.ts index 5e4dcf76678..23e254b3808 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterArray.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterArray.ts @@ -3,15 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assert } from '../../../../../base/common/assert.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; import { PartialFrontMatterValue } from './frontMatterValue.js'; import { FrontMatterArray } from '../tokens/frontMatterArray.js'; -import { assertDefined } from '../../../../../base/common/types.js'; +import { assertDefined } from '../../../../../../../../../base/common/types.js'; import { VALID_INTER_RECORD_SPACING_TOKENS } from '../constants.js'; import { FrontMatterValueToken } from '../tokens/frontMatterToken.js'; import { FrontMatterSequence } from '../tokens/frontMatterSequence.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; -import { Comma, LeftBracket, RightBracket } from '../../simpleCodec/tokens/index.js'; +import { Comma, LeftBracket, RightBracket } from '../../simpleCodec/tokens/tokens.js'; import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../../simpleCodec/parserBase.js'; /** diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts similarity index 96% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts index 64d98b56c95..0db69a34c0e 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts @@ -6,12 +6,12 @@ import { BaseToken } from '../../../baseToken.js'; import { NewLine } from '../../../linesCodec/tokens/newLine.js'; import { PartialFrontMatterValue } from '../frontMatterValue.js'; -import { assertNever } from '../../../../../../base/common/assert.js'; -import { assertDefined } from '../../../../../../base/common/types.js'; +import { assertNever } from '../../../../../../../../../../base/common/assert.js'; +import { assertDefined } from '../../../../../../../../../../base/common/types.js'; import { PartialFrontMatterSequence } from '../frontMatterSequence.js'; import { CarriageReturn } from '../../../linesCodec/tokens/carriageReturn.js'; import { type TSimpleDecoderToken } from '../../../simpleCodec/simpleDecoder.js'; -import { Word, FormFeed, SpacingToken } from '../../../simpleCodec/tokens/index.js'; +import { Word, FormFeed, SpacingToken } from '../../../simpleCodec/tokens/tokens.js'; import { assertNotConsumed, ParserBase, type TAcceptTokenResult } from '../../../simpleCodec/parserBase.js'; import { FrontMatterValueToken, FrontMatterRecordName, FrontMatterRecordDelimiter, FrontMatterRecord } from '../../tokens/index.js'; diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordName.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordName.ts similarity index 98% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordName.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordName.ts index f1cc5afc9e8..b9ab18936ee 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordName.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordName.ts @@ -5,7 +5,7 @@ import { type TSimpleDecoderToken } from '../../../simpleCodec/simpleDecoder.js'; import { FrontMatterRecordName, type TRecordNameToken } from '../../tokens/index.js'; -import { Colon, Word, Dash, SpacingToken } from '../../../simpleCodec/tokens/index.js'; +import { Colon, Word, Dash, SpacingToken } from '../../../simpleCodec/tokens/tokens.js'; import { PartialFrontMatterRecordNameWithDelimiter } from './frontMatterRecordNameWithDelimiter.js'; import { assertNotConsumed, ParserBase, type TAcceptTokenResult } from '../../../simpleCodec/parserBase.js'; diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.ts similarity index 97% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.ts index 6510e249906..21c54f39de8 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assert } from '../../../../../../base/common/assert.js'; +import { assert } from '../../../../../../../../../../base/common/assert.js'; import { PartialFrontMatterRecord } from './frontMatterRecord.js'; -import { Colon, SpacingToken } from '../../../simpleCodec/tokens/index.js'; +import { Colon, SpacingToken } from '../../../simpleCodec/tokens/tokens.js'; import { type TSimpleDecoderToken } from '../../../simpleCodec/simpleDecoder.js'; import { FrontMatterRecordName, FrontMatterRecordDelimiter } from '../../tokens/index.js'; import { assertNotConsumed, ParserBase, type TAcceptTokenResult } from '../../../simpleCodec/parserBase.js'; diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/index.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/index.ts similarity index 100% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterRecord/index.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/index.ts diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterSequence.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterSequence.ts similarity index 100% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterSequence.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterSequence.ts diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterString.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterString.ts similarity index 90% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterString.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterString.ts index 00f8b43301b..d0ed92746d6 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterString.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterString.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assert } from '../../../../../base/common/assert.js'; -import { SimpleToken } from '../../simpleCodec/tokens/index.js'; -import { assertDefined } from '../../../../../base/common/types.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; +import { SimpleToken } from '../../simpleCodec/tokens/tokens.js'; +import { assertDefined } from '../../../../../../../../../base/common/types.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; import { FrontMatterString, type TQuoteToken } from '../tokens/frontMatterString.js'; import { assertNotConsumed, ParserBase, type TAcceptTokenResult } from '../../simpleCodec/parserBase.js'; diff --git a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterValue.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterValue.ts similarity index 99% rename from src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterValue.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterValue.ts index dc39f0ede56..668a757c827 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/parsers/frontMatterValue.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterValue.ts @@ -11,7 +11,7 @@ import { FrontMatterValueToken } from '../tokens/frontMatterToken.js'; import { PartialFrontMatterSequence } from './frontMatterSequence.js'; import { FrontMatterSequence } from '../tokens/frontMatterSequence.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; -import { Word, Quote, DoubleQuote, LeftBracket } from '../../simpleCodec/tokens/index.js'; +import { Word, Quote, DoubleQuote, LeftBracket } from '../../simpleCodec/tokens/tokens.js'; import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../../simpleCodec/parserBase.js'; /** diff --git a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterArray.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterArray.ts similarity index 98% rename from src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterArray.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterArray.ts index 990b1629a8e..b8b01e42c79 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterArray.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterArray.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { BaseToken } from '../../baseToken.js'; -import { LeftBracket, RightBracket } from '../../simpleCodec/tokens/index.js'; +import { LeftBracket, RightBracket } from '../../simpleCodec/tokens/tokens.js'; import { FrontMatterValueToken, type TValueTypeName } from './frontMatterToken.js'; /** diff --git a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterBoolean.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterBoolean.ts similarity index 93% rename from src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterBoolean.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterBoolean.ts index 85e9bf1e1b3..3eae6d114ed 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterBoolean.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterBoolean.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { BaseToken } from '../../baseToken.js'; -import { Word } from '../../simpleCodec/tokens/index.js'; +import { Word } from '../../simpleCodec/tokens/tokens.js'; import { FrontMatterValueToken } from './frontMatterToken.js'; -import { assertDefined } from '../../../../../base/common/types.js'; +import { assertDefined } from '../../../../../../../../../base/common/types.js'; /** * Token that represents a `boolean` value in a Front Matter header. diff --git a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterRecord.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterRecord.ts similarity index 97% rename from src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterRecord.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterRecord.ts index 35f1da245d4..dc498c6d667 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterRecord.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterRecord.ts @@ -5,8 +5,8 @@ import { BaseToken } from '../../baseToken.js'; import { FrontMatterSequence } from './frontMatterSequence.js'; -import { Colon, Word, Dash, SpacingToken } from '../../simpleCodec/tokens/index.js'; -import { FrontMatterToken, FrontMatterValueToken, type TValueTypeName } from '../tokens/frontMatterToken.js'; +import { Colon, Word, Dash, SpacingToken } from '../../simpleCodec/tokens/tokens.js'; +import { FrontMatterToken, FrontMatterValueToken, type TValueTypeName } from './frontMatterToken.js'; /** * Type for tokens that can be used inside a record name. diff --git a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterSequence.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterSequence.ts similarity index 97% rename from src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterSequence.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterSequence.ts index 3a1f1607ac7..dcb6f70d5a3 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterSequence.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterSequence.ts @@ -5,9 +5,10 @@ import { BaseToken } from '../../baseToken.js'; import { FrontMatterValueToken } from './frontMatterToken.js'; -import { Word, SpacingToken } from '../../simpleCodec/tokens/index.js'; +import { Word, SpacingToken } from '../../simpleCodec/tokens/tokens.js'; import { type TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; + /** * Token represents a generic sequence of tokens in a Front Matter header. */ diff --git a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterString.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterString.ts similarity index 94% rename from src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterString.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterString.ts index f7f18666d66..8a7283d1098 100644 --- a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterString.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterString.ts @@ -5,7 +5,7 @@ import { BaseToken } from '../../baseToken.js'; import { FrontMatterValueToken } from './frontMatterToken.js'; -import { Quote, DoubleQuote } from '../../simpleCodec/tokens/index.js'; +import { Quote, DoubleQuote } from '../../simpleCodec/tokens/tokens.js'; /** * Type for any quote token that can be used to wrap a string. diff --git a/src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterToken.ts similarity index 100% rename from src/vs/editor/common/codecs/frontMatterCodec/tokens/frontMatterToken.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterToken.ts diff --git a/src/vs/editor/common/codecs/frontMatterCodec/tokens/index.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/index.ts similarity index 100% rename from src/vs/editor/common/codecs/frontMatterCodec/tokens/index.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/tokens/index.ts diff --git a/src/vs/editor/common/codecs/linesCodec/linesDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/linesDecoder.ts similarity index 95% rename from src/vs/editor/common/codecs/linesCodec/linesDecoder.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/linesDecoder.ts index 67ce2286028..5d9ad249d6f 100644 --- a/src/vs/editor/common/codecs/linesCodec/linesDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/linesDecoder.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { Line } from './tokens/line.js'; -import { Range } from '../../core/range.js'; +import { Range } from '../../../../../../../../editor/common/core/range.js'; import { NewLine } from './tokens/newLine.js'; -import { assert } from '../../../../base/common/assert.js'; +import { assert } from '../../../../../../../../base/common/assert.js'; import { CarriageReturn } from './tokens/carriageReturn.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { assertDefined } from '../../../../base/common/types.js'; -import { BaseDecoder } from '../../../../base/common/codecs/baseDecoder.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; +import { assertDefined } from '../../../../../../../../base/common/types.js'; +import { BaseDecoder } from '../baseDecoder.js'; /** * Any line break token type. diff --git a/src/vs/editor/common/codecs/linesCodec/tokens/carriageReturn.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.ts similarity index 94% rename from src/vs/editor/common/codecs/linesCodec/tokens/carriageReturn.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.ts index c1406b4f65b..46b3031829e 100644 --- a/src/vs/editor/common/codecs/linesCodec/tokens/carriageReturn.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { VSBuffer } from '../../../../../base/common/buffer.js'; +import { VSBuffer } from '../../../../../../../../../base/common/buffer.js'; import { SimpleToken } from '../../simpleCodec/tokens/simpleToken.js'; /** diff --git a/src/vs/editor/common/codecs/linesCodec/tokens/line.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/line.ts similarity index 87% rename from src/vs/editor/common/codecs/linesCodec/tokens/line.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/line.ts index c6be218b126..2fa0afef6ff 100644 --- a/src/vs/editor/common/codecs/linesCodec/tokens/line.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/line.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { BaseToken } from '../../baseToken.js'; -import { assert } from '../../../../../base/common/assert.js'; -import { Range } from '../../../../../editor/common/core/range.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; /** * Token representing a line of text with a `range` which diff --git a/src/vs/editor/common/codecs/linesCodec/tokens/newLine.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/newLine.ts similarity index 94% rename from src/vs/editor/common/codecs/linesCodec/tokens/newLine.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/newLine.ts index 1548e90a1b2..6d95751721d 100644 --- a/src/vs/editor/common/codecs/linesCodec/tokens/newLine.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/linesCodec/tokens/newLine.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { VSBuffer } from '../../../../../base/common/buffer.js'; +import { VSBuffer } from '../../../../../../../../../base/common/buffer.js'; import { SimpleToken } from '../../simpleCodec/tokens/simpleToken.js'; /** diff --git a/src/vs/editor/common/codecs/markdownCodec/markdownDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/markdownDecoder.ts similarity index 95% rename from src/vs/editor/common/codecs/markdownCodec/markdownDecoder.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/markdownDecoder.ts index bf98444794d..67bbda1f2ec 100644 --- a/src/vs/editor/common/codecs/markdownCodec/markdownDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/markdownDecoder.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { MarkdownToken } from './tokens/markdownToken.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; import { LeftBracket } from '../simpleCodec/tokens/brackets.js'; import { PartialMarkdownImage } from './parsers/markdownImage.js'; -import { ReadableStream } from '../../../../base/common/stream.js'; +import { ReadableStream } from '../../../../../../../../base/common/stream.js'; import { TSimpleDecoderToken } from '../simpleCodec/simpleDecoder.js'; import { LeftAngleBracket } from '../simpleCodec/tokens/angleBrackets.js'; import { ExclamationMark } from '../simpleCodec/tokens/exclamationMark.js'; -import { BaseDecoder } from '../../../../base/common/codecs/baseDecoder.js'; +import { BaseDecoder } from '../baseDecoder.js'; import { MarkdownCommentStart, PartialMarkdownCommentStart } from './parsers/markdownComment.js'; import { MarkdownExtensionsDecoder } from '../markdownExtensionsCodec/markdownExtensionsDecoder.js'; import { MarkdownLinkCaption, PartialMarkdownLink, PartialMarkdownLinkCaption } from './parsers/markdownLink.js'; diff --git a/src/vs/editor/common/codecs/markdownCodec/parsers/markdownComment.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownComment.ts similarity index 97% rename from src/vs/editor/common/codecs/markdownCodec/parsers/markdownComment.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownComment.ts index 04697569d8e..a017649f8b8 100644 --- a/src/vs/editor/common/codecs/markdownCodec/parsers/markdownComment.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownComment.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Range } from '../../../core/range.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; import { BaseToken } from '../../baseToken.js'; import { Dash } from '../../simpleCodec/tokens/dash.js'; -import { assert } from '../../../../../base/common/assert.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; import { MarkdownComment } from '../tokens/markdownComment.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; import { ExclamationMark } from '../../simpleCodec/tokens/exclamationMark.js'; diff --git a/src/vs/editor/common/codecs/markdownCodec/parsers/markdownImage.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownImage.ts similarity index 100% rename from src/vs/editor/common/codecs/markdownCodec/parsers/markdownImage.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownImage.ts diff --git a/src/vs/editor/common/codecs/markdownCodec/parsers/markdownLink.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownLink.ts similarity index 99% rename from src/vs/editor/common/codecs/markdownCodec/parsers/markdownLink.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownLink.ts index bff174f097c..641ddd14b9b 100644 --- a/src/vs/editor/common/codecs/markdownCodec/parsers/markdownLink.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/parsers/markdownLink.ts @@ -6,7 +6,7 @@ import { BaseToken } from '../../baseToken.js'; import { MarkdownLink } from '../tokens/markdownLink.js'; import { NewLine } from '../../linesCodec/tokens/newLine.js'; -import { assert } from '../../../../../base/common/assert.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; import { FormFeed } from '../../simpleCodec/tokens/formFeed.js'; import { VerticalTab } from '../../simpleCodec/tokens/verticalTab.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; diff --git a/src/vs/editor/common/codecs/markdownCodec/tokens/markdownComment.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownComment.ts similarity index 87% rename from src/vs/editor/common/codecs/markdownCodec/tokens/markdownComment.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownComment.ts index 4a2e8b062ff..8eadff3589a 100644 --- a/src/vs/editor/common/codecs/markdownCodec/tokens/markdownComment.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownComment.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Range } from '../../../core/range.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; import { MarkdownToken } from './markdownToken.js'; -import { assert } from '../../../../../base/common/assert.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; /** * A token that represent a `markdown comment` with a `range`. The `range` diff --git a/src/vs/editor/common/codecs/markdownCodec/tokens/markdownImage.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownImage.ts similarity index 94% rename from src/vs/editor/common/codecs/markdownCodec/tokens/markdownImage.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownImage.ts index 1feb79711e1..cab120f53db 100644 --- a/src/vs/editor/common/codecs/markdownCodec/tokens/markdownImage.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownImage.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { MarkdownToken } from './markdownToken.js'; -import { IRange, Range } from '../../../core/range.js'; -import { assert } from '../../../../../base/common/assert.js'; +import { IRange, Range } from '../../../../../../../../../editor/common/core/range.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; /** * A token that represent a `markdown image` with a `range`. The `range` diff --git a/src/vs/editor/common/codecs/markdownCodec/tokens/markdownLink.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.ts similarity index 94% rename from src/vs/editor/common/codecs/markdownCodec/tokens/markdownLink.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.ts index 977cc44533b..a963628675d 100644 --- a/src/vs/editor/common/codecs/markdownCodec/tokens/markdownLink.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { MarkdownToken } from './markdownToken.js'; -import { IRange, Range } from '../../../core/range.js'; -import { assert } from '../../../../../base/common/assert.js'; +import { IRange, Range } from '../../../../../../../../../editor/common/core/range.js'; +import { assert } from '../../../../../../../../../base/common/assert.js'; /** * A token that represent a `markdown link` with a `range`. The `range` diff --git a/src/vs/editor/common/codecs/markdownCodec/tokens/markdownToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownToken.ts similarity index 100% rename from src/vs/editor/common/codecs/markdownCodec/tokens/markdownToken.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownCodec/tokens/markdownToken.ts diff --git a/src/vs/editor/common/codecs/markdownExtensionsCodec/markdownExtensionsDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/markdownExtensionsDecoder.ts similarity index 94% rename from src/vs/editor/common/codecs/markdownExtensionsCodec/markdownExtensionsDecoder.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/markdownExtensionsDecoder.ts index 7d52e5aa7b3..b5ff3d2b9f9 100644 --- a/src/vs/editor/common/codecs/markdownExtensionsCodec/markdownExtensionsDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/markdownExtensionsDecoder.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { ReadableStream } from '../../../../base/common/stream.js'; -import { BaseDecoder } from '../../../../base/common/codecs/baseDecoder.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; +import { ReadableStream } from '../../../../../../../../base/common/stream.js'; +import { BaseDecoder } from '../baseDecoder.js'; import { MarkdownExtensionsToken } from './tokens/markdownExtensionsToken.js'; import { SimpleDecoder, TSimpleDecoderToken } from '../simpleCodec/simpleDecoder.js'; import { PartialFrontMatterHeader, PartialFrontMatterStartMarker } from './parsers/frontMatterHeader.js'; diff --git a/src/vs/editor/common/codecs/markdownExtensionsCodec/parsers/frontMatterHeader.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/parsers/frontMatterHeader.ts similarity index 98% rename from src/vs/editor/common/codecs/markdownExtensionsCodec/parsers/frontMatterHeader.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/parsers/frontMatterHeader.ts index 589aec9d63d..a63c911174c 100644 --- a/src/vs/editor/common/codecs/markdownExtensionsCodec/parsers/frontMatterHeader.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/parsers/frontMatterHeader.ts @@ -6,9 +6,9 @@ import { Dash } from '../../simpleCodec/tokens/dash.js'; import { NewLine } from '../../linesCodec/tokens/newLine.js'; import { FrontMatterHeader } from '../tokens/frontMatterHeader.js'; -import { assertDefined } from '../../../../../base/common/types.js'; +import { assertDefined } from '../../../../../../../../../base/common/types.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; -import { assert, assertNever } from '../../../../../base/common/assert.js'; +import { assert, assertNever } from '../../../../../../../../../base/common/assert.js'; import { CarriageReturn } from '../../linesCodec/tokens/carriageReturn.js'; import { FrontMatterMarker, TMarkerToken } from '../tokens/frontMatterMarker.js'; import { assertNotConsumed, IAcceptTokenSuccess, ParserBase, TAcceptTokenResult } from '../../simpleCodec/parserBase.js'; diff --git a/src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.ts similarity index 96% rename from src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.ts index 7451d66bcae..b5b3903b20a 100644 --- a/src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Text } from '../../textToken.js'; -import { Range } from '../../../core/range.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; import { BaseToken } from '../../baseToken.js'; import { MarkdownExtensionsToken } from './markdownExtensionsToken.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; diff --git a/src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterMarker.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterMarker.ts similarity index 95% rename from src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterMarker.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterMarker.ts index 3c65b1d661b..14813b3116b 100644 --- a/src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterMarker.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterMarker.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Range } from '../../../core/range.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; import { BaseToken } from '../../baseToken.js'; import { Dash } from '../../simpleCodec/tokens/dash.js'; import { NewLine } from '../../linesCodec/tokens/newLine.js'; diff --git a/src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/markdownExtensionsToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/markdownExtensionsToken.ts similarity index 100% rename from src/vs/editor/common/codecs/markdownExtensionsCodec/tokens/markdownExtensionsToken.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/markdownExtensionsToken.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/parserBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/parserBase.ts similarity index 98% rename from src/vs/editor/common/codecs/simpleCodec/parserBase.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/parserBase.ts index 3df13577159..84515dc1d6c 100644 --- a/src/vs/editor/common/codecs/simpleCodec/parserBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/parserBase.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { BaseToken } from '../baseToken.js'; -import { assert } from '../../../../base/common/assert.js'; +import { assert } from '../../../../../../../../base/common/assert.js'; /** * Common interface for a result of accepting a next token diff --git a/src/vs/editor/common/codecs/simpleCodec/simpleDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/simpleDecoder.ts similarity index 94% rename from src/vs/editor/common/codecs/simpleCodec/simpleDecoder.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/simpleDecoder.ts index aad7e03586f..9addf4df2ca 100644 --- a/src/vs/editor/common/codecs/simpleCodec/simpleDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/simpleDecoder.ts @@ -4,10 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { NewLine } from '../linesCodec/tokens/newLine.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { ReadableStream } from '../../../../base/common/stream.js'; import { CarriageReturn } from '../linesCodec/tokens/carriageReturn.js'; -import { BaseDecoder } from '../../../../base/common/codecs/baseDecoder.js'; import { LinesDecoder, TLineBreakToken, TLineToken } from '../linesCodec/linesDecoder.js'; import { At, @@ -37,8 +34,11 @@ import { type TAngleBracket, LeftAngleBracket, RightAngleBracket, -} from './tokens/index.js'; +} from './tokens/tokens.js'; import { ISimpleTokenClass, SimpleToken } from './tokens/simpleToken.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; +import { BaseDecoder } from '../baseDecoder.js'; +import { ReadableStream } from '../../../../../../../../base/common/stream.js'; /** * Type for all simple tokens. diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/angleBrackets.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/angleBrackets.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/angleBrackets.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/angleBrackets.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/at.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/at.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/at.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/at.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/brackets.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/brackets.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/brackets.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/brackets.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/colon.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/colon.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/colon.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/colon.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/comma.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/comma.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/comma.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/comma.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/curlyBraces.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/curlyBraces.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/curlyBraces.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/curlyBraces.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/dash.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/dash.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/dash.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/dash.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/dollarSign.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/dollarSign.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/dollarSign.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/dollarSign.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/doubleQuote.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/doubleQuote.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/doubleQuote.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/doubleQuote.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/exclamationMark.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/exclamationMark.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/exclamationMark.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/exclamationMark.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/formFeed.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/formFeed.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/formFeed.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/formFeed.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/hash.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/hash.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/hash.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/hash.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/parentheses.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/parentheses.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/parentheses.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/parentheses.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/quote.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/quote.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/quote.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/quote.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/simpleToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/simpleToken.ts similarity index 95% rename from src/vs/editor/common/codecs/simpleCodec/tokens/simpleToken.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/simpleToken.ts index dddd8b5a96f..5a611bb1ddd 100644 --- a/src/vs/editor/common/codecs/simpleCodec/tokens/simpleToken.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/simpleToken.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Range } from '../../../core/range.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; import { BaseToken } from '../../baseToken.js'; import { Line } from '../../linesCodec/tokens/line.js'; diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/slash.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/slash.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/slash.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/slash.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/space.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/space.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/space.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/space.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/tab.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/tab.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/tab.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/tab.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/index.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/index.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/verticalTab.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/verticalTab.ts similarity index 100% rename from src/vs/editor/common/codecs/simpleCodec/tokens/verticalTab.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/verticalTab.ts diff --git a/src/vs/editor/common/codecs/simpleCodec/tokens/word.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/word.ts similarity index 94% rename from src/vs/editor/common/codecs/simpleCodec/tokens/word.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/word.ts index 1629b38db47..bea656895fc 100644 --- a/src/vs/editor/common/codecs/simpleCodec/tokens/word.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/simpleCodec/tokens/word.ts @@ -5,7 +5,7 @@ import { BaseToken } from '../../baseToken.js'; import { Line } from '../../linesCodec/tokens/line.js'; -import { Range } from '../../../../../editor/common/core/range.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; /** * A token that represent a word - a set of continuous diff --git a/src/vs/editor/common/codecs/textToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/textToken.ts similarity index 100% rename from src/vs/editor/common/codecs/textToken.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/textToken.ts diff --git a/src/vs/editor/common/codecs/utils/objectStream.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStream.ts similarity index 93% rename from src/vs/editor/common/codecs/utils/objectStream.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStream.ts index 3d88b36a167..97d4460b67c 100644 --- a/src/vs/editor/common/codecs/utils/objectStream.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStream.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assertNever } from '../../../../base/common/assert.js'; -import { CancellationToken } from '../../../../base/common/cancellation.js'; -import { ObservableDisposable } from '../../../../base/common/observableDisposable.js'; -import { newWriteableStream, WriteableStream, ReadableStream } from '../../../../base/common/stream.js'; +import { assertNever } from '../../../../../../../../base/common/assert.js'; +import { CancellationToken } from '../../../../../../../../base/common/cancellation.js'; +import { ObservableDisposable } from '../../../utils/observableDisposable.js'; +import { newWriteableStream, ReadableStream, WriteableStream } from '../../../../../../../../base/common/stream.js'; + /** * A readable stream of provided objects. diff --git a/src/vs/editor/common/codecs/utils/objectStreamFromTextModel.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.ts similarity index 83% rename from src/vs/editor/common/codecs/utils/objectStreamFromTextModel.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.ts index e92bc936aea..d6083071c5f 100644 --- a/src/vs/editor/common/codecs/utils/objectStreamFromTextModel.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITextModel } from '../../model.js'; +import { ITextModel } from '../../../../../../../../editor/common/model.js'; import { ObjectStream } from './objectStream.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { CancellationToken } from '../../../../base/common/cancellation.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; +import { CancellationToken } from '../../../../../../../../base/common/cancellation.js'; /** * Create new instance of the stream from a provided text model. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/chatPromptDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/chatPromptDecoder.ts index 85f62beb086..5ac4a138fbe 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/chatPromptDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/chatPromptDecoder.ts @@ -12,14 +12,14 @@ import { PartialPromptAtMention } from './parsers/promptAtMentionParser.js'; import { PromptTemplateVariable } from './tokens/promptTemplateVariable.js'; import { assert, assertNever } from '../../../../../../base/common/assert.js'; import { PartialPromptSlashCommand } from './parsers/promptSlashCommandParser.js'; -import { BaseDecoder } from '../../../../../../base/common/codecs/baseDecoder.js'; +import { BaseDecoder } from './base/baseDecoder.js'; import { PromptVariable, PromptVariableWithData } from './tokens/promptVariable.js'; -import { At } from '../../../../../../editor/common/codecs/simpleCodec/tokens/at.js'; -import { Hash } from '../../../../../../editor/common/codecs/simpleCodec/tokens/hash.js'; -import { Slash } from '../../../../../../editor/common/codecs/simpleCodec/tokens/slash.js'; -import { DollarSign } from '../../../../../../editor/common/codecs/simpleCodec/tokens/dollarSign.js'; +import { At } from './base/simpleCodec/tokens/at.js'; +import { Hash } from './base/simpleCodec/tokens/hash.js'; +import { Slash } from './base/simpleCodec/tokens/slash.js'; +import { DollarSign } from './base/simpleCodec/tokens/dollarSign.js'; import { PartialPromptVariableName, PartialPromptVariableWithData } from './parsers/promptVariableParser.js'; -import { MarkdownDecoder, TMarkdownToken } from '../../../../../../editor/common/codecs/markdownCodec/markdownDecoder.js'; +import { MarkdownDecoder, TMarkdownToken } from './base/markdownCodec/markdownDecoder.js'; import { PartialPromptTemplateVariable, PartialPromptTemplateVariableStart, TPromptTemplateVariableParser } from './parsers/promptTemplateVariableParser.js'; /** diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptAtMentionParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptAtMentionParser.ts index dad221df7f6..2173ba438ad 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptAtMentionParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptAtMentionParser.ts @@ -6,21 +6,21 @@ import { PromptAtMention } from '../tokens/promptAtMention.js'; import { assert } from '../../../../../../../base/common/assert.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; -import { BaseToken } from '../../../../../../../editor/common/codecs/baseToken.js'; -import { At } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/at.js'; -import { Tab } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/tab.js'; -import { Hash } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/hash.js'; -import { Space } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/space.js'; -import { Colon } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/colon.js'; -import { NewLine } from '../../../../../../../editor/common/codecs/linesCodec/tokens/newLine.js'; -import { FormFeed } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/formFeed.js'; -import { VerticalTab } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/verticalTab.js'; -import { TSimpleDecoderToken } from '../../../../../../../editor/common/codecs/simpleCodec/simpleDecoder.js'; -import { CarriageReturn } from '../../../../../../../editor/common/codecs/linesCodec/tokens/carriageReturn.js'; -import { ExclamationMark } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/exclamationMark.js'; -import { LeftBracket, RightBracket } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/brackets.js'; -import { LeftAngleBracket, RightAngleBracket } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/angleBrackets.js'; -import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../../../../../../../editor/common/codecs/simpleCodec/parserBase.js'; +import { BaseToken } from '../base/baseToken.js'; +import { At } from '../base/simpleCodec/tokens/at.js'; +import { Tab } from '../base/simpleCodec/tokens/tab.js'; +import { Hash } from '../base/simpleCodec/tokens/hash.js'; +import { Space } from '../base/simpleCodec/tokens/space.js'; +import { Colon } from '../base/simpleCodec/tokens/colon.js'; +import { NewLine } from '../base/linesCodec/tokens/newLine.js'; +import { FormFeed } from '../base/simpleCodec/tokens/formFeed.js'; +import { VerticalTab } from '../base/simpleCodec/tokens/verticalTab.js'; +import { TSimpleDecoderToken } from '../base/simpleCodec/simpleDecoder.js'; +import { CarriageReturn } from '../base/linesCodec/tokens/carriageReturn.js'; +import { ExclamationMark } from '../base/simpleCodec/tokens/exclamationMark.js'; +import { LeftBracket, RightBracket } from '../base/simpleCodec/tokens/brackets.js'; +import { LeftAngleBracket, RightAngleBracket } from '../base/simpleCodec/tokens/angleBrackets.js'; +import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../base/simpleCodec/parserBase.js'; /** * List of characters that terminate the prompt at-mention sequence. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptSlashCommandParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptSlashCommandParser.ts index ebd3f9a096c..557f5e74379 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptSlashCommandParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptSlashCommandParser.ts @@ -6,22 +6,22 @@ import { assert } from '../../../../../../../base/common/assert.js'; import { PromptSlashCommand } from '../tokens/promptSlashCommand.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; -import { BaseToken } from '../../../../../../../editor/common/codecs/baseToken.js'; -import { At } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/at.js'; -import { Tab } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/tab.js'; -import { Hash } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/hash.js'; -import { Slash } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/slash.js'; -import { Space } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/space.js'; -import { Colon } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/colon.js'; -import { NewLine } from '../../../../../../../editor/common/codecs/linesCodec/tokens/newLine.js'; -import { FormFeed } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/formFeed.js'; -import { VerticalTab } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/verticalTab.js'; -import { TSimpleDecoderToken } from '../../../../../../../editor/common/codecs/simpleCodec/simpleDecoder.js'; -import { CarriageReturn } from '../../../../../../../editor/common/codecs/linesCodec/tokens/carriageReturn.js'; -import { ExclamationMark } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/exclamationMark.js'; -import { LeftBracket, RightBracket } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/brackets.js'; -import { LeftAngleBracket, RightAngleBracket } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/angleBrackets.js'; -import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../../../../../../../editor/common/codecs/simpleCodec/parserBase.js'; +import { BaseToken } from '../base/baseToken.js'; +import { At } from '../base/simpleCodec/tokens/at.js'; +import { Tab } from '../base/simpleCodec/tokens/tab.js'; +import { Hash } from '../base/simpleCodec/tokens/hash.js'; +import { Slash } from '../base/simpleCodec/tokens/slash.js'; +import { Space } from '../base/simpleCodec/tokens/space.js'; +import { Colon } from '../base/simpleCodec/tokens/colon.js'; +import { NewLine } from '../base/linesCodec/tokens/newLine.js'; +import { FormFeed } from '../base/simpleCodec/tokens/formFeed.js'; +import { VerticalTab } from '../base/simpleCodec/tokens/verticalTab.js'; +import { TSimpleDecoderToken } from '../base/simpleCodec/simpleDecoder.js'; +import { CarriageReturn } from '../base/linesCodec/tokens/carriageReturn.js'; +import { ExclamationMark } from '../base/simpleCodec/tokens/exclamationMark.js'; +import { LeftBracket, RightBracket } from '../base/simpleCodec/tokens/brackets.js'; +import { LeftAngleBracket, RightAngleBracket } from '../base/simpleCodec/tokens/angleBrackets.js'; +import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../base/simpleCodec/parserBase.js'; /** * List of characters that terminate the prompt at-mention sequence. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptTemplateVariableParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptTemplateVariableParser.ts index c40a8c5622f..b97ad0fd479 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptTemplateVariableParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptTemplateVariableParser.ts @@ -5,10 +5,10 @@ import { assert } from '../../../../../../../base/common/assert.js'; import { PromptTemplateVariable } from '../tokens/promptTemplateVariable.js'; -import { BaseToken } from '../../../../../../../editor/common/codecs/baseToken.js'; -import { TSimpleDecoderToken } from '../../../../../../../editor/common/codecs/simpleCodec/simpleDecoder.js'; -import { DollarSign, LeftCurlyBrace, RightCurlyBrace } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/index.js'; -import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../../../../../../../editor/common/codecs/simpleCodec/parserBase.js'; +import { BaseToken } from '../base/baseToken.js'; +import { TSimpleDecoderToken } from '../base/simpleCodec/simpleDecoder.js'; +import { DollarSign, LeftCurlyBrace, RightCurlyBrace } from '../base/simpleCodec/tokens/tokens.js'; +import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../base/simpleCodec/parserBase.js'; /** * Parsers of the `${variable}` token sequence in a prompt text. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptVariableParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptVariableParser.ts index 376f251b2ff..ef68e78ec2d 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptVariableParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/parsers/promptVariableParser.ts @@ -5,22 +5,22 @@ import { assert } from '../../../../../../../base/common/assert.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; -import { BaseToken } from '../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../base/baseToken.js'; import { PromptVariable, PromptVariableWithData } from '../tokens/promptVariable.js'; -import { At } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/at.js'; -import { Tab } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/tab.js'; -import { Hash } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/hash.js'; -import { Space } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/space.js'; -import { Colon } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/colon.js'; -import { NewLine } from '../../../../../../../editor/common/codecs/linesCodec/tokens/newLine.js'; -import { FormFeed } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/formFeed.js'; -import { VerticalTab } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/verticalTab.js'; -import { TSimpleDecoderToken } from '../../../../../../../editor/common/codecs/simpleCodec/simpleDecoder.js'; -import { CarriageReturn } from '../../../../../../../editor/common/codecs/linesCodec/tokens/carriageReturn.js'; -import { ExclamationMark } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/exclamationMark.js'; -import { LeftBracket, RightBracket } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/brackets.js'; -import { LeftAngleBracket, RightAngleBracket } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/angleBrackets.js'; -import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../../../../../../../editor/common/codecs/simpleCodec/parserBase.js'; +import { At } from '../base/simpleCodec/tokens/at.js'; +import { Tab } from '../base/simpleCodec/tokens/tab.js'; +import { Hash } from '../base/simpleCodec/tokens/hash.js'; +import { Space } from '../base/simpleCodec/tokens/space.js'; +import { Colon } from '../base/simpleCodec/tokens/colon.js'; +import { NewLine } from '../base/linesCodec/tokens/newLine.js'; +import { FormFeed } from '../base/simpleCodec/tokens/formFeed.js'; +import { VerticalTab } from '../base/simpleCodec/tokens/verticalTab.js'; +import { TSimpleDecoderToken } from '../base/simpleCodec/simpleDecoder.js'; +import { CarriageReturn } from '../base/linesCodec/tokens/carriageReturn.js'; +import { ExclamationMark } from '../base/simpleCodec/tokens/exclamationMark.js'; +import { LeftBracket, RightBracket } from '../base/simpleCodec/tokens/brackets.js'; +import { LeftAngleBracket, RightAngleBracket } from '../base/simpleCodec/tokens/angleBrackets.js'; +import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../base/simpleCodec/parserBase.js'; /** * List of characters that terminate the prompt variable sequence. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptTemplateVariable.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptTemplateVariable.ts index a50642ef526..be3051f2c88 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptTemplateVariable.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptTemplateVariable.ts @@ -5,8 +5,8 @@ import { PromptToken } from './promptToken.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; -import { DollarSign } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/dollarSign.js'; -import { LeftCurlyBrace, RightCurlyBrace } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/curlyBraces.js'; +import { DollarSign } from '../base/simpleCodec/tokens/dollarSign.js'; +import { LeftCurlyBrace, RightCurlyBrace } from '../base/simpleCodec/tokens/curlyBraces.js'; /** * Represents a `${variable}` token in a prompt text. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptToken.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptToken.ts index 38a9d69d5ac..021b8d5a425 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptToken.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptToken.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { BaseToken } from '../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../base/baseToken.js'; /** * Common base token that all chatbot `prompt` tokens should inherit from. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts index 0a67109dcec..b34815a0e7d 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts @@ -11,7 +11,7 @@ import { CancellationError } from '../../../../../../base/common/errors.js'; import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { ObservableDisposable } from '../../../../../../base/common/observableDisposable.js'; +import { ObservableDisposable } from '../utils/observableDisposable.js'; import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../constants.js'; import { FailedToResolveContentsStream, ResolveError } from '../../promptFileReferenceErrors.js'; import { cancelPreviousCalls } from '../../../../../../base/common/decorators/cancelPreviousCalls.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts index 47f4ae66330..fcc277f99ea 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts @@ -13,7 +13,7 @@ import { CancellationToken } from '../../../../../../base/common/cancellation.js import { IModelContentChangedEvent } from '../../../../../../editor/common/textModelEvents.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { IPromptContentsProviderOptions, PromptContentsProviderBase } from './promptContentsProviderBase.js'; -import { objectStreamFromTextModel } from '../../../../../../editor/common/codecs/utils/objectStreamFromTextModel.js'; +import { objectStreamFromTextModel } from '../codecs/base/utils/objectStreamFromTextModel.js'; /** * Prompt contents provider for a {@link ITextModel} instance. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterDecoration.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterDecoration.ts index 23ec581b6b8..3ccfec56ba0 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterDecoration.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterDecoration.ts @@ -7,11 +7,11 @@ import { CssClassModifiers } from '../types.js'; import { localize } from '../../../../../../../../../../nls.js'; import { FrontMatterMarkerDecoration } from './frontMatterMarkerDecoration.js'; import { Position } from '../../../../../../../../../../editor/common/core/position.js'; -import { BaseToken } from '../../../../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../../../../../codecs/base/baseToken.js'; import { contrastBorder, editorBackground } from '../../../../../../../../../../platform/theme/common/colorRegistry.js'; import { ColorIdentifier, darken, registerColor } from '../../../../../../../../../../platform/theme/common/colorUtils.js'; import { TAddAccessor, TDecorationStyles, ReactiveDecorationBase, asCssVariable, IReactiveDecorationClassNames } from './utils/index.js'; -import { FrontMatterHeader } from '../../../../../../../../../../editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { FrontMatterHeader } from '../../../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; /** * Decoration CSS class names. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterMarkerDecoration.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterMarkerDecoration.ts index 70e82996729..bde8c4bbafd 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterMarkerDecoration.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterMarkerDecoration.ts @@ -5,7 +5,7 @@ import { CssClassModifiers } from '../types.js'; import { TDecorationStyles, ReactiveDecorationBase, IReactiveDecorationClassNames } from './utils/index.js'; -import { FrontMatterMarker } from '../../../../../../../../../../editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterMarker.js'; +import { FrontMatterMarker } from '../../../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterMarker.js'; /** * Decoration CSS class names. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/decorationBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/decorationBase.ts index 614a22a7ce9..6f375c8cba4 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/decorationBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/decorationBase.ts @@ -5,7 +5,7 @@ import { Range } from '../../../../../../../../../../../editor/common/core/range.js'; import { IMarkdownString } from '../../../../../../../../../../../base/common/htmlContent.js'; -import { BaseToken } from '../../../../../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../../../../../../codecs/base/baseToken.js'; import { TrackedRangeStickiness } from '../../../../../../../../../../../editor/common/model.js'; import type { TAddAccessor, TChangeAccessor, TDecorationStyles, TRemoveAccessor } from './types.js'; import { ModelDecorationOptions } from '../../../../../../../../../../../editor/common/model/textModel.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/reactiveDecorationBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/reactiveDecorationBase.ts index c354526150c..e27e80a46a3 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/reactiveDecorationBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/reactiveDecorationBase.ts @@ -5,7 +5,7 @@ import { DecorationBase } from './decorationBase.js'; import { Position } from '../../../../../../../../../../../editor/common/core/position.js'; -import { BaseToken } from '../../../../../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../../../../../../codecs/base/baseToken.js'; import type { IReactiveDecorationClassNames, TAddAccessor, TChangeAccessor, TRemoveAccessor } from './types.js'; /** diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/promptDecorationsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/promptDecorationsProvider.ts index ef367348515..e8e55dc534b 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/promptDecorationsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/promptDecorationsProvider.ts @@ -9,11 +9,11 @@ import { ITextModel } from '../../../../../../../../../editor/common/model.js'; import { FrontMatterDecoration } from './decorations/frontMatterDecoration.js'; import { toDisposable } from '../../../../../../../../../base/common/lifecycle.js'; import { Position } from '../../../../../../../../../editor/common/core/position.js'; -import { BaseToken } from '../../../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../../../../codecs/base/baseToken.js'; import { ProviderInstanceManagerBase, TProviderClass } from '../providerInstanceManagerBase.js'; import { registerThemingParticipant } from '../../../../../../../../../platform/theme/common/themeService.js'; import { DecorationBase, ReactiveDecorationBase, type TDecorationClass, type TChangedDecorator } from './decorations/utils/index.js'; -import { FrontMatterHeader } from '../../../../../../../../../editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { FrontMatterHeader } from '../../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; /** * Prompt tokens that are decorated by this provider. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceBase.ts index 52f2f81a81a..470744d7d82 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceBase.ts @@ -5,7 +5,7 @@ import { IPromptsService, TSharedPrompt } from '../../../service/types.js'; import { ITextModel } from '../../../../../../../../editor/common/model.js'; -import { ObservableDisposable } from '../../../../../../../../base/common/observableDisposable.js'; +import { ObservableDisposable } from '../../../utils/observableDisposable.js'; import { CancellationToken, CancellationTokenSource } from '../../../../../../../../base/common/cancellation.js'; /** diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceManagerBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceManagerBase.ts index 905b3bdc1f3..1ac1564defe 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceManagerBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceManagerBase.ts @@ -8,7 +8,7 @@ import { assert } from '../../../../../../../../base/common/assert.js'; import { ITextModel } from '../../../../../../../../editor/common/model.js'; import { assertDefined } from '../../../../../../../../base/common/types.js'; import { Disposable } from '../../../../../../../../base/common/lifecycle.js'; -import { ObjectCache } from '../../../../../../../../base/common/objectCache.js'; +import { ObjectCache } from '../../../utils/objectCache.js'; import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../../../constants.js'; import { IModelService } from '../../../../../../../../editor/common/services/model.js'; import { PromptsConfig } from '../../../../../../../../platform/prompts/common/config.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts index 6353799465d..7562e42fae4 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts @@ -24,19 +24,19 @@ import type { TPromptReference, IResolveError, ITopError } from './types.js'; import { type IDisposable } from '../../../../../../base/common/lifecycle.js'; import { assert, assertNever } from '../../../../../../base/common/assert.js'; import { basename, dirname } from '../../../../../../base/common/resources.js'; -import { BaseToken } from '../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../codecs/base/baseToken.js'; import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js'; import { type IRange, Range } from '../../../../../../editor/common/core/range.js'; import { PromptHeader, type TPromptMetadata } from './promptHeader/promptHeader.js'; -import { ObservableDisposable } from '../../../../../../base/common/observableDisposable.js'; +import { ObservableDisposable } from '../utils/observableDisposable.js'; import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../constants.js'; -import { LinesDecoder } from '../../../../../../editor/common/codecs/linesCodec/linesDecoder.js'; +import { LinesDecoder } from '../codecs/base/linesCodec/linesDecoder.js'; import { IWorkspaceContextService } from '../../../../../../platform/workspace/common/workspace.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { MarkdownLink } from '../../../../../../editor/common/codecs/markdownCodec/tokens/markdownLink.js'; -import { MarkdownToken } from '../../../../../../editor/common/codecs/markdownCodec/tokens/markdownToken.js'; +import { MarkdownLink } from '../codecs/base/markdownCodec/tokens/markdownLink.js'; +import { MarkdownToken } from '../codecs/base/markdownCodec/tokens/markdownToken.js'; import { isPromptOrInstructionsFile, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { FrontMatterHeader } from '../../../../../../editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { FrontMatterHeader } from '../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; import { OpenFailed, NotPromptFile, RecursiveReference, FolderReference, ResolveError } from '../../promptFileReferenceErrors.js'; import { type IPromptContentsProviderOptions, DEFAULT_OPTIONS as CONTENTS_PROVIDER_DEFAULT_OPTIONS } from '../contentProviders/promptContentsProviderBase.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/headerBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/headerBase.ts index 7cb97d12a14..cea4c15d430 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/headerBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/headerBase.ts @@ -11,12 +11,12 @@ import { PromptDescriptionMetadata } from './metadata/index.js'; import { type TInstructionsMetadata } from './instructionsHeader.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; import { Disposable } from '../../../../../../../base/common/lifecycle.js'; -import { ObjectStream } from '../../../../../../../editor/common/codecs/utils/objectStream.js'; +import { ObjectStream } from '../../codecs/base/utils/objectStream.js'; import { PromptMetadataError, PromptMetadataWarning, type TDiagnostic } from './diagnostics.js'; -import { SimpleToken } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/index.js'; -import { FrontMatterRecord } from '../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; -import { FrontMatterHeader } from '../../../../../../../editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.js'; -import { FrontMatterDecoder, type TFrontMatterToken } from '../../../../../../../editor/common/codecs/frontMatterCodec/frontMatterDecoder.js'; +import { SimpleToken } from '../../codecs/base/simpleCodec/tokens/tokens.js'; +import { FrontMatterRecord } from '../../codecs/base/frontMatterCodec/tokens/index.js'; +import { FrontMatterHeader } from '../../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { FrontMatterDecoder, type TFrontMatterToken } from '../../codecs/base/frontMatterCodec/frontMatterDecoder.js'; /** * A metadata utility class "dehydrated" into a plain data object with diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts index a024a6bf11a..2d4137d8c43 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts @@ -6,7 +6,7 @@ import { PromptApplyToMetadata } from './metadata/applyTo.js'; import { HeaderBase, IHeaderMetadata, type TDehydrated } from './headerBase.js'; import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; -import { FrontMatterRecord } from '../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterRecord } from '../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Metadata utility object for instruction files. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts index b97dd2f0f63..e3fc03d9e3a 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts @@ -8,7 +8,7 @@ import { localize } from '../../../../../../../../nls.js'; import { INSTRUCTIONS_LANGUAGE_ID } from '../../../constants.js'; import { isEmptyPattern, parse, splitGlobAware } from '../../../../../../../../base/common/glob.js'; import { PromptMetadataDiagnostic, PromptMetadataError, PromptMetadataWarning } from '../diagnostics.js'; -import { FrontMatterRecord, FrontMatterToken } from '../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterRecord, FrontMatterToken } from '../../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Name of the metadata record in the prompt header. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/enum.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/enum.ts index 8a24c72dcbc..2b572e88ae7 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/enum.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/enum.ts @@ -8,8 +8,8 @@ import { localize } from '../../../../../../../../../nls.js'; import { assert } from '../../../../../../../../../base/common/assert.js'; import { isOneOf } from '../../../../../../../../../base/common/types.js'; import { PromptMetadataDiagnostic, PromptMetadataError } from '../../diagnostics.js'; -import { FrontMatterSequence } from '../../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/frontMatterSequence.js'; -import { FrontMatterRecord, FrontMatterString } from '../../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterSequence } from '../../../../codecs/base/frontMatterCodec/tokens/frontMatterSequence.js'; +import { FrontMatterRecord, FrontMatterString } from '../../../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Enum type is the special case of the {@link PromptStringMetadata string} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/record.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/record.ts index a158d7d43a2..aa7a4660f66 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/record.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/record.ts @@ -6,7 +6,7 @@ import { assert } from '../../../../../../../../../base/common/assert.js'; import { Range } from '../../../../../../../../../editor/common/core/range.js'; import { PromptMetadataDiagnostic, PromptMetadataError, PromptMetadataWarning } from '../../diagnostics.js'; -import { FrontMatterRecord } from '../../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterRecord } from '../../../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Supported primitive types for metadata values in a prompt header. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/string.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/string.ts index 6588310c4e1..d240efa069a 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/string.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/base/string.ts @@ -6,8 +6,8 @@ import { PromptMetadataRecord } from './record.js'; import { localize } from '../../../../../../../../../nls.js'; import { PromptMetadataDiagnostic, PromptMetadataError } from '../../diagnostics.js'; -import { FrontMatterSequence } from '../../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/frontMatterSequence.js'; -import { FrontMatterRecord, FrontMatterString } from '../../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterSequence } from '../../../../codecs/base/frontMatterCodec/tokens/frontMatterSequence.js'; +import { FrontMatterRecord, FrontMatterString } from '../../../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Base class for all metadata records with a `string` value. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/description.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/description.ts index 619352d2731..aaa8fa3a640 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/description.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/description.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { PromptStringMetadata } from './base/string.js'; -import { FrontMatterRecord, FrontMatterToken } from '../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterRecord, FrontMatterToken } from '../../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Name of the metadata record in the prompt header. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/mode.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/mode.ts index 865f301b651..6137e90ffae 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/mode.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/mode.ts @@ -5,7 +5,7 @@ import { ChatMode } from '../../../../constants.js'; import { PromptEnumMetadata } from './base/enum.js'; -import { FrontMatterRecord, FrontMatterToken } from '../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterRecord, FrontMatterToken } from '../../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Name of the metadata record in the prompt header. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/tools.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/tools.ts index e2b73e80ef4..c98638186f2 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/tools.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/tools.ts @@ -6,8 +6,8 @@ import { PromptMetadataRecord } from './base/record.js'; import { localize } from '../../../../../../../../nls.js'; import { PromptMetadataDiagnostic, PromptMetadataError, PromptMetadataWarning } from '../diagnostics.js'; -import { FrontMatterSequence } from '../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/frontMatterSequence.js'; -import { FrontMatterArray, FrontMatterRecord, FrontMatterString, FrontMatterToken, FrontMatterValueToken } from '../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterSequence } from '../../../codecs/base/frontMatterCodec/tokens/frontMatterSequence.js'; +import { FrontMatterArray, FrontMatterRecord, FrontMatterString, FrontMatterToken, FrontMatterValueToken } from '../../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Name of the metadata record in the prompt header. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts index 76049d743f4..9181fd57b15 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts @@ -11,7 +11,7 @@ import { assertDefined } from '../../../../../../../base/common/types.js'; import { PromptToolsMetadata, PromptModeMetadata } from './metadata/index.js'; import { HeaderBase, IHeaderMetadata, type TDehydrated } from './headerBase.js'; import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; -import { FrontMatterRecord } from '../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; +import { FrontMatterRecord } from '../../codecs/base/frontMatterCodec/tokens/index.js'; /** * Metadata utility object for prompt files. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 72afe3cdbb2..165bb3e9aa1 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -17,7 +17,7 @@ import { PromptFilesLocator } from '../utils/promptFilesLocator.js'; import { Disposable } from '../../../../../../base/common/lifecycle.js'; import { Event } from '../../../../../../base/common/event.js'; import { type ITextModel } from '../../../../../../editor/common/model.js'; -import { ObjectCache } from '../../../../../../base/common/objectCache.js'; +import { ObjectCache } from '../utils/objectCache.js'; import { ILogService } from '../../../../../../platform/log/common/log.js'; import { TextModelPromptParser } from '../parsers/textModelPromptParser.js'; import { ILabelService } from '../../../../../../platform/label/common/label.js'; diff --git a/src/vs/base/common/objectCache.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/objectCache.ts similarity index 98% rename from src/vs/base/common/objectCache.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/utils/objectCache.ts index aa50e02f5c6..443d6e44c94 100644 --- a/src/vs/base/common/objectCache.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/objectCache.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableMap } from '../../base/common/lifecycle.js'; +import { Disposable, DisposableMap } from '../../../../../../base/common/lifecycle.js'; import { ObservableDisposable, assertNotDisposed } from './observableDisposable.js'; /** diff --git a/src/vs/base/common/observableDisposable.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/observableDisposable.ts similarity index 97% rename from src/vs/base/common/observableDisposable.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/utils/observableDisposable.ts index 91fe9154a41..a0e6a70e733 100644 --- a/src/vs/base/common/observableDisposable.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/observableDisposable.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableStore, IDisposable, toDisposable } from './lifecycle.js'; +import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../../../base/common/lifecycle.js'; /** * @deprecated do not use this, https://github.com/microsoft/vscode/issues/248366 diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterBoolean.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterBoolean.test.ts similarity index 91% rename from src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterBoolean.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterBoolean.test.ts index a117af9a045..8d32c30d851 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterBoolean.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterBoolean.test.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; -import { Word } from '../../../../common/codecs/simpleCodec/tokens/index.js'; -import { randomBoolean } from '../../../../../base/test/common/testUtils.js'; -import { FrontMatterBoolean } from '../../../../common/codecs/frontMatterCodec/tokens/index.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { FrontMatterSequence } from '../../../../common/codecs/frontMatterCodec/tokens/frontMatterSequence.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { Word } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; +import { randomBoolean } from '../../../../../../../../../base/test/common/testUtils.js'; +import { FrontMatterBoolean } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/index.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; +import { FrontMatterSequence } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterSequence.js'; suite('FrontMatterBoolean', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterDecoder.test.ts similarity index 90% rename from src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterDecoder.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterDecoder.test.ts index 1cc9c7f466b..b4f78b9d19b 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterDecoder.test.ts @@ -4,19 +4,19 @@ *--------------------------------------------------------------------------------------------*/ -import { Range } from '../../../../common/core/range.js'; -import { TestDecoder } from '../../utils/testDecoder.js'; -import { VSBuffer } from '../../../../../base/common/buffer.js'; -import { newWriteableStream } from '../../../../../base/common/stream.js'; -import { NewLine } from '../../../../common/codecs/linesCodec/tokens/newLine.js'; -import { DoubleQuote } from '../../../../common/codecs/simpleCodec/tokens/doubleQuote.js'; -import { type TSimpleDecoderToken } from '../../../../common/codecs/simpleCodec/simpleDecoder.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { LeftBracket, RightBracket } from '../../../../common/codecs/simpleCodec/tokens/brackets.js'; -import { FrontMatterDecoder } from '../../../../common/codecs/frontMatterCodec/frontMatterDecoder.js'; -import { FrontMatterSequence } from '../../../../common/codecs/frontMatterCodec/tokens/frontMatterSequence.js'; -import { ExclamationMark, Quote, Tab, Word, Space, Colon, VerticalTab, Comma, Dash } from '../../../../common/codecs/simpleCodec/tokens/index.js'; -import { FrontMatterBoolean, FrontMatterString, FrontMatterArray, FrontMatterRecord, FrontMatterRecordDelimiter, FrontMatterRecordName } from '../../../../common/codecs/frontMatterCodec/tokens/index.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { TestDecoder } from '../utils/testDecoder.js'; +import { VSBuffer } from '../../../../../../../../../base/common/buffer.js'; +import { newWriteableStream } from '../../../../../../../../../base/common/stream.js'; +import { NewLine } from '../../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; +import { DoubleQuote } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/doubleQuote.js'; +import { type TSimpleDecoderToken } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/simpleDecoder.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; +import { LeftBracket, RightBracket } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/brackets.js'; +import { FrontMatterDecoder } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.js'; +import { FrontMatterSequence } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterSequence.js'; +import { ExclamationMark, Quote, Tab, Word, Space, Colon, VerticalTab, Comma, Dash } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; +import { FrontMatterBoolean, FrontMatterString, FrontMatterArray, FrontMatterRecord, FrontMatterRecordDelimiter, FrontMatterRecordName } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/index.js'; /** * Front Matter decoder for testing purposes. diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterRecord.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterRecord.test.ts similarity index 91% rename from src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterRecord.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterRecord.test.ts index cac93d99e46..fba57e45209 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterRecord.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterRecord.test.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { FrontMatterSequence } from '../../../../common/codecs/frontMatterCodec/tokens/frontMatterSequence.js'; -import { Colon, LeftBracket, Quote, RightBracket, Space, Tab, VerticalTab, Word } from '../../../../common/codecs/simpleCodec/tokens/index.js'; -import { FrontMatterArray, FrontMatterBoolean, FrontMatterRecord, FrontMatterRecordDelimiter, FrontMatterRecordName, FrontMatterString } from '../../../../common/codecs/frontMatterCodec/tokens/index.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; +import { FrontMatterSequence } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterSequence.js'; +import { Colon, LeftBracket, Quote, RightBracket, Space, Tab, VerticalTab, Word } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; +import { FrontMatterArray, FrontMatterBoolean, FrontMatterRecord, FrontMatterRecordDelimiter, FrontMatterRecordName, FrontMatterString } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/index.js'; suite('FrontMatterBoolean', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterSequence.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterSequence.test.ts similarity index 84% rename from src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterSequence.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterSequence.test.ts index a17bc998bdc..68602622bba 100644 --- a/src/vs/editor/test/common/codecs/frontMatterDecoder/frontMatterSequence.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/frontMatterDecoder/frontMatterSequence.test.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; -import { FrontMatterValueToken } from '../../../../common/codecs/frontMatterCodec/tokens/index.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { Space, Tab, VerticalTab, Word } from '../../../../common/codecs/simpleCodec/tokens/index.js'; -import { FrontMatterSequence } from '../../../../common/codecs/frontMatterCodec/tokens/frontMatterSequence.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { FrontMatterValueToken } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/index.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; +import { Space, Tab, VerticalTab, Word } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; +import { FrontMatterSequence } from '../../../../../../common/promptSyntax/codecs/base/frontMatterCodec/tokens/frontMatterSequence.js'; suite('FrontMatterSequence', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/editor/test/common/codecs/linesDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/linesDecoder.test.ts similarity index 89% rename from src/vs/editor/test/common/codecs/linesDecoder.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/linesDecoder.test.ts index 8e021b57ec3..b9ac4916923 100644 --- a/src/vs/editor/test/common/codecs/linesDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/linesDecoder.test.ts @@ -4,16 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../common/core/range.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { DisposableStore } from '../../../../base/common/lifecycle.js'; -import { Line } from '../../../common/codecs/linesCodec/tokens/line.js'; -import { TestDecoder, TTokensConsumeMethod } from '../utils/testDecoder.js'; -import { NewLine } from '../../../common/codecs/linesCodec/tokens/newLine.js'; -import { newWriteableStream, WriteableStream } from '../../../../base/common/stream.js'; -import { CarriageReturn } from '../../../common/codecs/linesCodec/tokens/carriageReturn.js'; -import { LinesDecoder, TLineToken } from '../../../common/codecs/linesCodec/linesDecoder.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; +import { Range } from '../../../../../../../../editor/common/core/range.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; +import { DisposableStore } from '../../../../../../../../base/common/lifecycle.js'; +import { Line } from '../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/line.js'; +import { TestDecoder, TTokensConsumeMethod } from './utils/testDecoder.js'; +import { NewLine } from '../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; +import { newWriteableStream, WriteableStream } from '../../../../../../../../base/common/stream.js'; +import { CarriageReturn } from '../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.js'; +import { LinesDecoder, TLineToken } from '../../../../../common/promptSyntax/codecs/base/linesCodec/linesDecoder.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../base/test/common/utils.js'; /** * Note! This decoder is also often used to test common logic of abstract {@link BaseDecoder} diff --git a/src/vs/editor/test/common/codecs/markdownDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/markdownDecoder.test.ts similarity index 93% rename from src/vs/editor/test/common/codecs/markdownDecoder.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/markdownDecoder.test.ts index 1b395bca186..1c9a0c0abbf 100644 --- a/src/vs/editor/test/common/codecs/markdownDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/markdownDecoder.test.ts @@ -4,28 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { TestDecoder } from '../utils/testDecoder.js'; -import { Range } from '../../../common/core/range.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { newWriteableStream } from '../../../../base/common/stream.js'; -import { Tab } from '../../../common/codecs/simpleCodec/tokens/tab.js'; -import { Word } from '../../../common/codecs/simpleCodec/tokens/word.js'; -import { Dash } from '../../../common/codecs/simpleCodec/tokens/dash.js'; -import { Space } from '../../../common/codecs/simpleCodec/tokens/space.js'; -import { Slash } from '../../../common/codecs/simpleCodec/tokens/slash.js'; -import { NewLine } from '../../../common/codecs/linesCodec/tokens/newLine.js'; -import { FormFeed } from '../../../common/codecs/simpleCodec/tokens/formFeed.js'; -import { VerticalTab } from '../../../common/codecs/simpleCodec/tokens/verticalTab.js'; -import { MarkdownLink } from '../../../common/codecs/markdownCodec/tokens/markdownLink.js'; -import { CarriageReturn } from '../../../common/codecs/linesCodec/tokens/carriageReturn.js'; -import { MarkdownImage } from '../../../common/codecs/markdownCodec/tokens/markdownImage.js'; -import { ExclamationMark } from '../../../common/codecs/simpleCodec/tokens/exclamationMark.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; -import { MarkdownComment } from '../../../common/codecs/markdownCodec/tokens/markdownComment.js'; -import { LeftBracket, RightBracket } from '../../../common/codecs/simpleCodec/tokens/brackets.js'; -import { MarkdownDecoder, TMarkdownToken } from '../../../common/codecs/markdownCodec/markdownDecoder.js'; -import { LeftParenthesis, RightParenthesis } from '../../../common/codecs/simpleCodec/tokens/parentheses.js'; -import { LeftAngleBracket, RightAngleBracket } from '../../../common/codecs/simpleCodec/tokens/angleBrackets.js'; +import { TestDecoder } from './utils/testDecoder.js'; +import { Range } from '../../../../../../../../editor/common/core/range.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; +import { newWriteableStream } from '../../../../../../../../base/common/stream.js'; +import { Tab } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tab.js'; +import { Word } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/word.js'; +import { Dash } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/dash.js'; +import { Space } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/space.js'; +import { Slash } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/slash.js'; +import { NewLine } from '../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; +import { FormFeed } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/formFeed.js'; +import { VerticalTab } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/verticalTab.js'; +import { MarkdownLink } from '../../../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.js'; +import { CarriageReturn } from '../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.js'; +import { MarkdownImage } from '../../../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownImage.js'; +import { ExclamationMark } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/exclamationMark.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../base/test/common/utils.js'; +import { MarkdownComment } from '../../../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownComment.js'; +import { LeftBracket, RightBracket } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/brackets.js'; +import { MarkdownDecoder, TMarkdownToken } from '../../../../../common/promptSyntax/codecs/base/markdownCodec/markdownDecoder.js'; +import { LeftParenthesis, RightParenthesis } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/parentheses.js'; +import { LeftAngleBracket, RightAngleBracket } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/angleBrackets.js'; /** * A reusable test utility that asserts that a `TestMarkdownDecoder` instance diff --git a/src/vs/editor/test/common/codecs/simpleDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/simpleDecoder.test.ts similarity index 90% rename from src/vs/editor/test/common/codecs/simpleDecoder.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/simpleDecoder.test.ts index 7ebb92e68a0..68beddf42f6 100644 --- a/src/vs/editor/test/common/codecs/simpleDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/simpleDecoder.test.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Range } from '../../../common/core/range.js'; -import { TestDecoder } from '../utils/testDecoder.js'; -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { newWriteableStream } from '../../../../base/common/stream.js'; -import { NewLine } from '../../../common/codecs/linesCodec/tokens/newLine.js'; -import { CarriageReturn } from '../../../common/codecs/linesCodec/tokens/carriageReturn.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; -import { SimpleDecoder, TSimpleDecoderToken } from '../../../common/codecs/simpleCodec/simpleDecoder.js'; +import { Range } from '../../../../../../../../editor/common/core/range.js'; +import { TestDecoder } from './utils/testDecoder.js'; +import { VSBuffer } from '../../../../../../../../base/common/buffer.js'; +import { newWriteableStream } from '../../../../../../../../base/common/stream.js'; +import { NewLine } from '../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; +import { CarriageReturn } from '../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../base/test/common/utils.js'; +import { SimpleDecoder, TSimpleDecoderToken } from '../../../../../common/promptSyntax/codecs/base/simpleCodec/simpleDecoder.js'; import { At, Tab, @@ -35,7 +35,7 @@ import { LeftAngleBracket, RightAngleBracket, Comma, -} from '../../../common/codecs/simpleCodec/tokens/index.js'; +} from '../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; /** * A reusable test utility that asserts that a `SimpleDecoder` instance diff --git a/src/vs/editor/test/common/codecs/testUtils/randomRange.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomRange.ts similarity index 86% rename from src/vs/editor/test/common/codecs/testUtils/randomRange.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomRange.ts index c9e589c5f0a..fbc57ef73a7 100644 --- a/src/vs/editor/test/common/codecs/testUtils/randomRange.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomRange.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; -import { randomInt } from '../../../../../base/common/numbers.js'; -import { randomBoolean } from '../../../../../base/test/common/testUtils.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { randomInt } from '../../../../../../../../../base/common/numbers.js'; +import { randomBoolean } from '../../../../../../../../../base/test/common/testUtils.js'; /** * Generates a random {@link Range} object. diff --git a/src/vs/editor/test/common/codecs/testUtils/randomTokens.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomTokens.ts similarity index 84% rename from src/vs/editor/test/common/codecs/testUtils/randomTokens.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomTokens.ts index 3e2e2e58734..89bfd64afa7 100644 --- a/src/vs/editor/test/common/codecs/testUtils/randomTokens.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomTokens.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; -import { Text } from '../../../../common/codecs/textToken.js'; -import { randomInt } from '../../../../../base/common/numbers.js'; -import { assertNever } from '../../../../../base/common/assert.js'; -import { NewLine } from '../../../../common/codecs/linesCodec/tokens/newLine.js'; -import { Space, Word } from '../../../../common/codecs/simpleCodec/tokens/index.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { Text } from '../../../../../../common/promptSyntax/codecs/base/textToken.js'; +import { randomInt } from '../../../../../../../../../base/common/numbers.js'; +import { assertNever } from '../../../../../../../../../base/common/assert.js'; +import { NewLine } from '../../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; +import { Space, Word } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; /** * Token type for the {@link cloneTokens} and {@link randomTokens} functions. diff --git a/src/vs/editor/test/common/codecs/tokens/baseToken.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/baseToken.test.ts similarity index 92% rename from src/vs/editor/test/common/codecs/tokens/baseToken.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/baseToken.test.ts index 677215bfbec..448cd3d439a 100644 --- a/src/vs/editor/test/common/codecs/tokens/baseToken.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/baseToken.test.ts @@ -4,18 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; -import { randomInt } from '../../../../../base/common/numbers.js'; -import { BaseToken } from '../../../../common/codecs/baseToken.js'; -import { assertDefined } from '../../../../../base/common/types.js'; -import { randomBoolean } from '../../../../../base/test/common/testUtils.js'; -import { NewLine } from '../../../../common/codecs/linesCodec/tokens/newLine.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { randomInt } from '../../../../../../../../../base/common/numbers.js'; +import { BaseToken } from '../../../../../../common/promptSyntax/codecs/base/baseToken.js'; +import { assertDefined } from '../../../../../../../../../base/common/types.js'; +import { randomBoolean } from '../../../../../../../../../base/test/common/testUtils.js'; +import { NewLine } from '../../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; import { randomRange, randomRangeNotEqualTo } from '../testUtils/randomRange.js'; -import { CarriageReturn } from '../../../../common/codecs/linesCodec/tokens/carriageReturn.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { TSimpleToken, WELL_KNOWN_TOKENS } from '../../../../common/codecs/simpleCodec/simpleDecoder.js'; -import { ISimpleTokenClass, SimpleToken } from '../../../../common/codecs/simpleCodec/tokens/simpleToken.js'; -import { At, Colon, DollarSign, ExclamationMark, Hash, LeftAngleBracket, LeftBracket, LeftCurlyBrace, RightAngleBracket, RightBracket, RightCurlyBrace, Slash, Space, Word } from '../../../../common/codecs/simpleCodec/tokens/index.js'; +import { CarriageReturn } from '../../../../../../common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; +import { TSimpleToken, WELL_KNOWN_TOKENS } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/simpleDecoder.js'; +import { ISimpleTokenClass, SimpleToken } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/simpleToken.js'; +import { At, Colon, DollarSign, ExclamationMark, Hash, LeftAngleBracket, LeftBracket, LeftCurlyBrace, RightAngleBracket, RightBracket, RightCurlyBrace, Slash, Space, Word } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; /** * List of simple tokens to randomly select from diff --git a/src/vs/editor/test/common/codecs/tokens/compositeToken.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/compositeToken.test.ts similarity index 91% rename from src/vs/editor/test/common/codecs/tokens/compositeToken.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/compositeToken.test.ts index d91f02260fe..1979deff707 100644 --- a/src/vs/editor/test/common/codecs/tokens/compositeToken.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/compositeToken.test.ts @@ -4,15 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; import { randomRange } from '../testUtils/randomRange.js'; -import { randomInt } from '../../../../../base/common/numbers.js'; -import { BaseToken } from '../../../../common/codecs/baseToken.js'; +import { randomInt } from '../../../../../../../../../base/common/numbers.js'; +import { BaseToken } from '../../../../../../common/promptSyntax/codecs/base/baseToken.js'; import { cloneTokens, randomTokens } from '../testUtils/randomTokens.js'; -import { CompositeToken } from '../../../../common/codecs/compositeToken.js'; -import { randomBoolean } from '../../../../../base/test/common/testUtils.js'; -import { Word } from '../../../../common/codecs/simpleCodec/tokens/index.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; +import { CompositeToken } from '../../../../../../common/promptSyntax/codecs/base/compositeToken.js'; +import { randomBoolean } from '../../../../../../../../../base/test/common/testUtils.js'; +import { Word } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; suite('CompositeToken', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/editor/test/common/codecs/tokens/simpleToken.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/simpleToken.test.ts similarity index 89% rename from src/vs/editor/test/common/codecs/tokens/simpleToken.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/simpleToken.test.ts index 66f96a794b1..df349f08cc4 100644 --- a/src/vs/editor/test/common/codecs/tokens/simpleToken.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/simpleToken.test.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { Range } from '../../../../common/core/range.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { SpacingToken, SimpleToken, Space, Tab, VerticalTab } from '../../../../common/codecs/simpleCodec/tokens/index.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; +import { SpacingToken, SimpleToken, Space, Tab, VerticalTab } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; suite('SimpleToken', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/editor/test/common/codecs/utils/objectStream.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/objectStream.test.ts similarity index 83% rename from src/vs/editor/test/common/codecs/utils/objectStream.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/objectStream.test.ts index 8191b24ccf0..bcbd12424e6 100644 --- a/src/vs/editor/test/common/codecs/utils/objectStream.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/objectStream.test.ts @@ -4,17 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { URI } from '../../../../../base/common/uri.js'; -import { createTextModel } from '../../testTextModel.js'; +import { URI } from '../../../../../../../../../base/common/uri.js'; +import { createTextModel } from '../../../../../../../../../editor/test/common/testTextModel.js'; import { randomTokens } from '../testUtils/randomTokens.js'; -import { randomInt } from '../../../../../base/common/numbers.js'; -import { BaseToken } from '../../../../common/codecs/baseToken.js'; -import { assertDefined } from '../../../../../base/common/types.js'; -import { randomBoolean } from '../../../../../base/test/common/testUtils.js'; -import { CancellationTokenSource } from '../../../../../base/common/cancellation.js'; -import { arrayToGenerator, ObjectStream } from '../../../../common/codecs/utils/objectStream.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { objectStreamFromTextModel } from '../../../../common/codecs/utils/objectStreamFromTextModel.js'; +import { randomInt } from '../../../../../../../../../base/common/numbers.js'; +import { assertDefined } from '../../../../../../../../../base/common/types.js'; +import { randomBoolean } from '../../../../../../../../../base/test/common/testUtils.js'; +import { CancellationTokenSource } from '../../../../../../../../../base/common/cancellation.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../../base/test/common/utils.js'; +import { arrayToGenerator, ObjectStream } from '../../../../../../common/promptSyntax/codecs/base/utils/objectStream.js'; +import { objectStreamFromTextModel } from '../../../../../../common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.js'; +import { BaseToken } from '../../../../../../common/promptSyntax/codecs/base/baseToken.js'; suite('ObjectStream', () => { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/editor/test/common/utils/testDecoder.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/testDecoder.ts similarity index 91% rename from src/vs/editor/test/common/utils/testDecoder.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/testDecoder.ts index 637bf86f6fd..62a1293ff13 100644 --- a/src/vs/editor/test/common/utils/testDecoder.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/testDecoder.ts @@ -4,14 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { VSBuffer } from '../../../../base/common/buffer.js'; -import { randomInt } from '../../../../base/common/numbers.js'; -import { BaseToken } from '../../../common/codecs/baseToken.js'; -import { assertDefined } from '../../../../base/common/types.js'; -import { Disposable } from '../../../../base/common/lifecycle.js'; -import { WriteableStream } from '../../../../base/common/stream.js'; -import { BaseDecoder } from '../../../../base/common/codecs/baseDecoder.js'; -import { SimpleToken } from '../../../common/codecs/simpleCodec/tokens/simpleToken.js'; +import { VSBuffer } from '../../../../../../../../../base/common/buffer.js'; +import { randomInt } from '../../../../../../../../../base/common/numbers.js'; +import { assertDefined } from '../../../../../../../../../base/common/types.js'; +import { Disposable } from '../../../../../../../../../base/common/lifecycle.js'; +import { WriteableStream } from '../../../../../../../../../base/common/stream.js'; +import { BaseDecoder } from '../../../../../../common/promptSyntax/codecs/base/baseDecoder.js'; +import { BaseToken } from '../../../../../../common/promptSyntax/codecs/base/baseToken.js'; +import { SimpleToken } from '../../../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/simpleToken.js'; + /** * Kind of decoder tokens consume methods are different ways diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts index d284843f94a..8c5b9ded809 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptCodec.test.ts @@ -6,10 +6,10 @@ import { VSBuffer } from '../../../../../../../base/common/buffer.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; import { newWriteableStream } from '../../../../../../../base/common/stream.js'; -import { TestDecoder } from '../../../../../../../editor/test/common/utils/testDecoder.js'; +import { TestDecoder } from './base/utils/testDecoder.js'; import { ChatPromptCodec } from '../../../../common/promptSyntax/codecs/chatPromptCodec.js'; -import { NewLine } from '../../../../../../../editor/common/codecs/linesCodec/tokens/newLine.js'; -import { Space, Tab, Word } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/index.js'; +import { NewLine } from '../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; +import { Space, Tab, Word } from '../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; import { PromptVariableWithData } from '../../../../common/promptSyntax/codecs/tokens/promptVariable.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; import { ChatPromptDecoder, TChatPromptToken } from '../../../../common/promptSyntax/codecs/chatPromptDecoder.js'; diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts index e8c57961a94..45572f00fc1 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/chatPromptDecoder.test.ts @@ -6,16 +6,16 @@ import { VSBuffer } from '../../../../../../../base/common/buffer.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; import { newWriteableStream } from '../../../../../../../base/common/stream.js'; -import { TestDecoder } from '../../../../../../../editor/test/common/utils/testDecoder.js'; -import { NewLine } from '../../../../../../../editor/common/codecs/linesCodec/tokens/newLine.js'; +import { TestDecoder } from './base/utils/testDecoder.js'; +import { NewLine } from '../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; import { PromptAtMention } from '../../../../common/promptSyntax/codecs/tokens/promptAtMention.js'; import { PromptSlashCommand } from '../../../../common/promptSyntax/codecs/tokens/promptSlashCommand.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; -import { MarkdownLink } from '../../../../../../../editor/common/codecs/markdownCodec/tokens/markdownLink.js'; +import { MarkdownLink } from '../../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.js'; import { PromptTemplateVariable } from '../../../../common/promptSyntax/codecs/tokens/promptTemplateVariable.js'; import { ChatPromptDecoder, TChatPromptToken } from '../../../../common/promptSyntax/codecs/chatPromptDecoder.js'; import { PromptVariable, PromptVariableWithData } from '../../../../common/promptSyntax/codecs/tokens/promptVariable.js'; -import { At, Dash, ExclamationMark, FormFeed, Hash, Space, Tab, VerticalTab, Word } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/index.js'; +import { At, Dash, ExclamationMark, FormFeed, Hash, Space, Tab, VerticalTab, Word } from '../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; /** * A reusable test utility that asserts that a `ChatPromptDecoder` instance diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts index da2d62f7e48..d673169ba4d 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/markdownExtensionsDecoder.test.ts @@ -7,20 +7,20 @@ import { assert } from '../../../../../../../base/common/assert.js'; import { VSBuffer } from '../../../../../../../base/common/buffer.js'; import { randomInt } from '../../../../../../../base/common/numbers.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; -import { Text } from '../../../../../../../editor/common/codecs/textToken.js'; +import { Text } from '../../../../common/promptSyntax/codecs/base/textToken.js'; import { newWriteableStream } from '../../../../../../../base/common/stream.js'; import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; -import { TestDecoder } from '../../../../../../../editor/test/common/utils/testDecoder.js'; -import { Word } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/word.js'; -import { NewLine } from '../../../../../../../editor/common/codecs/linesCodec/tokens/newLine.js'; +import { TestDecoder } from './base/utils/testDecoder.js'; +import { Word } from '../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/word.js'; +import { NewLine } from '../../../../common/promptSyntax/codecs/base/linesCodec/tokens/newLine.js'; import { type TChatPromptToken } from '../../../../common/promptSyntax/codecs/chatPromptDecoder.js'; -import { TestSimpleDecoder } from '../../../../../../../editor/test/common/codecs/simpleDecoder.test.js'; +import { TestSimpleDecoder } from './base/simpleDecoder.test.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; -import { CarriageReturn } from '../../../../../../../editor/common/codecs/linesCodec/tokens/carriageReturn.js'; -import { FrontMatterHeader } from '../../../../../../../editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterHeader.js'; -import { Colon, Dash, DoubleQuote, Space, Tab, VerticalTab } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/index.js'; -import { MarkdownExtensionsDecoder } from '../../../../../../../editor/common/codecs/markdownExtensionsCodec/markdownExtensionsDecoder.js'; -import { FrontMatterMarker, TMarkerToken } from '../../../../../../../editor/common/codecs/markdownExtensionsCodec/tokens/frontMatterMarker.js'; +import { CarriageReturn } from '../../../../common/promptSyntax/codecs/base/linesCodec/tokens/carriageReturn.js'; +import { FrontMatterHeader } from '../../../../common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { Colon, Dash, DoubleQuote, Space, Tab, VerticalTab } from '../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; +import { MarkdownExtensionsDecoder } from '../../../../common/promptSyntax/codecs/base/markdownExtensionsCodec/markdownExtensionsDecoder.js'; +import { FrontMatterMarker, TMarkerToken } from '../../../../common/promptSyntax/codecs/base/markdownExtensionsCodec/tokens/frontMatterMarker.js'; /** * Type for supported end-of-line tokens. diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts index 193354e7759..de38092ac21 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/fileReference.test.ts @@ -7,7 +7,7 @@ import assert from 'assert'; import { randomInt } from '../../../../../../../../base/common/numbers.js'; import { Range } from '../../../../../../../../editor/common/core/range.js'; import { assertDefined } from '../../../../../../../../base/common/types.js'; -import { BaseToken } from '../../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../../../../../common/promptSyntax/codecs/base/baseToken.js'; import { PromptToken } from '../../../../../common/promptSyntax/codecs/tokens/promptToken.js'; import { FileReference } from '../../../../../common/promptSyntax/codecs/tokens/fileReference.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../base/test/common/utils.js'; diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/markdownLink.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/markdownLink.test.ts index d012f30e686..ecbf48a1fa4 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/markdownLink.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/tokens/markdownLink.test.ts @@ -7,10 +7,10 @@ import assert from 'assert'; import { randomInt } from '../../../../../../../../base/common/numbers.js'; import { Range } from '../../../../../../../../editor/common/core/range.js'; import { assertDefined } from '../../../../../../../../base/common/types.js'; -import { BaseToken } from '../../../../../../../../editor/common/codecs/baseToken.js'; +import { BaseToken } from '../../../../../common/promptSyntax/codecs/base/baseToken.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../../base/test/common/utils.js'; -import { MarkdownLink } from '../../../../../../../../editor/common/codecs/markdownCodec/tokens/markdownLink.js'; -import { MarkdownToken } from '../../../../../../../../editor/common/codecs/markdownCodec/tokens/markdownToken.js'; +import { MarkdownLink } from '../../../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.js'; +import { MarkdownToken } from '../../../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownToken.js'; suite('FileReference', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts index d4fa753ddec..cf0091333a7 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/contentProviders/filePromptContentsProvider.test.ts @@ -16,9 +16,9 @@ import { FileService } from '../../../../../../../platform/files/common/fileServ import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; import { timeout } from '../../../../../../../base/common/async.js'; import { NullPolicyService } from '../../../../../../../platform/policy/common/policy.js'; -import { Line } from '../../../../../../../editor/common/codecs/linesCodec/tokens/line.js'; +import { Line } from '../../../../common/promptSyntax/codecs/base/linesCodec/tokens/line.js'; import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; -import { LinesDecoder } from '../../../../../../../editor/common/codecs/linesCodec/linesDecoder.js'; +import { LinesDecoder } from '../../../../common/promptSyntax/codecs/base/linesCodec/linesDecoder.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'; import { ConfigurationService } from '../../../../../../../platform/configuration/common/configurationService.js'; diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts index 45b5a66787b..90676ae9cae 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts @@ -26,7 +26,7 @@ import { getPromptFileType, PromptsType } from '../../../../../../platform/promp import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { MarkdownLink } from '../../../../../../editor/common/codecs/markdownCodec/tokens/markdownLink.js'; +import { MarkdownLink } from '../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.js'; import { ConfigurationService } from '../../../../../../platform/configuration/common/configurationService.js'; import { InMemoryFileSystemProvider } from '../../../../../../platform/files/common/inMemoryFilesystemProvider.js'; import { IPromptParserOptions, type TErrorCondition } from '../../../common/promptSyntax/parsers/basePromptParser.js'; diff --git a/src/vs/base/test/common/objectCache.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/objectCache.test.ts similarity index 96% rename from src/vs/base/test/common/objectCache.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/objectCache.test.ts index 0e0053c0dab..e8c538f5e08 100644 --- a/src/vs/base/test/common/objectCache.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/objectCache.test.ts @@ -5,10 +5,10 @@ import assert from 'assert'; import { spy } from 'sinon'; -import { ObjectCache } from '../../common/objectCache.js'; -import { timeout } from '../../../base/common/async.js'; -import { ObservableDisposable } from '../../common/observableDisposable.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../base/test/common/utils.js'; +import { ObjectCache } from '../../../../common/promptSyntax/utils/objectCache.js'; +import { timeout } from '../../../../../../../base/common/async.js'; +import { ObservableDisposable } from '../../../../common/promptSyntax/utils/observableDisposable.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; /** * Test object class. diff --git a/src/vs/base/test/common/observableDisposable.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/observableDisposable.test.ts similarity index 95% rename from src/vs/base/test/common/observableDisposable.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/observableDisposable.test.ts index c29b44330c5..2478b0136d4 100644 --- a/src/vs/base/test/common/observableDisposable.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/observableDisposable.test.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; import { spy } from 'sinon'; -import { timeout } from '../../common/async.js'; -import { randomInt } from '../../common/numbers.js'; -import { Disposable, IDisposable } from '../../common/lifecycle.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js'; -import { assertNotDisposed, ObservableDisposable } from '../../common/observableDisposable.js'; +import { timeout } from '../../../../../../../base/common/async.js'; +import { randomInt } from '../../../../../../../base/common/numbers.js'; +import { Disposable, IDisposable } from '../../../../../../../base/common/lifecycle.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; +import { assertNotDisposed, ObservableDisposable } from '../../../../common/promptSyntax/utils/observableDisposable.js'; suite('ObservableDisposable', () => { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts index 16927d60d51..38d070a4d91 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/treeUtils.test.ts @@ -6,11 +6,11 @@ import assert from 'assert'; import { randomInt } from '../../../../../../../base/common/numbers.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; -import { BaseToken } from '../../../../../../../editor/common/codecs/baseToken.js'; -import { CompositeToken } from '../../../../../../../editor/common/codecs/compositeToken.js'; +import { BaseToken } from '../../../../common/promptSyntax/codecs/base/baseToken.js'; +import { CompositeToken } from '../../../../common/promptSyntax/codecs/base/compositeToken.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; import { curry, difference, flatten, forEach, map, TTree } from '../../../../common/promptSyntax/utils/treeUtils.js'; -import { ExclamationMark, Space, Tab, VerticalTab, Word } from '../../../../../../../editor/common/codecs/simpleCodec/tokens/index.js'; +import { ExclamationMark, Space, Tab, VerticalTab, Word } from '../../../../common/promptSyntax/codecs/base/simpleCodec/tokens/tokens.js'; suite('tree utilities', () => { ensureNoDisposablesAreLeakedInTestSuite(); From 65bb1d66dce64e367dd86260fc4c7b2173c24c33 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 6 Jun 2025 16:08:12 +0200 Subject: [PATCH 074/236] `assertIsDefined` vs `assertDefined` (fix #248362) (#250844) --- src/vs/base/common/types.ts | 12 +++---- src/vs/base/node/zip.ts | 6 ++-- src/vs/base/test/common/types.test.ts | 20 +++++------ .../browser/view/domLineBreaksComputer.ts | 4 +-- .../diffEditorViewZones.ts | 4 +-- .../editor/contrib/find/browser/findWidget.ts | 6 ++-- .../browser/parameterHintsWidget.ts | 10 +++--- .../electron-main/diagnosticsMainService.ts | 4 +-- .../electron-main/lifecycleMainService.ts | 6 ++-- .../electron-main/sharedProcess.ts | 4 +-- .../userDataSync/common/extensionsMerge.ts | 20 +++++------ .../electron-main/windowsMainService.ts | 4 +-- .../workbench/api/common/extHostDocuments.ts | 4 +-- .../workbench/api/common/extHostEditorTabs.ts | 6 ++-- .../workbench/api/common/extHostNotebook.ts | 4 +-- src/vs/workbench/browser/composite.ts | 4 +-- src/vs/workbench/browser/layout.ts | 10 +++--- src/vs/workbench/browser/part.ts | 4 +-- .../parts/activitybar/activitybarPart.ts | 6 ++-- .../parts/auxiliarybar/auxiliaryBarPart.ts | 4 +-- .../workbench/browser/parts/compositePart.ts | 12 +++---- .../browser/parts/editor/editorDropTarget.ts | 10 +++--- .../browser/parts/editor/editorPanes.ts | 6 ++-- .../browser/parts/editor/editorPlaceholder.ts | 6 ++-- .../browser/parts/editor/editorStatus.ts | 16 ++++----- .../browser/parts/editor/editorTabsControl.ts | 6 ++-- .../parts/editor/multiEditorTabsControl.ts | 26 +++++++------- .../browser/parts/editor/sideBySideEditor.ts | 14 ++++---- .../parts/editor/singleEditorTabsControl.ts | 8 ++--- .../browser/parts/editor/textCodeEditor.ts | 4 +-- .../browser/parts/editor/textDiffEditor.ts | 6 ++-- .../browser/parts/editor/textEditor.ts | 4 +-- .../parts/editor/textResourceEditor.ts | 4 +-- .../notifications/notificationsCenter.ts | 12 +++---- .../parts/notifications/notificationsList.ts | 6 ++-- .../notifications/notificationsToasts.ts | 4 +-- .../browser/parts/paneCompositePartService.ts | 4 +-- .../browser/parts/panel/panelPart.ts | 4 +-- .../browser/parts/sidebar/sidebarPart.ts | 4 +-- .../browser/parts/statusbar/statusbarItem.ts | 4 +-- .../browser/parts/statusbar/statusbarPart.ts | 10 +++--- .../workbench/browser/parts/views/viewPane.ts | 4 +-- .../browser/parts/views/viewPaneContainer.ts | 14 ++++---- src/vs/workbench/browser/web.main.ts | 4 +-- src/vs/workbench/common/editor.ts | 4 +-- .../browser/dictation/editorDictation.ts | 4 +-- .../customEditor/browser/customEditorInput.ts | 8 ++--- .../customEditor/browser/customEditors.ts | 6 ++-- .../files/browser/editors/textFileEditor.ts | 4 +-- .../contrib/files/common/explorerModel.ts | 4 +-- .../notebookEditorModelResolverServiceImpl.ts | 4 +-- .../browser/keybindingsEditorContribution.ts | 6 ++-- .../search/browser/searchActionsNav.ts | 4 +-- .../searchEditor/browser/searchEditor.ts | 4 +-- .../searchEditor/browser/searchEditorModel.ts | 4 +-- .../contrib/splash/browser/partsSplash.ts | 12 +++---- .../trustedDomainsFileSystemProvider.ts | 4 +-- .../browser/gettingStarted.ts | 16 ++++----- .../browser/gettingStartedDetailsRenderer.ts | 6 ++-- .../common/newFile.contribution.ts | 4 +-- .../common/walkThroughContentProvider.ts | 4 +-- .../services/search/common/queryBuilder.ts | 4 +-- .../storage/browser/storageService.ts | 6 ++-- .../textfile/common/textFileEditorModel.ts | 4 +-- .../test/browser/textFileEditorModel.test.ts | 16 ++++----- .../common/untitledTextEditorModel.ts | 4 +-- .../browser/viewDescriptorService.test.ts | 10 +++--- .../common/storedFileWorkingCopy.ts | 8 ++--- .../common/workingCopyHistoryService.ts | 36 +++++++++---------- .../browser/storedFileWorkingCopy.test.ts | 4 +-- .../workingCopyHistoryTracker.test.ts | 4 +-- .../test/browser/workbenchTestServices.ts | 4 +-- 72 files changed, 266 insertions(+), 266 deletions(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index 00d8814661e..b08d15edc6c 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -105,7 +105,7 @@ export function assertType(condition: unknown, type?: string): asserts condition * * @see {@link assertDefined} for a similar utility that leverages TS assertion functions to narrow down the type of `arg` to be non-nullable. */ -export function assertIsDefined(arg: T | null | undefined): NonNullable { +export function assertReturnsDefined(arg: T | null | undefined): NonNullable { assert( arg !== null && arg !== undefined, 'Argument is `undefined` or `null`.', @@ -137,7 +137,7 @@ export function assertIsDefined(arg: T | null | undefined): NonNullable { * console.log(someValue.length); // now type of `someValue` is `string` * ``` * - * @see {@link assertIsDefined} for a similar utility but without assertion. + * @see {@link assertReturnsDefined} for a similar utility but without assertion. * @see {@link https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions typescript-3-7.html#assertion-functions} */ export function assertDefined(value: T, error: string | NonNullable): asserts value is NonNullable { @@ -151,10 +151,10 @@ export function assertDefined(value: T, error: string | NonNullable): /** * Asserts that each argument passed in is neither undefined nor null. */ -export function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined): [T1, T2]; -export function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined): [T1, T2, T3]; -export function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined, t4: T4 | null | undefined): [T1, T2, T3, T4]; -export function assertAllDefined(...args: (unknown | null | undefined)[]): unknown[] { +export function assertReturnsAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined): [T1, T2]; +export function assertReturnsAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined): [T1, T2, T3]; +export function assertReturnsAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined, t4: T4 | null | undefined): [T1, T2, T3, T4]; +export function assertReturnsAllDefined(...args: (unknown | null | undefined)[]): unknown[] { const result = []; for (let i = 0; i < args.length; i++) { diff --git a/src/vs/base/node/zip.ts b/src/vs/base/node/zip.ts index 8de90376c70..090db2da3f0 100644 --- a/src/vs/base/node/zip.ts +++ b/src/vs/base/node/zip.ts @@ -8,7 +8,7 @@ import { Readable } from 'stream'; import { createCancelablePromise, Sequencer } from '../common/async.js'; import { CancellationToken } from '../common/cancellation.js'; import * as path from '../common/path.js'; -import { assertIsDefined } from '../common/types.js'; +import { assertReturnsDefined } from '../common/types.js'; import { Promises } from './pfs.js'; import * as nls from '../../nls.js'; import type { Entry, ZipFile } from 'yauzl'; @@ -168,7 +168,7 @@ async function openZip(zipFile: string, lazy: boolean = false): Promise if (error) { reject(toExtractError(error)); } else { - resolve(assertIsDefined(zipfile)); + resolve(assertReturnsDefined(zipfile)); } }); }); @@ -180,7 +180,7 @@ function openZipStream(zipFile: ZipFile, entry: Entry): Promise { if (error) { reject(toExtractError(error)); } else { - resolve(assertIsDefined(stream)); + resolve(assertReturnsDefined(stream)); } }); }); diff --git a/src/vs/base/test/common/types.test.ts b/src/vs/base/test/common/types.test.ts index 9b4aa432467..7195c458a57 100644 --- a/src/vs/base/test/common/types.test.ts +++ b/src/vs/base/test/common/types.test.ts @@ -158,18 +158,18 @@ suite('Types', () => { }); test('assertIsDefined / assertAreDefined', () => { - assert.throws(() => types.assertIsDefined(undefined)); - assert.throws(() => types.assertIsDefined(null)); - assert.throws(() => types.assertAllDefined(null, undefined)); - assert.throws(() => types.assertAllDefined(true, undefined)); - assert.throws(() => types.assertAllDefined(undefined, false)); + assert.throws(() => types.assertReturnsDefined(undefined)); + assert.throws(() => types.assertReturnsDefined(null)); + assert.throws(() => types.assertReturnsAllDefined(null, undefined)); + assert.throws(() => types.assertReturnsAllDefined(true, undefined)); + assert.throws(() => types.assertReturnsAllDefined(undefined, false)); - assert.strictEqual(types.assertIsDefined(true), true); - assert.strictEqual(types.assertIsDefined(false), false); - assert.strictEqual(types.assertIsDefined('Hello'), 'Hello'); - assert.strictEqual(types.assertIsDefined(''), ''); + assert.strictEqual(types.assertReturnsDefined(true), true); + assert.strictEqual(types.assertReturnsDefined(false), false); + assert.strictEqual(types.assertReturnsDefined('Hello'), 'Hello'); + assert.strictEqual(types.assertReturnsDefined(''), ''); - const res = types.assertAllDefined(1, true, 'Hello'); + const res = types.assertReturnsAllDefined(1, true, 'Hello'); assert.strictEqual(res[0], 1); assert.strictEqual(res[1], true); assert.strictEqual(res[2], 'Hello'); diff --git a/src/vs/editor/browser/view/domLineBreaksComputer.ts b/src/vs/editor/browser/view/domLineBreaksComputer.ts index 583d7f9cfa0..b2efc74cf9f 100644 --- a/src/vs/editor/browser/view/domLineBreaksComputer.ts +++ b/src/vs/editor/browser/view/domLineBreaksComputer.ts @@ -6,7 +6,7 @@ import { createTrustedTypesPolicy } from '../../../base/browser/trustedTypes.js'; import { CharCode } from '../../../base/common/charCode.js'; import * as strings from '../../../base/common/strings.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { applyFontInfo } from '../config/domFontInfo.js'; import { WrappingIndent } from '../../common/config/editorOptions.js'; import { FontInfo } from '../../common/config/fontInfo.js'; @@ -35,7 +35,7 @@ export class DOMLineBreaksComputerFactory implements ILineBreaksComputerFactory injectedTexts.push(injectedText); }, finalize: () => { - return createLineBreaks(assertIsDefined(this.targetWindow.deref()), requests, fontInfo, tabSize, wrappingColumn, wrappingIndent, wordBreak, injectedTexts); + return createLineBreaks(assertReturnsDefined(this.targetWindow.deref()), requests, fontInfo, tabSize, wrappingColumn, wrappingIndent, wordBreak, injectedTexts); } }; } diff --git a/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts b/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts index ce4565f526f..0a2fd9eda46 100644 --- a/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts +++ b/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts @@ -10,7 +10,7 @@ import { Codicon } from '../../../../../../base/common/codicons.js'; import { Disposable, DisposableStore } from '../../../../../../base/common/lifecycle.js'; import { IObservable, autorun, derived, observableFromEvent, observableValue } from '../../../../../../base/common/observable.js'; import { ThemeIcon } from '../../../../../../base/common/themables.js'; -import { assertIsDefined } from '../../../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../../../base/common/types.js'; import { applyFontInfo } from '../../../../config/domFontInfo.js'; import { CodeEditorWidget } from '../../../codeEditor/codeEditorWidget.js'; import { diffDeleteDecoration, diffRemoveIcon } from '../../registrations.contribution.js'; @@ -239,7 +239,7 @@ export class DiffEditorViewZones extends Disposable { let zoneId: string | undefined = undefined; alignmentViewZonesDisposables.add( new InlineDiffDeletedCodeMargin( - () => assertIsDefined(zoneId), + () => assertReturnsDefined(zoneId), marginDomNode, this._editors.modified, a.diff, diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index e64fb54d32d..97d96df256f 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -38,7 +38,7 @@ import { registerIcon, widgetClose } from '../../../../platform/theme/common/ico import { registerThemingParticipant } from '../../../../platform/theme/common/themeService.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; import { isHighContrast } from '../../../../platform/theme/common/theme.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { defaultInputBoxStyles, defaultToggleStyles } from '../../../../platform/theme/browser/defaultStyles.js'; import { Selection } from '../../../common/core/selection.js'; import { createInstantHoverDelegate, getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js'; @@ -1008,7 +1008,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL icon: findPreviousMatchIcon, hoverDelegate, onTrigger: () => { - assertIsDefined(this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction)).run().then(undefined, onUnexpectedError); + assertReturnsDefined(this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction)).run().then(undefined, onUnexpectedError); } }, this._hoverService)); @@ -1018,7 +1018,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL icon: findNextMatchIcon, hoverDelegate, onTrigger: () => { - assertIsDefined(this._codeEditor.getAction(FIND_IDS.NextMatchFindAction)).run().then(undefined, onUnexpectedError); + assertReturnsDefined(this._codeEditor.getAction(FIND_IDS.NextMatchFindAction)).run().then(undefined, onUnexpectedError); } }, this._hoverService)); diff --git a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts index ef3cd7d78cc..7aa3fac2c6e 100644 --- a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts @@ -11,7 +11,7 @@ import { Event } from '../../../../base/common/event.js'; import { IMarkdownString } from '../../../../base/common/htmlContent.js'; import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js'; import { escapeRegExpCharacters } from '../../../../base/common/strings.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import './parameterHints.css'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from '../../../browser/editorBrowser.js'; import { EDITOR_FONT_DEFAULTS, EditorOption } from '../../../common/config/editorOptions.js'; @@ -282,16 +282,16 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget { } private hasDocs(signature: languages.SignatureInformation, activeParameter: languages.ParameterInformation | undefined): boolean { - if (activeParameter && typeof activeParameter.documentation === 'string' && assertIsDefined(activeParameter.documentation).length > 0) { + if (activeParameter && typeof activeParameter.documentation === 'string' && assertReturnsDefined(activeParameter.documentation).length > 0) { return true; } - if (activeParameter && typeof activeParameter.documentation === 'object' && assertIsDefined(activeParameter.documentation).value.length > 0) { + if (activeParameter && typeof activeParameter.documentation === 'object' && assertReturnsDefined(activeParameter.documentation).value.length > 0) { return true; } - if (signature.documentation && typeof signature.documentation === 'string' && assertIsDefined(signature.documentation).length > 0) { + if (signature.documentation && typeof signature.documentation === 'string' && assertReturnsDefined(signature.documentation).length > 0) { return true; } - if (signature.documentation && typeof signature.documentation === 'object' && assertIsDefined(signature.documentation.value).length > 0) { + if (signature.documentation && typeof signature.documentation === 'object' && assertReturnsDefined(signature.documentation.value).length > 0) { return true; } return false; diff --git a/src/vs/platform/diagnostics/electron-main/diagnosticsMainService.ts b/src/vs/platform/diagnostics/electron-main/diagnosticsMainService.ts index 6a9e1fc437a..72e9060db8c 100644 --- a/src/vs/platform/diagnostics/electron-main/diagnosticsMainService.ts +++ b/src/vs/platform/diagnostics/electron-main/diagnosticsMainService.ts @@ -13,7 +13,7 @@ import { ICodeWindow } from '../../window/electron-main/window.js'; import { getAllWindowsExcludingOffscreen, IWindowsMainService } from '../../windows/electron-main/windows.js'; import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from '../../workspace/common/workspace.js'; import { IWorkspacesManagementMainService } from '../../workspaces/electron-main/workspacesManagementMainService.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { ILogService } from '../../log/common/log.js'; import { UtilityProcess } from '../../utilityProcess/electron-main/utilityProcess.js'; @@ -106,7 +106,7 @@ export class DiagnosticsMainService implements IDiagnosticsMainService { private async codeWindowToInfo(window: ICodeWindow): Promise { const folderURIs = await this.getFolderURIs(window); - const win = assertIsDefined(window.win); + const win = assertReturnsDefined(window.win); return this.browserWindowToInfo(win, folderURIs, window.remoteAuthority); } diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts index 4912966c79c..30456f29d99 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts @@ -10,7 +10,7 @@ import { Emitter, Event } from '../../../base/common/event.js'; import { Disposable, DisposableStore } from '../../../base/common/lifecycle.js'; import { isMacintosh, isWindows } from '../../../base/common/platform.js'; import { cwd } from '../../../base/common/process.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { NativeParsedArgs } from '../../environment/common/argv.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; import { ILogService } from '../../log/common/log.js'; @@ -428,7 +428,7 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe windowListeners.add(window.onWillLoad(e => this._onWillLoadWindow.fire({ window, workspace: e.workspace, reason: e.reason }))); // Window Before Closing: Main -> Renderer - const win = assertIsDefined(window.win); + const win = assertReturnsDefined(window.win); windowListeners.add(Event.fromNodeEventEmitter(win, 'close')(e => { // The window already acknowledged to be closed @@ -478,7 +478,7 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe } registerAuxWindow(auxWindow: IAuxiliaryWindow): void { - const win = assertIsDefined(auxWindow.win); + const win = assertReturnsDefined(auxWindow.win); const windowListeners = new DisposableStore(); windowListeners.add(Event.fromNodeEventEmitter(win, 'close')(e => { diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 324779023c3..a9b7f5a4e47 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -17,7 +17,7 @@ import { ILoggerMainService } from '../../log/electron-main/loggerService.js'; import { UtilityProcess } from '../../utilityProcess/electron-main/utilityProcess.js'; import { NullTelemetryService } from '../../telemetry/common/telemetryUtils.js'; import { parseSharedProcessDebugPort } from '../../environment/node/environmentService.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { SharedProcessChannelConnection, SharedProcessRawConnection, SharedProcessLifecycle } from '../common/sharedProcess.js'; import { Emitter } from '../../../base/common/event.js'; @@ -202,7 +202,7 @@ export class SharedProcess extends Disposable { await this.whenIpcReady; // Connect and return message port - const utilityProcess = assertIsDefined(this.utilityProcess); + const utilityProcess = assertReturnsDefined(this.utilityProcess); return utilityProcess.connect(payload); } } diff --git a/src/vs/platform/userDataSync/common/extensionsMerge.ts b/src/vs/platform/userDataSync/common/extensionsMerge.ts index f3eeaba274c..0057aa793ac 100644 --- a/src/vs/platform/userDataSync/common/extensionsMerge.ts +++ b/src/vs/platform/userDataSync/common/extensionsMerge.ts @@ -6,7 +6,7 @@ import { IStringDictionary } from '../../../base/common/collections.js'; import { deepClone, equals } from '../../../base/common/objects.js'; import * as semver from '../../../base/common/semver/semver.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { IExtensionIdentifier } from '../../extensions/common/extensions.js'; import { ILocalSyncExtension, IRemoteSyncExtension, ISyncExtension } from './userDataSync.js'; @@ -118,7 +118,7 @@ export function merge(localExtensions: ILocalSyncExtension[], remoteExtensions: continue; } - const baseExtension = assertIsDefined(lastSyncExtensionsMap?.get(key)); + const baseExtension = assertReturnsDefined(lastSyncExtensionsMap?.get(key)); const wasAnInstalledExtensionDuringLastSync = lastSyncBuiltinExtensionsSet && !lastSyncBuiltinExtensionsSet.has(key) && baseExtension.installed; if (localExtension.installed && wasAnInstalledExtensionDuringLastSync /* It is an installed extension now and during last sync */) { // Installed extension is removed from remote. Remove it from local. @@ -132,7 +132,7 @@ export function merge(localExtensions: ILocalSyncExtension[], remoteExtensions: // Remotely added extension => does not exist in base and exist in remote for (const key of baseToRemote.added.values()) { - const remoteExtension = assertIsDefined(remoteExtensionsMap.get(key)); + const remoteExtension = assertReturnsDefined(remoteExtensionsMap.get(key)); const localExtension = localExtensionsMap.get(key); // Also exist in local @@ -156,8 +156,8 @@ export function merge(localExtensions: ILocalSyncExtension[], remoteExtensions: // Remotely updated extension => exist in base and remote for (const key of baseToRemote.updated.values()) { - const remoteExtension = assertIsDefined(remoteExtensionsMap.get(key)); - const baseExtension = assertIsDefined(lastSyncExtensionsMap?.get(key)); + const remoteExtension = assertReturnsDefined(remoteExtensionsMap.get(key)); + const baseExtension = assertReturnsDefined(lastSyncExtensionsMap?.get(key)); const localExtension = localExtensionsMap.get(key); // Also exist in local @@ -186,7 +186,7 @@ export function merge(localExtensions: ILocalSyncExtension[], remoteExtensions: if (baseToRemote.added.has(key)) { continue; } - newRemoteExtensionsMap.set(key, assertIsDefined(localExtensionsMap.get(key))); + newRemoteExtensionsMap.set(key, assertReturnsDefined(localExtensionsMap.get(key))); } // Locally updated extension => exist in base and local @@ -199,8 +199,8 @@ export function merge(localExtensions: ILocalSyncExtension[], remoteExtensions: if (baseToRemote.updated.has(key)) { continue; } - const localExtension = assertIsDefined(localExtensionsMap.get(key)); - const remoteExtension = assertIsDefined(remoteExtensionsMap.get(key)); + const localExtension = assertReturnsDefined(localExtensionsMap.get(key)); + const remoteExtension = assertReturnsDefined(remoteExtensionsMap.get(key)); // Update remotely newRemoteExtensionsMap.set(key, merge(key, localExtension, remoteExtension, localExtension)); } @@ -220,7 +220,7 @@ export function merge(localExtensions: ILocalSyncExtension[], remoteExtensions: continue; } // Skip if it is a builtin extension - if (!assertIsDefined(remoteExtensionsMap.get(key)).installed) { + if (!assertReturnsDefined(remoteExtensionsMap.get(key)).installed) { continue; } // Skip if last sync builtin extensions set is not available @@ -228,7 +228,7 @@ export function merge(localExtensions: ILocalSyncExtension[], remoteExtensions: continue; } // Skip if it was a builtin extension during last sync - if (lastSyncBuiltinExtensionsSet.has(key) || !assertIsDefined(lastSyncExtensionsMap?.get(key)).installed) { + if (lastSyncBuiltinExtensionsSet.has(key) || !assertReturnsDefined(lastSyncExtensionsMap?.get(key)).installed) { continue; } newRemoteExtensionsMap.delete(key); diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index 594b8364353..6b9748620c9 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -20,7 +20,7 @@ import { getMarks, mark } from '../../../base/common/performance.js'; import { IProcessEnvironment, isMacintosh, isWindows, OS } from '../../../base/common/platform.js'; import { cwd } from '../../../base/common/process.js'; import { extUriBiasedIgnorePathCase, isEqualAuthority, normalizePath, originalFSPath, removeTrailingPathSeparator } from '../../../base/common/resources.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { URI } from '../../../base/common/uri.js'; import { getNLSLanguage, getNLSMessages, localize } from '../../../nls.js'; import { IBackupMainService } from '../../backup/electron-main/backup.js'; @@ -1555,7 +1555,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic disposables.add(createdWindow.onDidLeaveFullScreen(() => this._onDidChangeFullScreen.fire({ window: createdWindow, fullscreen: false }))); disposables.add(createdWindow.onDidTriggerSystemContextMenu(({ x, y }) => this._onDidTriggerSystemContextMenu.fire({ window: createdWindow, x, y }))); - const webContents = assertIsDefined(createdWindow.win?.webContents); + const webContents = assertReturnsDefined(createdWindow.win?.webContents); webContents.removeAllListeners('devtools-reload-page'); // remove built in listener so we can handle this on our own disposables.add(Event.fromNodeEventEmitter(webContents, 'devtools-reload-page')(() => this.lifecycleMainService.reload(createdWindow))); diff --git a/src/vs/workbench/api/common/extHostDocuments.ts b/src/vs/workbench/api/common/extHostDocuments.ts index 4e7dd522c51..bbf8b4200c7 100644 --- a/src/vs/workbench/api/common/extHostDocuments.ts +++ b/src/vs/workbench/api/common/extHostDocuments.ts @@ -12,7 +12,7 @@ import { ExtHostDocumentData, setWordDefinitionFor } from './extHostDocumentData import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors.js'; import * as TypeConverters from './extHostTypeConverters.js'; import type * as vscode from 'vscode'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { deepFreeze } from '../../../base/common/objects.js'; import { TextDocumentChangeReason } from './extHostTypes.js'; @@ -88,7 +88,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape { promise = this._proxy.$tryOpenDocument(uri, options).then(uriData => { this._documentLoader.delete(uri.toString()); const canonicalUri = URI.revive(uriData); - return assertIsDefined(this._documentsAndEditors.getDocument(canonicalUri)); + return assertReturnsDefined(this._documentsAndEditors.getDocument(canonicalUri)); }, err => { this._documentLoader.delete(uri.toString()); return Promise.reject(err); diff --git a/src/vs/workbench/api/common/extHostEditorTabs.ts b/src/vs/workbench/api/common/extHostEditorTabs.ts index 592c75c4bae..cabc7c37ac3 100644 --- a/src/vs/workbench/api/common/extHostEditorTabs.ts +++ b/src/vs/workbench/api/common/extHostEditorTabs.ts @@ -5,7 +5,7 @@ import { diffSets } from '../../../base/common/collections.js'; import { Emitter } from '../../../base/common/event.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { URI } from '../../../base/common/uri.js'; import { createDecorator } from '../../../platform/instantiation/common/instantiation.js'; import { IEditorTabDto, IEditorTabGroupDto, IExtHostEditorTabsShape, MainContext, MainThreadEditorTabsShape, TabInputKind, TabModelOperationKind, TabOperation } from './extHost.protocol.js'; @@ -248,7 +248,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { }, get activeTabGroup() { const activeTabGroupId = that._activeGroupId; - const activeTabGroup = assertIsDefined(that._extHostTabGroups.find(candidate => candidate.groupId === activeTabGroupId)?.apiObject); + const activeTabGroup = assertReturnsDefined(that._extHostTabGroups.find(candidate => candidate.groupId === activeTabGroupId)?.apiObject); return activeTabGroup; }, close: async (tabOrTabGroup: vscode.Tab | readonly vscode.Tab[] | vscode.TabGroup | readonly vscode.TabGroup[], preserveFocus?: boolean) => { @@ -300,7 +300,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { }); // Set the active tab group id - const activeTabGroupId = assertIsDefined(tabGroups.find(group => group.isActive === true)?.groupId); + const activeTabGroupId = assertReturnsDefined(tabGroups.find(group => group.isActive === true)?.groupId); if (activeTabGroupId !== undefined && this._activeGroupId !== activeTabGroupId) { this._activeGroupId = activeTabGroupId; } diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 75b64857223..a4e75dc114f 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -12,7 +12,7 @@ import { DisposableStore, IDisposable, toDisposable } from '../../../base/common import { ResourceMap, ResourceSet } from '../../../base/common/map.js'; import { MarshalledId } from '../../../base/common/marshallingIds.js'; import { isFalsyOrWhitespace } from '../../../base/common/strings.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { URI, UriComponents } from '../../../base/common/uri.js'; import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js'; import * as files from '../../../platform/files/common/files.js'; @@ -200,7 +200,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { } const canonicalUri = await this._notebookDocumentsProxy.$tryOpenNotebook(uri); const document = this._documents.get(URI.revive(canonicalUri)); - return assertIsDefined(document?.apiNotebook); + return assertReturnsDefined(document?.apiNotebook); } async showNotebookDocument(notebook: vscode.NotebookDocument, options?: vscode.NotebookDocumentShowOptions): Promise { diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index 8be1325c257..d4c3a8b56d5 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -13,7 +13,7 @@ import { IConstructorSignature, IInstantiationService } from '../../platform/ins import { trackFocus, Dimension, IDomPosition } from '../../base/browser/dom.js'; import { IStorageService } from '../../platform/storage/common/storage.js'; import { Disposable } from '../../base/common/lifecycle.js'; -import { assertIsDefined } from '../../base/common/types.js'; +import { assertReturnsDefined } from '../../base/common/types.js'; import { IActionViewItem } from '../../base/browser/ui/actionbar/actionbar.js'; import { MenuId } from '../../platform/actions/common/actions.js'; import { IBoundarySashes } from '../../base/browser/ui/sash/sash.js'; @@ -60,7 +60,7 @@ export abstract class Composite extends Component implements IComposite { } private registerFocusTrackEvents(): { onDidFocus: Emitter; onDidBlur: Emitter } { - const container = assertIsDefined(this.getContainer()); + const container = assertReturnsDefined(this.getContainer()); const focusTracker = this._register(trackFocus(container)); const onDidFocus = this._onDidFocus = this._register(new Emitter()); diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 208a96a34ef..bee05148c77 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -30,7 +30,7 @@ import { IStatusbarService } from '../services/statusbar/browser/statusbar.js'; import { IFileService } from '../../platform/files/common/files.js'; import { isCodeEditor } from '../../editor/browser/editorBrowser.js'; import { coalesce } from '../../base/common/arrays.js'; -import { assertIsDefined } from '../../base/common/types.js'; +import { assertReturnsDefined } from '../../base/common/types.js'; import { INotificationService, NotificationsFilter } from '../../platform/notification/common/notification.js'; import { IThemeService } from '../../platform/theme/common/themeService.js'; import { WINDOW_ACTIVE_BORDER, WINDOW_INACTIVE_BORDER } from '../common/theme.js'; @@ -556,9 +556,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.stateModel.setRuntimeValue(LayoutStateKeys.SIDEBAR_POSITON, position); // Adjust CSS - const activityBarContainer = assertIsDefined(activityBar.getContainer()); - const sideBarContainer = assertIsDefined(sideBar.getContainer()); - const auxiliaryBarContainer = assertIsDefined(auxiliaryBar.getContainer()); + const activityBarContainer = assertReturnsDefined(activityBar.getContainer()); + const sideBarContainer = assertReturnsDefined(sideBar.getContainer()); + const auxiliaryBarContainer = assertReturnsDefined(auxiliaryBar.getContainer()); activityBarContainer.classList.remove(oldPositionValue); sideBarContainer.classList.remove(oldPositionValue); activityBarContainer.classList.add(newPositionValue); @@ -2137,7 +2137,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const newPositionValue = positionToString(position); // Adjust CSS - const panelContainer = assertIsDefined(panelPart.getContainer()); + const panelContainer = assertReturnsDefined(panelPart.getContainer()); panelContainer.classList.remove(oldPositionValue); panelContainer.classList.add(newPositionValue); diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index e85aac5c3cf..cd1bdc2eec0 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -11,7 +11,7 @@ import { IStorageService } from '../../platform/storage/common/storage.js'; import { ISerializableView, IViewSize } from '../../base/browser/ui/grid/grid.js'; import { Event, Emitter } from '../../base/common/event.js'; import { IWorkbenchLayoutService } from '../services/layout/browser/layoutService.js'; -import { assertIsDefined } from '../../base/common/types.js'; +import { assertReturnsDefined } from '../../base/common/types.js'; import { IDisposable, toDisposable } from '../../base/common/lifecycle.js'; export interface IPartOptions { @@ -194,7 +194,7 @@ export abstract class Part extends Component implements ISerializableView { * Layout title and content area in the given dimension. */ protected layoutContents(width: number, height: number): ILayoutContentResult { - const partLayout = assertIsDefined(this.partLayout); + const partLayout = assertReturnsDefined(this.partLayout); return partLayout.layout(width, height); } diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index e2726d823d5..080b6871061 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -16,7 +16,7 @@ import { IThemeService, IColorTheme, registerThemingParticipant } from '../../.. import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER } from '../../../common/theme.js'; import { activeContrastBorder, contrastBorder, focusBorder } from '../../../../platform/theme/common/colorRegistry.js'; import { addDisposableListener, append, EventType, isAncestor, $, clearNode } from '../../../../base/browser/dom.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { CustomMenubarControl } from '../titlebar/menubarControl.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { getMenuBarVisibility, MenuSettings } from '../../../../platform/window/common/window.js'; @@ -129,7 +129,7 @@ export class ActivitybarPart extends Part { override updateStyles(): void { super.updateStyles(); - const container = assertIsDefined(this.getContainer()); + const container = assertReturnsDefined(this.getContainer()); const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || ''; container.style.backgroundColor = background; @@ -281,7 +281,7 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { this.menuBarContainer = $('.menubar'); - const content = assertIsDefined(this.element); + const content = assertReturnsDefined(this.element); content.prepend(this.menuBarContainer); // Menubar: install a custom menu bar depending on configuration diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts index 75a3ce42d68..be4e9e74042 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts @@ -21,7 +21,7 @@ import { ActivityBarPosition, IWorkbenchLayoutService, LayoutSettings, Parts, Po import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js'; import { IAction, Separator, SubmenuAction, toAction } from '../../../../base/common/actions.js'; import { ToggleAuxiliaryBarAction } from './auxiliaryBarActions.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { LayoutPriority } from '../../../../base/browser/ui/splitview/splitview.js'; import { ToggleSidebarPositionAction } from '../../actions/layoutActions.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; @@ -159,7 +159,7 @@ export class AuxiliaryBarPart extends AbstractPaneCompositePart { override updateStyles(): void { super.updateStyles(); - const container = assertIsDefined(this.getContainer()); + const container = assertReturnsDefined(this.getContainer()); container.style.backgroundColor = this.getColor(SIDE_BAR_BACKGROUND) || ''; const borderColor = this.getColor(SIDE_BAR_BORDER) || this.getColor(contrastBorder); const isPositionLeft = this.layoutService.getSideBarPosition() === Position.RIGHT; diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 32335eb82c3..099641bd5e3 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -26,7 +26,7 @@ import { IThemeService } from '../../../platform/theme/common/themeService.js'; import { INotificationService } from '../../../platform/notification/common/notification.js'; import { Dimension, append, $, hide, show } from '../../../base/browser/dom.js'; import { AnchorAlignment } from '../../../base/browser/ui/contextview/contextview.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { createActionViewItem } from '../../../platform/actions/browser/menuEntryActionViewItem.js'; import { AbstractProgressScope, ScopedProgressIndicator } from '../../services/progress/browser/progressIndicator.js'; import { WorkbenchToolBar } from '../../../platform/actions/browser/toolbar.js'; @@ -181,7 +181,7 @@ export abstract class CompositePart extends Part { const compositeDescriptor = this.registry.getComposite(id); if (compositeDescriptor) { const that = this; - const compositeProgressIndicator = new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope { + const compositeProgressIndicator = new ScopedProgressIndicator(assertReturnsDefined(this.progressBar), new class extends AbstractProgressScope { constructor() { super(compositeDescriptor!.id, !!isActive); this._register(that.onDidCompositeOpen.event(e => this.onScopeOpened(e.composite.getId()))); @@ -252,7 +252,7 @@ export abstract class CompositePart extends Part { show(compositeContainer); // Setup action runner - const toolBar = assertIsDefined(this.toolBar); + const toolBar = assertReturnsDefined(this.toolBar); toolBar.actionRunner = composite.getActionRunner(); // Update title with composite title if it differs from descriptor @@ -333,7 +333,7 @@ export abstract class CompositePart extends Part { this.titleLabel.updateTitle(compositeId, compositeTitle, keybinding?.getLabel() ?? undefined); - const toolBar = assertIsDefined(this.toolBar); + const toolBar = assertReturnsDefined(this.toolBar); toolBar.setAriaLabel(localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle)); } @@ -345,7 +345,7 @@ export abstract class CompositePart extends Part { const secondaryActions: IAction[] = composite?.getSecondaryActions().slice(0) || []; // Update context - const toolBar = assertIsDefined(this.toolBar); + const toolBar = assertReturnsDefined(this.toolBar); toolBar.context = this.actionsContextProvider(); // Return fn to set into toolbar @@ -455,7 +455,7 @@ export abstract class CompositePart extends Part { super.updateStyles(); // Forward to title label - const titleLabel = assertIsDefined(this.titleLabel); + const titleLabel = assertReturnsDefined(this.titleLabel); titleLabel.updateStyles(); } diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 9f0b51ba1c2..f604df1d0fe 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -10,7 +10,7 @@ import { renderFormattedText } from '../../../../base/browser/formattedTextRende import { RunOnceScheduler } from '../../../../base/common/async.js'; import { toDisposable } from '../../../../base/common/lifecycle.js'; import { isMacintosh, isWeb } from '../../../../base/common/platform.js'; -import { assertAllDefined, assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsAllDefined, assertReturnsDefined } from '../../../../base/common/types.js'; import { localize } from '../../../../nls.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; @@ -113,7 +113,7 @@ class DropOverlay extends Themable { } override updateStyles(): void { - const overlay = assertIsDefined(this.overlay); + const overlay = assertReturnsDefined(this.overlay); // Overlay drop background overlay.style.backgroundColor = this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND) || ''; @@ -492,7 +492,7 @@ class DropOverlay extends Themable { } // Make sure the overlay is visible now - const overlay = assertIsDefined(this.overlay); + const overlay = assertReturnsDefined(this.overlay); overlay.style.opacity = '1'; // Enable transition after a timeout to prevent initial animation @@ -503,7 +503,7 @@ class DropOverlay extends Themable { } private doPositionOverlay(options: { top: string; left: string; width: string; height: string }): void { - const [container, overlay] = assertAllDefined(this.container, this.overlay); + const [container, overlay] = assertReturnsAllDefined(this.container, this.overlay); // Container const offsetHeight = this.getOverlayOffsetHeight(); @@ -532,7 +532,7 @@ class DropOverlay extends Themable { } private hideOverlay(): void { - const overlay = assertIsDefined(this.overlay); + const overlay = assertReturnsDefined(this.overlay); // Reset overlay this.doPositionOverlay({ top: '0', left: '0', width: '100%', height: '100%' }); diff --git a/src/vs/workbench/browser/parts/editor/editorPanes.ts b/src/vs/workbench/browser/parts/editor/editorPanes.ts index af5df2dd0b0..85ba667b681 100644 --- a/src/vs/workbench/browser/parts/editor/editorPanes.ts +++ b/src/vs/workbench/browser/parts/editor/editorPanes.ts @@ -18,7 +18,7 @@ import { EditorPane } from './editorPane.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { IEditorProgressService, LongRunningOperation } from '../../../../platform/progress/common/progress.js'; import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS, IInternalEditorOpenOptions } from './editor.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IWorkspaceTrustManagementService } from '../../../../platform/workspace/common/workspaceTrust.js'; import { ErrorPlaceholderEditor, IErrorEditorPlaceholderOptions, WorkspaceTrustRequiredPlaceholderEditor } from './editorPlaceholder.js'; import { EditorOpenSource, IEditorOptions } from '../../../../platform/editor/common/editor.js'; @@ -317,7 +317,7 @@ export class EditorPanes extends Disposable { return WorkspaceTrustRequiredPlaceholderEditor.DESCRIPTOR; } - return assertIsDefined(this.editorPanesRegistry.getEditorPane(editor)); + return assertReturnsDefined(this.editorPanesRegistry.getEditorPane(editor)); } private doShowEditorPane(descriptor: IEditorPaneDescriptor): EditorPane { @@ -337,7 +337,7 @@ export class EditorPanes extends Disposable { this.doSetActiveEditorPane(editorPane); // Show editor - const container = assertIsDefined(editorPane.getContainer()); + const container = assertReturnsDefined(editorPane.getContainer()); this.editorPanesParent.appendChild(container); show(container); diff --git a/src/vs/workbench/browser/parts/editor/editorPlaceholder.ts b/src/vs/workbench/browser/parts/editor/editorPlaceholder.ts index 4b3ef8b4dc7..06c253a9186 100644 --- a/src/vs/workbench/browser/parts/editor/editorPlaceholder.ts +++ b/src/vs/workbench/browser/parts/editor/editorPlaceholder.ts @@ -18,7 +18,7 @@ import { Dimension, size, clearNode, $, EventHelper } from '../../../../base/bro import { CancellationToken } from '../../../../base/common/cancellation.js'; import { DisposableStore, IDisposable, MutableDisposable } from '../../../../base/common/lifecycle.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; -import { assertAllDefined } from '../../../../base/common/types.js'; +import { assertReturnsAllDefined } from '../../../../base/common/types.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { IWorkspaceContextService, isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier } from '../../../../platform/workspace/common/workspace.js'; import { EditorOpenSource, IEditorOptions } from '../../../../platform/editor/common/editor.js'; @@ -90,7 +90,7 @@ export abstract class EditorPlaceholder extends EditorPane { } private async renderInput(input: EditorInput, options: IEditorOptions | undefined): Promise { - const [container, scrollbar] = assertAllDefined(this.container, this.scrollbar); + const [container, scrollbar] = assertReturnsAllDefined(this.container, this.scrollbar); // Reset any previous contents clearNode(container); @@ -155,7 +155,7 @@ export abstract class EditorPlaceholder extends EditorPane { } layout(dimension: Dimension): void { - const [container, scrollbar] = assertAllDefined(this.container, this.scrollbar); + const [container, scrollbar] = assertReturnsAllDefined(this.container, this.scrollbar); // Pass on to Container size(container, dimension.width, dimension.height); diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 52c6462f761..6170eb89808 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -8,7 +8,7 @@ import { localize, localize2 } from '../../../../nls.js'; import { getWindowById, runAtThisOrScheduleAtNextAnimationFrame } from '../../../../base/browser/dom.js'; import { format, compare, splitLines } from '../../../../base/common/strings.js'; import { extname, basename, isEqual } from '../../../../base/common/resources.js'; -import { areFunctions, assertIsDefined } from '../../../../base/common/types.js'; +import { areFunctions, assertReturnsDefined } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { Action } from '../../../../base/common/actions.js'; import { Language } from '../../../../base/common/platform.js'; @@ -412,13 +412,13 @@ class EditorStatus extends Disposable { } const picks: QuickPickInput[] = [ - assertIsDefined(activeTextEditorControl.getAction(IndentUsingSpaces.ID)), - assertIsDefined(activeTextEditorControl.getAction(IndentUsingTabs.ID)), - assertIsDefined(activeTextEditorControl.getAction(ChangeTabDisplaySize.ID)), - assertIsDefined(activeTextEditorControl.getAction(DetectIndentation.ID)), - assertIsDefined(activeTextEditorControl.getAction(IndentationToSpacesAction.ID)), - assertIsDefined(activeTextEditorControl.getAction(IndentationToTabsAction.ID)), - assertIsDefined(activeTextEditorControl.getAction(TrimTrailingWhitespaceAction.ID)) + assertReturnsDefined(activeTextEditorControl.getAction(IndentUsingSpaces.ID)), + assertReturnsDefined(activeTextEditorControl.getAction(IndentUsingTabs.ID)), + assertReturnsDefined(activeTextEditorControl.getAction(ChangeTabDisplaySize.ID)), + assertReturnsDefined(activeTextEditorControl.getAction(DetectIndentation.ID)), + assertReturnsDefined(activeTextEditorControl.getAction(IndentationToSpacesAction.ID)), + assertReturnsDefined(activeTextEditorControl.getAction(IndentationToTabsAction.ID)), + assertReturnsDefined(activeTextEditorControl.getAction(TrimTrailingWhitespaceAction.ID)) ].map((a: IEditorAction) => { return { id: a.id, diff --git a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts index 4d4573776a7..b0a44e2c23a 100644 --- a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts @@ -28,7 +28,7 @@ import { IEditorCommandsContext, EditorResourceAccessor, IEditorPartOptions, Sid import { EditorInput } from '../../../common/editor/editorInput.js'; import { ResourceContextKey, ActiveEditorPinnedContext, ActiveEditorStickyContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, ActiveEditorFirstInGroupContext, ActiveEditorAvailableEditorIdsContext, applyAvailableEditorIds, ActiveEditorLastInGroupContext } from '../../../common/contextkeys.js'; import { AnchorAlignment } from '../../../../base/browser/ui/contextview/contextview.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { isFirefox } from '../../../../base/browser/browser.js'; import { isCancellationError } from '../../../../base/common/errors.js'; import { SideBySideEditorInput } from '../../../common/editor/sideBySideEditorInput.js'; @@ -260,7 +260,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC const editorActions = this.groupView.createEditorActions(this.editorActionsDisposables); this.editorActionsDisposables.add(editorActions.onDidChange(() => this.updateEditorActionsToolbar())); - const editorActionsToolbar = assertIsDefined(this.editorActionsToolbar); + const editorActionsToolbar = assertReturnsDefined(this.editorActionsToolbar); const { primary, secondary } = this.prepareEditorActions(editorActions.actions); editorActionsToolbar.setActions(prepareActions(primary), prepareActions(secondary)); } @@ -275,7 +275,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC return; } - const editorActionsToolbar = assertIsDefined(this.editorActionsToolbar); + const editorActionsToolbar = assertReturnsDefined(this.editorActionsToolbar); editorActionsToolbar.setActions([], []); } diff --git a/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts b/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts index 88f8e4f9842..9a978f7f848 100644 --- a/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts @@ -36,7 +36,7 @@ import { addDisposableListener, EventType, EventHelper, Dimension, scheduleAtNex import { localize } from '../../../../nls.js'; import { IEditorGroupsView, EditorServiceImpl, IEditorGroupView, IInternalEditorOpenOptions, IEditorPartsView, prepareMoveCopyEditors } from './editor.js'; import { CloseEditorTabAction, UnpinEditorAction } from './editorActions.js'; -import { assertAllDefined, assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsAllDefined, assertReturnsDefined } from '../../../../base/common/types.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { basenameOrAuthority } from '../../../../base/common/resources.js'; import { RunOnceScheduler } from '../../../../base/common/async.js'; @@ -224,7 +224,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { } private updateTabSizing(fromEvent: boolean): void { - const [tabsContainer, tabSizingFixedDisposables] = assertAllDefined(this.tabsContainer, this.tabSizingFixedDisposables); + const [tabsContainer, tabSizingFixedDisposables] = assertReturnsAllDefined(this.tabsContainer, this.tabSizingFixedDisposables); tabSizingFixedDisposables.clear(); @@ -505,7 +505,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { this.updateTabsControlVisibility(); // Create tabs as needed - const [tabsContainer, tabsScrollbar] = assertAllDefined(this.tabsContainer, this.tabsScrollbar); + const [tabsContainer, tabsScrollbar] = assertReturnsAllDefined(this.tabsContainer, this.tabsScrollbar); for (let i = tabsContainer.children.length; i < this.tabsModel.count; i++) { tabsContainer.appendChild(this.createTab(i, tabsContainer, tabsScrollbar)); } @@ -592,7 +592,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { if (this.tabsModel.count) { // Remove tabs that got closed - const tabsContainer = assertIsDefined(this.tabsContainer); + const tabsContainer = assertReturnsDefined(this.tabsContainer); while (tabsContainer.children.length > this.tabsModel.count) { // Remove one tab from container (must be the last to keep indexes in order!) @@ -788,7 +788,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { } private doWithTab(tabIndex: number, editor: EditorInput, fn: (editor: EditorInput, tabIndex: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel, tabActionBar: ActionBar) => void): void { - const tabsContainer = assertIsDefined(this.tabsContainer); + const tabsContainer = assertReturnsDefined(this.tabsContainer); const tabContainer = tabsContainer.children[tabIndex] as HTMLElement; const tabResourceLabel = this.tabResourceLabels.get(tabIndex); const tabLabel = this.tabLabels[tabIndex]; @@ -857,7 +857,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { // Given a `tabIndex` that is relative to the tabs model // returns the `editorIndex` relative to the entire group - const editor = assertIsDefined(this.tabsModel.getEditorByIndex(tabIndex)); + const editor = assertReturnsDefined(this.tabsModel.getEditorByIndex(tabIndex)); return this.groupView.getIndexOfEditor(editor); } @@ -891,7 +891,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { anchor = this.lastSingleSelectSelectedEditor; } else { // The active editor is the anchor - const activeEditor = assertIsDefined(this.groupView.activeEditor); + const activeEditor = assertReturnsDefined(this.groupView.activeEditor); this.lastSingleSelectSelectedEditor = activeEditor; anchor = activeEditor; } @@ -1331,7 +1331,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { return; } - let newActiveEditor = assertIsDefined(this.groupView.activeEditor); + let newActiveEditor = assertReturnsDefined(this.groupView.activeEditor); // If active editor is bing unselected then find the most recently opened selected editor // that is not the editor being unselected @@ -1352,7 +1352,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { private async unselectAllEditors(): Promise { if (this.groupView.selectedEditors.length > 1) { - const activeEditor = assertIsDefined(this.groupView.activeEditor); + const activeEditor = assertReturnsDefined(this.groupView.activeEditor); await this.groupView.setSelection(activeEditor, []); } } @@ -1845,7 +1845,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { } private doLayoutTabsWrapping(dimensions: IEditorTitleControlDimensions): boolean { - const [tabsAndActionsContainer, tabsContainer, editorToolbarContainer, tabsScrollbar] = assertAllDefined(this.tabsAndActionsContainer, this.tabsContainer, this.editorActionsToolbarContainer, this.tabsScrollbar); + const [tabsAndActionsContainer, tabsContainer, editorToolbarContainer, tabsScrollbar] = assertReturnsAllDefined(this.tabsAndActionsContainer, this.tabsContainer, this.editorActionsToolbarContainer, this.tabsScrollbar); // Handle wrapping tabs according to setting: // - enabled: only add class if tabs wrap and don't exceed available dimensions @@ -1979,7 +1979,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { } private doLayoutTabsNonWrapping(options?: IMultiEditorTabsControlLayoutOptions): void { - const [tabsContainer, tabsScrollbar] = assertAllDefined(this.tabsContainer, this.tabsScrollbar); + const [tabsContainer, tabsScrollbar] = assertReturnsAllDefined(this.tabsContainer, this.tabsScrollbar); // // Synopsis @@ -2123,7 +2123,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { } private updateTabsControlVisibility(): void { - const tabsAndActionsContainer = assertIsDefined(this.tabsAndActionsContainer); + const tabsAndActionsContainer = assertReturnsDefined(this.tabsAndActionsContainer); tabsAndActionsContainer.classList.toggle('empty', !this.visible); // Reset dimensions if hidden @@ -2148,7 +2148,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { private getTabAtIndex(tabIndex: number): HTMLElement | undefined { if (tabIndex >= 0) { - const tabsContainer = assertIsDefined(this.tabsContainer); + const tabsContainer = assertReturnsDefined(this.tabsContainer); return tabsContainer.children[tabIndex] as HTMLElement | undefined; } diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 691a716cba6..640c0b8bfe8 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -20,7 +20,7 @@ import { IEditorGroup, IEditorGroupsService } from '../../../services/editor/com import { SplitView, Sizing, Orientation } from '../../../../base/browser/ui/splitview/splitview.js'; import { Event, Relay, Emitter } from '../../../../base/common/event.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IEditorOptions } from '../../../../platform/editor/common/editor.js'; import { IConfigurationChangeEvent, IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { DEFAULT_EDITOR_MIN_DIMENSIONS } from './editor.js'; @@ -157,7 +157,7 @@ export class SideBySideEditor extends AbstractEditorWithViewState this.layoutPane(this.secondaryEditorPane, size), @@ -238,7 +238,7 @@ export class SideBySideEditor extends AbstractEditorWithViewState this.layoutPane(this.primaryEditorPane, size), @@ -328,8 +328,8 @@ export class SideBySideEditor extends AbstractEditorWithViewState { - const titleContainer = assertIsDefined(this.titleContainer); + const titleContainer = assertReturnsDefined(this.titleContainer); // Signal dirty (unless saving) if (editor.isDirty() && !editor.isSaving()) { @@ -224,7 +224,7 @@ export class SingleEditorTabsControl extends EditorTabsControl { } protected handleBreadcrumbsEnablementChange(): void { - const titleContainer = assertIsDefined(this.titleContainer); + const titleContainer = assertReturnsDefined(this.titleContainer); titleContainer.classList.toggle('breadcrumbs', Boolean(this.breadcrumbsControl)); this.redraw(); @@ -280,7 +280,7 @@ export class SingleEditorTabsControl extends EditorTabsControl { } // Clear if there is no editor - const [titleContainer, editorLabel] = assertAllDefined(this.titleContainer, this.editorLabel); + const [titleContainer, editorLabel] = assertReturnsAllDefined(this.titleContainer, this.editorLabel); if (!editor) { titleContainer.classList.remove('dirty'); editorLabel.clear(); diff --git a/src/vs/workbench/browser/parts/editor/textCodeEditor.ts b/src/vs/workbench/browser/parts/editor/textCodeEditor.ts index e7ace5f1af3..44dbef9ffa0 100644 --- a/src/vs/workbench/browser/parts/editor/textCodeEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textCodeEditor.ts @@ -5,7 +5,7 @@ import { localize } from '../../../../nls.js'; import { URI } from '../../../../base/common/uri.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { ITextEditorPane } from '../../../common/editor.js'; import { applyTextEditorOptions } from '../../../common/editor/editorOptions.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; @@ -83,7 +83,7 @@ export abstract class AbstractTextCodeEditor extends super.setOptions(options); if (options) { - applyTextEditorOptions(options, assertIsDefined(this.editorControl), ScrollType.Smooth); + applyTextEditorOptions(options, assertReturnsDefined(this.editorControl), ScrollType.Smooth); } } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 63b7b0d6f70..3de940f1771 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -5,7 +5,7 @@ import { localize } from '../../../../nls.js'; import { deepClone } from '../../../../base/common/objects.js'; -import { isObject, assertIsDefined } from '../../../../base/common/types.js'; +import { isObject, assertReturnsDefined } from '../../../../base/common/types.js'; import { ICodeEditor, IDiffEditor } from '../../../../editor/browser/editorBrowser.js'; import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from '../../../../editor/common/config/editorOptions.js'; import { AbstractTextEditor, IEditorConfiguration } from './textEditor.js'; @@ -121,7 +121,7 @@ export class TextDiffEditor extends AbstractTextEditor imp } // Set Editor Model - const control = assertIsDefined(this.diffEditorControl); + const control = assertReturnsDefined(this.diffEditorControl); const resolvedDiffEditorModel = resolvedModel as TextDiffEditorModel; const vm = resolvedDiffEditorModel.textDiffEditorModel ? control.createViewModel(resolvedDiffEditorModel.textDiffEditorModel) : null; @@ -243,7 +243,7 @@ export class TextDiffEditor extends AbstractTextEditor imp super.setOptions(options); if (options) { - applyTextEditorOptions(options, assertIsDefined(this.diffEditorControl), ScrollType.Smooth); + applyTextEditorOptions(options, assertReturnsDefined(this.diffEditorControl), ScrollType.Smooth); } } diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index e0a45755595..817d9febf0f 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -7,7 +7,7 @@ import { localize } from '../../../../nls.js'; import { URI } from '../../../../base/common/uri.js'; import { distinct, deepClone } from '../../../../base/common/objects.js'; import { Emitter, Event } from '../../../../base/common/event.js'; -import { isObject, assertIsDefined } from '../../../../base/common/types.js'; +import { isObject, assertReturnsDefined } from '../../../../base/common/types.js'; import { MutableDisposable } from '../../../../base/common/lifecycle.js'; import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { IEditorOpenContext, IEditorPaneSelection, EditorPaneSelectionCompareResult, EditorPaneSelectionChangeReason, IEditorPaneWithSelection, IEditorPaneSelectionChangeEvent, IEditorPaneScrollPosition, IEditorPaneWithScrolling } from '../../../common/editor.js'; @@ -248,7 +248,7 @@ export abstract class AbstractTextEditor extends Abs this.updateEditorConfiguration(); // Update aria label on editor - const editorContainer = assertIsDefined(this.editorContainer); + const editorContainer = assertReturnsDefined(this.editorContainer); editorContainer.setAttribute('aria-label', this.computeAriaLabel()); } diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index f828e558722..147f439bb35 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { ICodeEditor, IPasteEvent } from '../../../../editor/browser/editorBrowser.js'; import { IEditorOpenContext, isTextEditorViewState } from '../../../common/editor.js'; import { EditorInput } from '../../../common/editor/editorInput.js'; @@ -67,7 +67,7 @@ export abstract class AbstractTextResourceEditor extends AbstractTextCodeEditor< } // Set Editor Model - const control = assertIsDefined(this.editorControl); + const control = assertReturnsDefined(this.editorControl); const textEditorModel = resolvedModel.textEditorModel; control.setModel(textEditorModel); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index 103e37a3019..d7cea3a5c02 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -22,7 +22,7 @@ import { ActionBar } from '../../../../base/browser/ui/actionbar/actionbar.js'; import { ClearAllNotificationsAction, ConfigureDoNotDisturbAction, ToggleDoNotDisturbBySourceAction, HideNotificationsCenterAction, ToggleDoNotDisturbAction } from './notificationsActions.js'; import { IAction, Separator, toAction } from '../../../../base/common/actions.js'; import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; -import { assertAllDefined, assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsAllDefined, assertReturnsDefined } from '../../../../base/common/types.js'; import { NotificationsCenterVisibleContext } from '../../../common/contextkeys.js'; import { INotificationService, NotificationsFilter } from '../../../../platform/notification/common/notification.js'; import { mainWindow } from '../../../../base/browser/window.js'; @@ -87,7 +87,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente show(): void { if (this._isVisible) { - const notificationsList = assertIsDefined(this.notificationsList); + const notificationsList = assertReturnsDefined(this.notificationsList); // Make visible notificationsList.show(); @@ -107,7 +107,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente this.updateTitle(); // Make visible - const [notificationsList, notificationsCenterContainer] = assertAllDefined(this.notificationsList, this.notificationsCenterContainer); + const [notificationsList, notificationsCenterContainer] = assertReturnsAllDefined(this.notificationsList, this.notificationsCenterContainer); this._isVisible = true; notificationsCenterContainer.classList.add('visible'); notificationsList.show(); @@ -135,7 +135,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente } private updateTitle(): void { - const [notificationsCenterTitle, clearAllAction] = assertAllDefined(this.notificationsCenterTitle, this.clearAllAction); + const [notificationsCenterTitle, clearAllAction] = assertReturnsAllDefined(this.notificationsCenterTitle, this.clearAllAction); if (this.model.notifications.length === 0) { notificationsCenterTitle.textContent = localize('notificationsEmpty', "No new notifications"); @@ -245,7 +245,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente let focusEditor = false; // Update notifications list based on event kind - const [notificationsList, notificationsCenterContainer] = assertAllDefined(this.notificationsList, this.notificationsCenterContainer); + const [notificationsList, notificationsCenterContainer] = assertReturnsAllDefined(this.notificationsList, this.notificationsCenterContainer); switch (e.kind) { case NotificationChangeType.ADD: notificationsList.updateNotificationsList(e.index, 0, [e.item]); @@ -365,7 +365,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente } // Apply to list - const notificationsList = assertIsDefined(this.notificationsList); + const notificationsList = assertReturnsDefined(this.notificationsList); notificationsList.layout(Math.min(maxWidth, availableWidth), Math.min(maxHeight, availableHeight)); } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index edb6062b717..cd5c2f5b6a5 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -14,7 +14,7 @@ import { INotificationViewItem } from '../../../common/notifications.js'; import { NotificationsListDelegate, NotificationRenderer } from './notificationsViewer.js'; import { CopyNotificationMessageAction } from './notificationsActions.js'; import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; -import { assertAllDefined } from '../../../../base/common/types.js'; +import { assertReturnsAllDefined } from '../../../../base/common/types.js'; import { NotificationFocusedContext } from '../../../common/contextkeys.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { AriaRole } from '../../../../base/browser/ui/aria/aria.js'; @@ -131,7 +131,7 @@ export class NotificationsList extends Disposable { } updateNotificationsList(start: number, deleteCount: number, items: INotificationViewItem[] = []) { - const [list, listContainer] = assertAllDefined(this.list, this.listContainer); + const [list, listContainer] = assertReturnsAllDefined(this.list, this.listContainer); const listHasDOMFocus = isAncestorOfActiveElement(listContainer); // Remember focus and relative top of that item @@ -188,7 +188,7 @@ export class NotificationsList extends Disposable { return; } - const [list, listDelegate] = assertAllDefined(this.list, this.listDelegate); + const [list, listDelegate] = assertReturnsAllDefined(this.list, this.listDelegate); list.updateElementHeight(index, listDelegate.getHeight(item)); list.layout(); } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index e3c132ba9f9..42fffede341 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -23,7 +23,7 @@ import { ScrollbarVisibility } from '../../../../base/common/scrollable.js'; import { ILifecycleService, LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js'; import { IHostService } from '../../../services/host/browser/host.js'; import { IntervalCounter } from '../../../../base/common/async.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { NotificationsToastsVisibleContext } from '../../../common/contextkeys.js'; import { mainWindow } from '../../../../base/browser/window.js'; @@ -608,7 +608,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast } // Update visibility in DOM - const notificationsToastsContainer = assertIsDefined(this.notificationsToastsContainer); + const notificationsToastsContainer = assertReturnsDefined(this.notificationsToastsContainer); if (visible) { notificationsToastsContainer.appendChild(toast.container); } else { diff --git a/src/vs/workbench/browser/parts/paneCompositePartService.ts b/src/vs/workbench/browser/parts/paneCompositePartService.ts index f89d38b6ec9..199ac1c8821 100644 --- a/src/vs/workbench/browser/parts/paneCompositePartService.ts +++ b/src/vs/workbench/browser/parts/paneCompositePartService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from '../../../base/common/event.js'; -import { assertIsDefined } from '../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../base/common/types.js'; import { InstantiationType, registerSingleton } from '../../../platform/instantiation/common/extensions.js'; import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js'; import { IProgressIndicator } from '../../../platform/progress/common/progress.js'; @@ -86,7 +86,7 @@ export class PaneCompositePartService extends Disposable implements IPaneComposi } private getPartByLocation(viewContainerLocation: ViewContainerLocation): IPaneCompositePart { - return assertIsDefined(this.paneCompositeParts.get(viewContainerLocation)); + return assertReturnsDefined(this.paneCompositeParts.get(viewContainerLocation)); } } diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 5e58b5801c4..c83ce6aa881 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -20,7 +20,7 @@ import { contrastBorder } from '../../../../platform/theme/common/colorRegistry. import { INotificationService } from '../../../../platform/notification/common/notification.js'; import { Dimension } from '../../../../base/browser/dom.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; import { IViewDescriptorService } from '../../../common/views.js'; import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js'; @@ -116,7 +116,7 @@ export class PanelPart extends AbstractPaneCompositePart { override updateStyles(): void { super.updateStyles(); - const container = assertIsDefined(this.getContainer()); + const container = assertReturnsDefined(this.getContainer()); container.style.backgroundColor = this.getColor(PANEL_BACKGROUND) || ''; const borderColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || ''; container.style.borderLeftColor = borderColor; diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 1b1f83b23ce..b8c0c9542f1 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -19,7 +19,7 @@ import { IContextKeyService } from '../../../../platform/contextkey/common/conte import { AnchorAlignment } from '../../../../base/browser/ui/contextview/contextview.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; import { LayoutPriority } from '../../../../base/browser/ui/grid/grid.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IViewDescriptorService } from '../../../common/views.js'; import { AbstractPaneCompositePart, CompositeBarPosition } from '../paneCompositePart.js'; import { ActivityBarCompositeBar, ActivitybarPart } from '../activitybar/activitybarPart.js'; @@ -135,7 +135,7 @@ export class SidebarPart extends AbstractPaneCompositePart { override updateStyles(): void { super.updateStyles(); - const container = assertIsDefined(this.getContainer()); + const container = assertReturnsDefined(this.getContainer()); container.style.backgroundColor = this.getColor(SIDE_BAR_BACKGROUND) || ''; container.style.color = this.getColor(SIDE_BAR_FOREGROUND) || ''; diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarItem.ts b/src/vs/workbench/browser/parts/statusbar/statusbarItem.ts index 241526727af..7d2da303a22 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarItem.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarItem.ts @@ -15,7 +15,7 @@ import { ThemeColor } from '../../../../base/common/themables.js'; import { isThemeColor } from '../../../../editor/common/editorCommon.js'; import { addDisposableListener, EventType, hide, show, append, EventHelper, $ } from '../../../../base/browser/dom.js'; import { INotificationService } from '../../../../platform/notification/common/notification.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { Command } from '../../../../editor/common/languages.js'; import { StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js'; import { KeyCode } from '../../../../base/common/keyCodes.js'; @@ -46,7 +46,7 @@ export class StatusbarEntryItem extends Disposable { readonly beakContainer: HTMLElement; get name(): string { - return assertIsDefined(this.entry).name; + return assertReturnsDefined(this.entry).name; } get hasCommand(): boolean { diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index d7760cf9a18..69a46a740b2 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -24,7 +24,7 @@ import { InstantiationType, registerSingleton } from '../../../../platform/insta import { equals } from '../../../../base/common/arrays.js'; import { StandardMouseEvent } from '../../../../base/browser/mouseEvent.js'; import { ToggleStatusbarVisibilityAction } from '../../actions/layoutActions.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { isHighContrast } from '../../../../platform/theme/common/theme.js'; import { hash } from '../../../../base/common/hash.js'; @@ -445,8 +445,8 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { } private appendStatusbarEntries(): void { - const leftItemsContainer = assertIsDefined(this.leftItemsContainer); - const rightItemsContainer = assertIsDefined(this.rightItemsContainer); + const leftItemsContainer = assertReturnsDefined(this.leftItemsContainer); + const rightItemsContainer = assertReturnsDefined(this.rightItemsContainer); // Clear containers clearNode(leftItemsContainer); @@ -473,7 +473,7 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { entries.reverse(); // reversing due to flex: row-reverse } - const target = assertIsDefined(entry.alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer); + const target = assertReturnsDefined(entry.alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer); const index = entries.indexOf(entry); if (index + 1 === entries.length) { @@ -635,7 +635,7 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { override updateStyles(): void { super.updateStyles(); - const container = assertIsDefined(this.getContainer()); + const container = assertReturnsDefined(this.getContainer()); const styleOverride: IStatusbarStyleOverride | undefined = [...this.styleOverrides].sort((a, b) => a.priority - b.priority)[0]; // Background / foreground colors diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index e8dedb875d8..c34db2ed2c7 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -23,7 +23,7 @@ import { IConfigurationService } from '../../../../platform/configuration/common import { Extensions as ViewContainerExtensions, IView, IViewDescriptorService, ViewContainerLocation, IViewsRegistry, IViewContentDescriptor, defaultViewIcon, ViewContainerLocationToString } from '../../../common/views.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { assertIsDefined, PartialExcept } from '../../../../base/common/types.js'; +import { assertReturnsDefined, PartialExcept } from '../../../../base/common/types.js'; import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { MenuId, Action2, IAction2Options, SubmenuItemAction } from '../../../../platform/actions/common/actions.js'; import { createActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js'; @@ -641,7 +641,7 @@ export abstract class ViewPane extends Pane implements IView { if (this.progressIndicator === undefined) { const that = this; - this.progressIndicator = this._register(new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope { + this.progressIndicator = this._register(new ScopedProgressIndicator(assertReturnsDefined(this.progressBar), new class extends AbstractProgressScope { constructor() { super(that.id, that.isBodyVisible()); this._register(that.onDidChangeBodyVisibility(isVisible => isVisible ? this.onScopeOpened(that.id) : this.onScopeClosed(that.id))); diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index eaa4e9aae1a..bf89cf67fee 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -14,7 +14,7 @@ import { RunOnceScheduler } from '../../../../base/common/async.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import { combinedDisposable, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import './media/paneviewlet.css'; import * as nls from '../../../../nls.js'; import { createActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js'; @@ -347,7 +347,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { readonly onDidBlurView = this._onDidBlurView.event; get onDidSashChange(): Event { - return assertIsDefined(this.paneview).onDidSashChange; + return assertReturnsDefined(this.paneview).onDidSashChange; } get panes(): ViewPane[] { @@ -887,7 +887,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { const paneItem: IViewPaneItem = { pane, disposable: store }; this.paneItems.splice(index, 0, paneItem); - assertIsDefined(this.paneview).addPane(pane, size, index); + assertReturnsDefined(this.paneview).addPane(pane, size, index); let overlay: ViewPaneDropOverlay | undefined; @@ -1041,7 +1041,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { this.lastFocusedPane = undefined; } - assertIsDefined(this.paneview).removePane(pane); + assertReturnsDefined(this.paneview).removePane(pane); const [paneItem] = this.paneItems.splice(index, 1); paneItem.disposable.dispose(); @@ -1065,7 +1065,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { const [paneItem] = this.paneItems.splice(fromIndex, 1); this.paneItems.splice(toIndex, 0, paneItem); - assertIsDefined(this.paneview).movePane(from, to); + assertReturnsDefined(this.paneview).movePane(from, to); this.viewContainerModel.move(fromViewDescriptor.id, toViewDescriptor.id); @@ -1073,11 +1073,11 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { } resizePane(pane: ViewPane, size: number): void { - assertIsDefined(this.paneview).resizePane(pane, size); + assertReturnsDefined(this.paneview).resizePane(pane, size); } getPaneSize(pane: ViewPane): number { - return assertIsDefined(this.paneview).getPaneSize(pane); + return assertReturnsDefined(this.paneview).getPaneSize(pane); } private updateViewHeaders(): void { diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 8aec734eb49..6d42eeaa3d4 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -5,7 +5,7 @@ import { mark } from '../../base/common/performance.js'; import { domContentLoaded, detectFullscreen, getCookieValue, getWindow } from '../../base/browser/dom.js'; -import { assertIsDefined } from '../../base/common/types.js'; +import { assertReturnsDefined } from '../../base/common/types.js'; import { ServiceCollection } from '../../platform/instantiation/common/serviceCollection.js'; import { ILogService, ConsoleLogger, getLogLevel, ILoggerService, ILogger } from '../../platform/log/common/log.js'; import { ConsoleLogInAutomationLogger } from '../../platform/log/browser/log.js'; @@ -209,7 +209,7 @@ export class BrowserMain extends Disposable { await remoteAuthorityResolverService.resolveAuthority(this.configuration.remoteAuthority); }, openTunnel: async tunnelOptions => { - const tunnel = assertIsDefined(await remoteExplorerService.forward({ + const tunnel = assertReturnsDefined(await remoteExplorerService.forward({ remote: tunnelOptions.remoteAddress, local: tunnelOptions.localAddressPort, name: tunnelOptions.label, diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 0e01088e1e2..c4c2b8e3b29 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -5,7 +5,7 @@ import { localize } from '../../nls.js'; import { Event } from '../../base/common/event.js'; -import { DeepRequiredNonNullable, assertIsDefined } from '../../base/common/types.js'; +import { DeepRequiredNonNullable, assertReturnsDefined } from '../../base/common/types.js'; import { URI } from '../../base/common/uri.js'; import { Disposable, IDisposable, toDisposable } from '../../base/common/lifecycle.js'; import { ICodeEditorViewState, IDiffEditor, IDiffEditorViewState, IEditor, IEditorViewState } from '../../editor/common/editorCommon.js'; @@ -1558,7 +1558,7 @@ class EditorFactoryRegistry implements IEditorFactoryRegistry { } getFileEditorFactory(): IFileEditorFactory { - return assertIsDefined(this.fileEditorFactory); + return assertReturnsDefined(this.fileEditorFactory); } registerEditorSerializer(editorTypeId: string, ctor: IConstructorSignature): IDisposable { diff --git a/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts b/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts index d5e53fcba54..12178f16a0f 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts @@ -25,7 +25,7 @@ import { Selection } from '../../../../../editor/common/core/selection.js'; import { Position } from '../../../../../editor/common/core/position.js'; import { Range } from '../../../../../editor/common/core/range.js'; import { registerAction2 } from '../../../../../platform/actions/common/actions.js'; -import { assertIsDefined } from '../../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../../base/common/types.js'; import { ActionBar } from '../../../../../base/browser/ui/actionbar/actionbar.js'; import { toAction } from '../../../../../base/common/actions.js'; import { ThemeIcon } from '../../../../../base/common/themables.js'; @@ -225,7 +225,7 @@ export class EditorDictation extends Disposable implements IEditorContribution { let lastReplaceTextLength = 0; const replaceText = (text: string, isPreview: boolean) => { if (!previewStart) { - previewStart = assertIsDefined(this.editor.getPosition()); + previewStart = assertReturnsDefined(this.editor.getPosition()); } const endPosition = new Position(previewStart.lineNumber, previewStart.column + text.length); diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index d246fb9fdda..ee708d0ddda 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -12,7 +12,7 @@ import { IReference } from '../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../base/common/network.js'; import { basename } from '../../../../base/common/path.js'; import { dirname, isEqual } from '../../../../base/common/resources.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { localize } from '../../../../nls.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; @@ -338,7 +338,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { if (!this._modelRef) { const oldCapabilities = this.capabilities; - this._modelRef = this._register(assertIsDefined(await this.customEditorService.models.tryRetain(this.resource, this.viewType))); + this._modelRef = this._register(assertReturnsDefined(await this.customEditorService.models.tryRetain(this.resource, this.viewType))); this._register(this._modelRef.object.onDidChangeDirty(() => this._onDidChangeDirty.fire())); this._register(this._modelRef.object.onDidChangeReadonly(() => this._onDidChangeCapabilities.fire())); // If we're loading untitled file data we should ensure it's dirty @@ -362,12 +362,12 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { } public undo(): void | Promise { - assertIsDefined(this._modelRef); + assertReturnsDefined(this._modelRef); return this.undoRedoService.undo(this.resource); } public redo(): void | Promise { - assertIsDefined(this._modelRef); + assertReturnsDefined(this._modelRef); return this.undoRedoService.redo(this.resource); } diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index d9bd443af2c..f473e0a6b74 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -9,7 +9,7 @@ import { Emitter, Event } from '../../../../base/common/event.js'; import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../base/common/network.js'; import { extname, isEqual } from '../../../../base/common/resources.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { RedoCommand, UndoCommand } from '../../../../editor/browser/editorExtensions.js'; import { IResourceEditorInput } from '../../../../platform/editor/common/editor.js'; @@ -157,8 +157,8 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ editorID: string, group: IEditorGroup ): DiffEditorInput { - const modifiedOverride = CustomEditorInput.create(this.instantiationService, assertIsDefined(editor.modified.resource), editorID, group.id, { customClasses: 'modified' }); - const originalOverride = CustomEditorInput.create(this.instantiationService, assertIsDefined(editor.original.resource), editorID, group.id, { customClasses: 'original' }); + const modifiedOverride = CustomEditorInput.create(this.instantiationService, assertReturnsDefined(editor.modified.resource), editorID, group.id, { customClasses: 'modified' }); + const originalOverride = CustomEditorInput.create(this.instantiationService, assertReturnsDefined(editor.original.resource), editorID, group.id, { customClasses: 'original' }); return this.instantiationService.createInstance(DiffEditorInput, editor.label, editor.description, originalOverride, modifiedOverride, true); } diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index bff940f4e0b..eeea241e304 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -5,7 +5,7 @@ import { localize } from '../../../../../nls.js'; import { mark } from '../../../../../base/common/performance.js'; -import { assertIsDefined } from '../../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../../base/common/types.js'; import { IPathService } from '../../../../services/path/common/pathService.js'; import { IAction, toAction } from '../../../../../base/common/actions.js'; import { VIEWLET_ID, TEXT_FILE_EDITOR_ID, BINARY_TEXT_FILE_MODE } from '../../common/files.js'; @@ -125,7 +125,7 @@ export class TextFileEditor extends AbstractTextCodeEditor const textFileModel = resolvedModel; // Editor - const control = assertIsDefined(this.editorControl); + const control = assertReturnsDefined(this.editorControl); control.setModel(textFileModel.textEditorModel); // Restore view state (unless provided by options) diff --git a/src/vs/workbench/contrib/files/common/explorerModel.ts b/src/vs/workbench/contrib/files/common/explorerModel.ts index ff3943dc129..468d501385d 100644 --- a/src/vs/workbench/contrib/files/common/explorerModel.ts +++ b/src/vs/workbench/contrib/files/common/explorerModel.ts @@ -19,7 +19,7 @@ import { IFilesConfiguration, SortOrder } from './files.js'; import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js'; import { ExplorerFileNestingTrie } from './explorerFileNestingTrie.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IFilesConfigurationService } from '../../../services/filesConfiguration/common/filesConfigurationService.js'; import { IMarkdownString } from '../../../../base/common/htmlContent.js'; @@ -355,7 +355,7 @@ export class ExplorerItem { if (nestedItems !== undefined) { fileEntryItem.nestedChildren = []; for (const name of nestedItems.keys()) { - const child = assertIsDefined(this.children.get(name)); + const child = assertReturnsDefined(this.children.get(name)); fileEntryItem.nestedChildren.push(child); child.nestedParent = fileEntryItem; } diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts index 4f712df54e1..d11424320a4 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts @@ -17,7 +17,7 @@ import { ResourceMap } from '../../../../base/common/map.js'; import { FileWorkingCopyManager, IFileWorkingCopyManager } from '../../../services/workingCopy/common/fileWorkingCopyManager.js'; import { Schemas } from '../../../../base/common/network.js'; import { NotebookProviderInfo } from './notebookProvider.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IFileReadLimits } from '../../../../platform/files/common/files.js'; @@ -188,7 +188,7 @@ export class NotebookModelResolverServiceImpl implements INotebookEditorModelRes } private createUntitledUri(notebookType: string) { - const info = this._notebookService.getContributedNotebookType(assertIsDefined(notebookType)); + const info = this._notebookService.getContributedNotebookType(assertReturnsDefined(notebookType)); if (!info) { throw new Error('UNKNOWN notebook type: ' + notebookType); } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts index af01934653d..6a34c4f6ec5 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts @@ -22,7 +22,7 @@ import { ThemeColor } from '../../../../base/common/themables.js'; import { overviewRulerInfo, overviewRulerError } from '../../../../editor/common/core/editorColorRegistry.js'; import { IModelDeltaDecoration, ITextModel, TrackedRangeStickiness, OverviewRulerLane } from '../../../../editor/common/model.js'; import { KeybindingParser } from '../../../../base/common/keybindingParser.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { isEqual } from '../../../../base/common/resources.js'; import { IUserDataProfileService } from '../../../services/userDataProfile/common/userDataProfile.js'; import { DEFINE_KEYBINDING_EDITOR_CONTRIB_ID, IDefineKeybindingEditorContribution } from '../../../services/preferences/common/preferences.js'; @@ -100,7 +100,7 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { this._updateDecorations = this._register(new RunOnceScheduler(() => this._updateDecorationsNow(), 500)); - const model = assertIsDefined(this._editor.getModel()); + const model = assertReturnsDefined(this._editor.getModel()); this._register(model.onDidChangeContent(() => this._updateDecorations.schedule())); this._register(this._keybindingService.onDidUpdateKeybindings(() => this._updateDecorations.schedule())); this._register({ @@ -113,7 +113,7 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { } private _updateDecorationsNow(): void { - const model = assertIsDefined(this._editor.getModel()); + const model = assertReturnsDefined(this._editor.getModel()); const newDecorations: IModelDeltaDecoration[] = []; diff --git a/src/vs/workbench/contrib/search/browser/searchActionsNav.ts b/src/vs/workbench/contrib/search/browser/searchActionsNav.ts index 8f8bf18d96c..da1c42c240f 100644 --- a/src/vs/workbench/contrib/search/browser/searchActionsNav.ts +++ b/src/vs/workbench/contrib/search/browser/searchActionsNav.ts @@ -16,7 +16,7 @@ import { SearchEditor } from '../../searchEditor/browser/searchEditor.js'; import { SearchEditorInput } from '../../searchEditor/browser/searchEditorInput.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; @@ -46,7 +46,7 @@ registerAction2(class ToggleQueryDetailsAction extends Action2 { (accessor.get(IEditorService).activeEditorPane as SearchEditor).toggleQueryDetails(args[0]?.show); } else if (contextService.getValue(Constants.SearchContext.SearchViewFocusedKey.serialize())) { const searchView = getSearchView(accessor.get(IViewsService)); - assertIsDefined(searchView).toggleQueryDetails(undefined, args[0]?.show); + assertReturnsDefined(searchView).toggleQueryDetails(undefined, args[0]?.show); } } }); diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts index 06c660a0325..8e408accee9 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts @@ -10,7 +10,7 @@ import { Delayer } from '../../../../base/common/async.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import { DisposableStore } from '../../../../base/common/lifecycle.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import './media/searchEditor.css'; import { ICodeEditorWidgetOptions } from '../../../../editor/browser/widget/codeEditor/codeEditorWidget.js'; @@ -137,7 +137,7 @@ export class SearchEditor extends AbstractTextCodeEditor super.createEditor(searchResultContainer); this.registerEditorListeners(); - const scopedContextKeyService = assertIsDefined(this.scopedContextKeyService); + const scopedContextKeyService = assertReturnsDefined(this.scopedContextKeyService); InSearchEditor.bindTo(scopedContextKeyService).set(true); this.createQueryEditor( diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts index f833d6f0123..15c1e4442df 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts @@ -11,7 +11,7 @@ import { IInstantiationService, ServicesAccessor } from '../../../../platform/in import { parseSavedSearchEditor, parseSerializedSearchEditor } from './searchEditorSerialization.js'; import { IWorkingCopyBackupService } from '../../../services/workingCopy/common/workingCopyBackup.js'; import { SearchConfiguration, SearchEditorWorkingCopyTypeId } from './constants.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { createTextBufferFactoryFromStream } from '../../../../editor/common/model/textModel.js'; import { Emitter } from '../../../../base/common/event.js'; import { ResourceMap } from '../../../../base/common/map.js'; @@ -33,7 +33,7 @@ export class SearchEditorModel { ) { } async resolve(): Promise { - return assertIsDefined(searchEditorModelFactory.models.get(this.resource)).resolve(); + return assertReturnsDefined(searchEditorModelFactory.models.get(this.resource)).resolve(); } } diff --git a/src/vs/workbench/contrib/splash/browser/partsSplash.ts b/src/vs/workbench/contrib/splash/browser/partsSplash.ts index 935a7432d71..5a061483a4e 100644 --- a/src/vs/workbench/contrib/splash/browser/partsSplash.ts +++ b/src/vs/workbench/contrib/splash/browser/partsSplash.ts @@ -17,7 +17,7 @@ import { IWorkbenchEnvironmentService } from '../../../services/environment/comm import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import * as perf from '../../../../base/common/performance.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { ISplashStorageService } from './splash.js'; import { mainWindow } from '../../../../base/browser/window.js'; import { ILifecycleService, LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js'; @@ -92,11 +92,11 @@ export class PartsSplash { layoutInfo: !this._shouldSaveLayoutInfo() ? undefined : { sideBarSide: this._layoutService.getSideBarPosition() === Position.RIGHT ? 'right' : 'left', editorPartMinWidth: DEFAULT_EDITOR_MIN_DIMENSIONS.width, - titleBarHeight: this._layoutService.isVisible(Parts.TITLEBAR_PART, mainWindow) ? dom.getTotalHeight(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.TITLEBAR_PART))) : 0, - activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? dom.getTotalWidth(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.ACTIVITYBAR_PART))) : 0, - sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? dom.getTotalWidth(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.SIDEBAR_PART))) : 0, - auxiliarySideBarWidth: this._layoutService.isVisible(Parts.AUXILIARYBAR_PART) ? dom.getTotalWidth(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.AUXILIARYBAR_PART))) : 0, - statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART, mainWindow) ? dom.getTotalHeight(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.STATUSBAR_PART))) : 0, + titleBarHeight: this._layoutService.isVisible(Parts.TITLEBAR_PART, mainWindow) ? dom.getTotalHeight(assertReturnsDefined(this._layoutService.getContainer(mainWindow, Parts.TITLEBAR_PART))) : 0, + activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? dom.getTotalWidth(assertReturnsDefined(this._layoutService.getContainer(mainWindow, Parts.ACTIVITYBAR_PART))) : 0, + sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? dom.getTotalWidth(assertReturnsDefined(this._layoutService.getContainer(mainWindow, Parts.SIDEBAR_PART))) : 0, + auxiliarySideBarWidth: this._layoutService.isVisible(Parts.AUXILIARYBAR_PART) ? dom.getTotalWidth(assertReturnsDefined(this._layoutService.getContainer(mainWindow, Parts.AUXILIARYBAR_PART))) : 0, + statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART, mainWindow) ? dom.getTotalHeight(assertReturnsDefined(this._layoutService.getContainer(mainWindow, Parts.STATUSBAR_PART))) : 0, windowBorder: this._layoutService.hasMainWindowBorder(), windowBorderRadius: this._layoutService.getMainWindowBorderRadius() } diff --git a/src/vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider.ts b/src/vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider.ts index d508a0d8785..393c8c36a12 100644 --- a/src/vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider.ts +++ b/src/vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider.ts @@ -12,7 +12,7 @@ import { IStorageService, StorageScope, StorageTarget } from '../../../../platfo import { IWorkbenchContribution } from '../../../common/contributions.js'; import { VSBuffer } from '../../../../base/common/buffer.js'; import { readTrustedDomains, TRUSTED_DOMAINS_CONTENT_STORAGE_KEY, TRUSTED_DOMAINS_STORAGE_KEY } from './trustedDomains.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; const TRUSTED_DOMAINS_SCHEMA = 'trustedDomains'; @@ -109,7 +109,7 @@ export class TrustedDomainsFileSystemProvider implements IFileSystemProviderWith trustedDomainsContent.indexOf(CONFIG_HELP_TEXT_PRE) === -1 || trustedDomainsContent.indexOf(CONFIG_HELP_TEXT_AFTER) === -1 || trustedDomainsContent.indexOf(configuring ?? '') === -1 || - [...defaultTrustedDomains, ...trustedDomains].some(d => !assertIsDefined(trustedDomainsContent).includes(d)) + [...defaultTrustedDomains, ...trustedDomains].some(d => !assertReturnsDefined(trustedDomainsContent).includes(d)) ) { trustedDomainsContent = computeTrustedDomainContent(defaultTrustedDomains, trustedDomains, configuring); } diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts index 8d728275a51..2f4b15dc6e3 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts @@ -23,7 +23,7 @@ import { parse } from '../../../../base/common/marshalling.js'; import { Schemas, matchesScheme } from '../../../../base/common/network.js'; import { OS } from '../../../../base/common/platform.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { generateUuid } from '../../../../base/common/uuid.js'; import './media/gettingStarted.css'; @@ -276,7 +276,7 @@ export class GettingStartedPage extends EditorPane { ourStep.done = step.done; if (category.id === this.currentWalkthrough?.id) { - const badgeelements = assertIsDefined(this.window.document.querySelectorAll(`[data-done-step-id="${step.id}"]`)); + const badgeelements = assertReturnsDefined(this.window.document.querySelectorAll(`[data-done-step-id="${step.id}"]`)); badgeelements.forEach(badgeelement => { if (step.done) { badgeelement.setAttribute('aria-checked', 'true'); @@ -490,7 +490,7 @@ export class GettingStartedPage extends EditorPane { } private toggleStepCompletion(argument: string) { - const stepToggle = assertIsDefined(this.currentWalkthrough?.steps.find(step => step.id === argument)); + const stepToggle = assertReturnsDefined(this.currentWalkthrough?.steps.find(step => step.id === argument)); if (stepToggle.done) { this.gettingStartedService.deprogressStep(argument); } else { @@ -530,7 +530,7 @@ export class GettingStartedPage extends EditorPane { if (!this.currentWalkthrough) { throw Error('no walkthrough selected'); } - const stepToExpand = assertIsDefined(this.currentWalkthrough.steps.find(step => step.id === stepId)); + const stepToExpand = assertReturnsDefined(this.currentWalkthrough.steps.find(step => step.id === stepId)); if (!forceRebuild && this.currentMediaComponent === stepId) { return; } this.currentMediaComponent = stepId; @@ -774,7 +774,7 @@ export class GettingStartedPage extends EditorPane { // No steps around... just ignore. return; } - id = assertIsDefined(stepElement.getAttribute('data-step-id')); + id = assertReturnsDefined(stepElement.getAttribute('data-step-id')); } stepElement.parentElement?.querySelectorAll('.expanded').forEach(node => { if (node.getAttribute('data-step-id') !== id) { @@ -1215,7 +1215,7 @@ export class GettingStartedPage extends EditorPane { const stats = this.getWalkthroughCompletionStats(category); - const bar = assertIsDefined(element.querySelector('.progress-bar-inner')) as HTMLDivElement; + const bar = assertReturnsDefined(element.querySelector('.progress-bar-inner')) as HTMLDivElement; bar.setAttribute('aria-valuemin', '0'); bar.setAttribute('aria-valuenow', '' + stats.stepsComplete); bar.setAttribute('aria-valuemax', '' + stats.stepsTotal); @@ -1272,7 +1272,7 @@ export class GettingStartedPage extends EditorPane { const gettingStartedSize = Math.floor(fullSize.width / 2); const gettingStartedGroup = this.groupsService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).find(group => (group.activeEditor instanceof GettingStartedInput)); - this.groupsService.setSize(assertIsDefined(gettingStartedGroup), { width: gettingStartedSize, height: fullSize.height }); + this.groupsService.setSize(assertReturnsDefined(gettingStartedGroup), { width: gettingStartedSize, height: fullSize.height }); } const nonGettingStartedGroup = this.groupsService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).find(group => !(group.activeEditor instanceof GettingStartedInput)); @@ -2079,7 +2079,7 @@ export class GettingStartedPage extends EditorPane { } private setSlide(toEnable: 'details' | 'categories', firstLaunch: boolean = false) { - const slideManager = assertIsDefined(this.container.querySelector('.gettingStarted')); + const slideManager = assertReturnsDefined(this.container.querySelector('.gettingStarted')); if (toEnable === 'categories') { slideManager.classList.remove('showDetails'); slideManager.classList.add('showCategories'); diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts index 1ca5db0b86b..c4e3637ca2c 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer.ts @@ -10,7 +10,7 @@ import { DEFAULT_MARKDOWN_STYLES, renderMarkdownDocument } from '../../markdown/ import { URI } from '../../../../base/common/uri.js'; import { language } from '../../../../base/common/platform.js'; import { joinPath } from '../../../../base/common/resources.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { asWebviewUri } from '../../webview/common/webview.js'; import { ResourceMap } from '../../../../base/common/map.js'; import { IFileService } from '../../../../platform/files/common/files.js'; @@ -230,7 +230,7 @@ export class GettingStartedDetailsRenderer { const contents = await this.readContentsOfPath(path, false); this.svgCache.set(path, contents); } - return assertIsDefined(this.svgCache.get(path)); + return assertReturnsDefined(this.svgCache.get(path)); } private async readAndCacheStepMarkdown(path: URI, base: URI): Promise { @@ -239,7 +239,7 @@ export class GettingStartedDetailsRenderer { const markdownContents = await renderMarkdownDocument(transformUris(contents, base), this.extensionService, this.languageService, { allowUnknownProtocols: true }); this.mdCache.set(path, markdownContents); } - return assertIsDefined(this.mdCache.get(path)); + return assertReturnsDefined(this.mdCache.get(path)); } private async readContentsOfPath(path: URI, useModuleId = true): Promise { diff --git a/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts b/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts index 4b6a9aeab73..b443285e3c2 100644 --- a/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts +++ b/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts @@ -6,7 +6,7 @@ import { promiseWithResolvers } from '../../../../base/common/async.js'; import { KeyMod, KeyCode } from '../../../../base/common/keyCodes.js'; import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { localize, localize2 } from '../../../../nls.js'; import { ILocalizedString } from '../../../../platform/action/common/action.js'; import { Action2, IMenuService, MenuId, registerAction2, IMenu, MenuRegistry, MenuItemAction } from '../../../../platform/actions/common/actions.js'; @@ -43,7 +43,7 @@ registerAction2(class extends Action2 { } async run(accessor: ServicesAccessor): Promise { - return assertIsDefined(NewFileTemplatesManager.Instance).run(); + return assertReturnsDefined(NewFileTemplatesManager.Instance).run(); } }); diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts b/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts index b7ed7fdb242..84889e04ebe 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/common/walkThroughContentProvider.ts @@ -13,7 +13,7 @@ import * as marked from '../../../../base/common/marked/marked.js'; import { Schemas } from '../../../../base/common/network.js'; import { Range } from '../../../../editor/common/core/range.js'; import { createTextBufferFactory } from '../../../../editor/common/model/textModel.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; interface IWalkThroughContentProvider { @@ -100,6 +100,6 @@ export class WalkThroughSnippetContentProvider implements ITextModelContentProvi const markdown = textBuffer.getValueInRange(range, EndOfLinePreference.TextDefined); marked.marked(markdown, { renderer }); } - return assertIsDefined(codeEditorModel); + return assertReturnsDefined(codeEditorModel); } } diff --git a/src/vs/workbench/services/search/common/queryBuilder.ts b/src/vs/workbench/services/search/common/queryBuilder.ts index feaaf16c7f4..b75fb3f366a 100644 --- a/src/vs/workbench/services/search/common/queryBuilder.ts +++ b/src/vs/workbench/services/search/common/queryBuilder.ts @@ -12,7 +12,7 @@ import { Schemas } from '../../../../base/common/network.js'; import * as path from '../../../../base/common/path.js'; import { isEqual, basename, relativePath, isAbsolutePath } from '../../../../base/common/resources.js'; import * as strings from '../../../../base/common/strings.js'; -import { assertIsDefined, isDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined, isDefined } from '../../../../base/common/types.js'; import { URI, URI as uri, UriComponents } from '../../../../base/common/uri.js'; import { isMultilineRegexSource } from '../../../../editor/common/model/textModelSearch.js'; import * as nls from '../../../../nls.js'; @@ -313,7 +313,7 @@ export class QueryBuilder { } const relPath = path.relative(searchRoot.fsPath, file.fsPath); - assertIsDefined(folderQuery.includePattern)[relPath.replace(/\\/g, '/')] = true; + assertReturnsDefined(folderQuery.includePattern)[relPath.replace(/\\/g, '/')] = true; } else { if (file.fsPath) { hasIncludedFile = true; diff --git a/src/vs/workbench/services/storage/browser/storageService.ts b/src/vs/workbench/services/storage/browser/storageService.ts index ca10b6f7d95..309033e3b9a 100644 --- a/src/vs/workbench/services/storage/browser/storageService.ts +++ b/src/vs/workbench/services/storage/browser/storageService.ts @@ -11,7 +11,7 @@ import { DeferredPromise, Promises } from '../../../../base/common/async.js'; import { toErrorMessage } from '../../../../base/common/errorMessage.js'; import { Emitter } from '../../../../base/common/event.js'; import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { InMemoryStorageDatabase, isStorageItemsChangeEvent, IStorage, IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest, Storage } from '../../../../base/parts/storage/common/storage.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { AbstractStorageService, isProfileUsingDefaultStorage, IS_NEW_KEY, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; @@ -168,7 +168,7 @@ export class BrowserStorageService extends AbstractStorageService { return; } - const oldProfileStorage = assertIsDefined(this.profileStorage); + const oldProfileStorage = assertReturnsDefined(this.profileStorage); const oldItems = oldProfileStorage.items; // Close old profile storage but only if this is @@ -181,7 +181,7 @@ export class BrowserStorageService extends AbstractStorageService { await this.createProfileStorage(toProfile); // Handle data switch and eventing - this.switchData(oldItems, assertIsDefined(this.profileStorage), StorageScope.PROFILE); + this.switchData(oldItems, assertReturnsDefined(this.profileStorage), StorageScope.PROFILE); } protected async switchToWorkspace(toWorkspace: IAnyWorkspaceIdentifier, preserveData: boolean): Promise { diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index c87a3d473b9..6ab27644450 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -7,7 +7,7 @@ import { localize } from '../../../../nls.js'; import { Emitter } from '../../../../base/common/event.js'; import { URI } from '../../../../base/common/uri.js'; import { mark } from '../../../../base/common/performance.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { EncodingMode, ITextFileService, TextFileEditorModelState, ITextFileEditorModel, ITextFileStreamContent, ITextFileResolveOptions, IResolvedTextFileEditorModel, TextFileResolveReason, ITextFileEditorModelSaveEvent, ITextFileSaveAsOptions } from './textfiles.js'; import { IRevertOptions, SaveReason, SaveSourceRegistry } from '../../../common/editor.js'; import { BaseTextEditorModel } from '../../../common/editor/textEditorModel.js'; @@ -929,7 +929,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // participant triggering progress.report({ message: localize('saveTextFile', "Writing into file...") }); this.trace(`doSave(${versionId}) - before write()`); - const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat); + const lastResolvedFileStat = assertReturnsDefined(this.lastResolvedFileStat); const resolvedTextFileEditorModel = this; return this.saveSequentializer.run(versionId, (async () => { try { diff --git a/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts index 2a7acd660f7..cde036203e0 100644 --- a/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts @@ -12,7 +12,7 @@ import { ensureNoDisposablesAreLeakedInTestSuite, toResource } from '../../../.. import { TextFileEditorModelManager } from '../../common/textFileEditorModelManager.js'; import { FileOperationResult, FileOperationError, NotModifiedSinceFileOperationError } from '../../../../../platform/files/common/files.js'; import { DeferredPromise, timeout } from '../../../../../base/common/async.js'; -import { assertIsDefined } from '../../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../../base/common/types.js'; import { createTextBufferFactory } from '../../../../../editor/common/model/textModel.js'; import { DisposableStore, toDisposable } from '../../../../../base/common/lifecycle.js'; import { SaveReason, SaveSourceRegistry } from '../../../../common/editor.js'; @@ -611,7 +611,7 @@ suite('Files - TextFileEditorModel', () => { await model.resolve(); - const stat = assertIsDefined(getLastResolvedFileStat(model)); + const stat = assertReturnsDefined(getLastResolvedFileStat(model)); accessor.textFileService.setReadStreamErrorOnce(new NotModifiedSinceFileOperationError('error', { ...stat, mtime: stat.mtime - 1, readonly: !stat.readonly, locked: !stat.locked })); await model.resolve(); @@ -641,8 +641,8 @@ suite('Files - TextFileEditorModel', () => { model1.updateTextEditorModel(createTextBufferFactory('foo')); - const m1Mtime = assertIsDefined(getLastResolvedFileStat(model1)).mtime; - const m2Mtime = assertIsDefined(getLastResolvedFileStat(model2)).mtime; + const m1Mtime = assertReturnsDefined(getLastResolvedFileStat(model1)).mtime; + const m2Mtime = assertReturnsDefined(getLastResolvedFileStat(model2)).mtime; assert.ok(m1Mtime > 0); assert.ok(m2Mtime > 0); @@ -662,12 +662,12 @@ suite('Files - TextFileEditorModel', () => { // web tests does not ensure timeouts are respected at all, so we cannot // really assert the mtime to be different, only that it is equal or greater. // https://github.com/microsoft/vscode/issues/161886 - assert.ok(assertIsDefined(getLastResolvedFileStat(model1)).mtime >= m1Mtime); - assert.ok(assertIsDefined(getLastResolvedFileStat(model2)).mtime >= m2Mtime); + assert.ok(assertReturnsDefined(getLastResolvedFileStat(model1)).mtime >= m1Mtime); + assert.ok(assertReturnsDefined(getLastResolvedFileStat(model2)).mtime >= m2Mtime); } else { // on desktop we want to assert this condition more strictly though - assert.ok(assertIsDefined(getLastResolvedFileStat(model1)).mtime > m1Mtime); - assert.ok(assertIsDefined(getLastResolvedFileStat(model2)).mtime > m2Mtime); + assert.ok(assertReturnsDefined(getLastResolvedFileStat(model1)).mtime > m1Mtime); + assert.ok(assertReturnsDefined(getLastResolvedFileStat(model2)).mtime > m2Mtime); } }); diff --git a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts index 31ff76a179e..c0526af39e8 100644 --- a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts +++ b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts @@ -18,7 +18,7 @@ import { IWorkingCopyService } from '../../workingCopy/common/workingCopyService import { IWorkingCopy, WorkingCopyCapabilities, IWorkingCopyBackup, NO_TYPE_ID, IWorkingCopySaveEvent } from '../../workingCopy/common/workingCopy.js'; import { IEncodingSupport, ILanguageSupport, ITextFileService } from '../../textfile/common/textfiles.js'; import { IModelContentChangedEvent } from '../../../../editor/common/textModelEvents.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { ILabelService } from '../../../../platform/label/common/label.js'; import { ensureValidWordDefinition } from '../../../../editor/common/core/wordHelper.js'; import { IEditorService } from '../../editor/common/editorService.js'; @@ -349,7 +349,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt } // Listen to text model events - const textEditorModel = assertIsDefined(this.textEditorModel); + const textEditorModel = assertReturnsDefined(this.textEditorModel); this.installModelListeners(textEditorModel); // Only adjust name and dirty state etc. if we diff --git a/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts b/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts index 97e0c77dd21..3565d55c3c9 100644 --- a/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts +++ b/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts @@ -11,7 +11,7 @@ import { workbenchInstantiationService } from '../../../../test/browser/workbenc import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js'; import { SyncDescriptor } from '../../../../../platform/instantiation/common/descriptors.js'; import { ViewDescriptorService } from '../../browser/viewDescriptorService.js'; -import { assertIsDefined } from '../../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../../base/common/types.js'; import { ContextKeyService } from '../../../../../platform/contextkey/browser/contextKeyService.js'; import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../../platform/storage/common/storage.js'; @@ -172,8 +172,8 @@ suite('ViewDescriptorService', () => { assert.strictEqual(sidebarViews.activeViewDescriptors.length, 1, 'Sidebar container should have 1 view'); assert.strictEqual(panelViews.activeViewDescriptors.length, 0, 'Panel container should have no views'); - const generatedPanel = assertIsDefined(testObject.getViewContainerByViewId(viewDescriptors[0].id)); - const generatedSidebar = assertIsDefined(testObject.getViewContainerByViewId(viewDescriptors[2].id)); + const generatedPanel = assertReturnsDefined(testObject.getViewContainerByViewId(viewDescriptors[0].id)); + const generatedSidebar = assertReturnsDefined(testObject.getViewContainerByViewId(viewDescriptors[2].id)); assert.strictEqual(testObject.getViewContainerLocation(generatedPanel), ViewContainerLocation.Panel, 'Generated Panel should be in located in the panel'); assert.strictEqual(testObject.getViewContainerLocation(generatedSidebar), ViewContainerLocation.Sidebar, 'Generated Sidebar should be in located in the sidebar'); @@ -311,8 +311,8 @@ suite('ViewDescriptorService', () => { testObject.moveViewsToContainer([viewDescriptors[1]], panelContainer); testObject.moveViewToLocation(viewDescriptors[2], ViewContainerLocation.Sidebar); - const generatedPanel = assertIsDefined(testObject.getViewContainerByViewId(viewDescriptors[0].id)); - const generatedSidebar = assertIsDefined(testObject.getViewContainerByViewId(viewDescriptors[2].id)); + const generatedPanel = assertReturnsDefined(testObject.getViewContainerByViewId(viewDescriptors[0].id)); + const generatedSidebar = assertReturnsDefined(testObject.getViewContainerByViewId(viewDescriptors[2].id)); testObject.reset(); diff --git a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts index 39280946a7b..c12163d118e 100644 --- a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts +++ b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts @@ -13,7 +13,7 @@ import { IWorkingCopyService } from './workingCopyService.js'; import { IWorkingCopyBackup, IWorkingCopyBackupMeta, IWorkingCopySaveEvent, WorkingCopyCapabilities } from './workingCopy.js'; import { raceCancellation, TaskSequentializer, timeout } from '../../../../base/common/async.js'; import { ILogService } from '../../../../platform/log/common/log.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { IWorkingCopyFileService } from './workingCopyFileService.js'; import { VSBufferReadableStream } from '../../../../base/common/buffer.js'; import { IFilesConfigurationService } from '../../filesConfiguration/common/filesConfigurationService.js'; @@ -1029,7 +1029,7 @@ export class StoredFileWorkingCopy extend // participant triggering progress.report({ message: localize('saveTextFile', "Writing into file...") }); this.trace(`doSave(${versionId}) - before write()`); - const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat); + const lastResolvedFileStat = assertReturnsDefined(this.lastResolvedFileStat); const resolvedFileWorkingCopy = this; return this.saveSequentializer.run(versionId, (async () => { try { @@ -1074,9 +1074,9 @@ export class StoredFileWorkingCopy extend // Write them to disk if (options?.writeElevated && this.elevatedFileService.isSupported(lastResolvedFileStat.resource)) { - stat = await this.elevatedFileService.writeFileElevated(lastResolvedFileStat.resource, assertIsDefined(snapshot), writeFileOptions); + stat = await this.elevatedFileService.writeFileElevated(lastResolvedFileStat.resource, assertReturnsDefined(snapshot), writeFileOptions); } else { - stat = await this.fileService.writeFile(lastResolvedFileStat.resource, assertIsDefined(snapshot), writeFileOptions); + stat = await this.fileService.writeFile(lastResolvedFileStat.resource, assertReturnsDefined(snapshot), writeFileOptions); } } diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts index 3b11c22384d..048f33d93e0 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts @@ -5,7 +5,7 @@ import { localize } from '../../../../nls.js'; import { Event, Emitter } from '../../../../base/common/event.js'; -import { assertIsDefined } from '../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../base/common/types.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from '../../../common/contributions.js'; import { ILifecycleService, LifecyclePhase, WillShutdownEvent } from '../../lifecycle/common/lifecycle.js'; @@ -155,9 +155,9 @@ export class WorkingCopyHistoryModel { } private async doAddEntry(source: SaveSource, sourceDescription: string | undefined = undefined, timestamp: number, token: CancellationToken): Promise { - const workingCopyResource = assertIsDefined(this.workingCopyResource); - const workingCopyName = assertIsDefined(this.workingCopyName); - const historyEntriesFolder = assertIsDefined(this.historyEntriesFolder); + const workingCopyResource = assertReturnsDefined(this.workingCopyResource); + const workingCopyName = assertReturnsDefined(this.workingCopyName); + const historyEntriesFolder = assertReturnsDefined(this.historyEntriesFolder); // Perform a fast clone operation with minimal overhead to a new random location const id = `${randomPath(undefined, undefined, 4)}${extname(workingCopyResource)}`; @@ -185,7 +185,7 @@ export class WorkingCopyHistoryModel { } private async doReplaceEntry(entry: IWorkingCopyHistoryEntry, source: SaveSource, sourceDescription: string | undefined = undefined, timestamp: number, token: CancellationToken): Promise { - const workingCopyResource = assertIsDefined(this.workingCopyResource); + const workingCopyResource = assertReturnsDefined(this.workingCopyResource); // Perform a fast clone operation with minimal overhead to the existing location await this.fileService.cloneFile(workingCopyResource, entry.location); @@ -317,8 +317,8 @@ export class WorkingCopyHistoryModel { } private async resolveEntriesFromDisk(): Promise> { - const workingCopyResource = assertIsDefined(this.workingCopyResource); - const workingCopyName = assertIsDefined(this.workingCopyName); + const workingCopyResource = assertReturnsDefined(this.workingCopyResource); + const workingCopyName = assertReturnsDefined(this.workingCopyName); const [entryListing, entryStats] = await Promise.all([ @@ -364,13 +364,13 @@ export class WorkingCopyHistoryModel { async moveEntries(target: WorkingCopyHistoryModel, source: SaveSource, token: CancellationToken): Promise { const timestamp = Date.now(); - const sourceDescription = this.labelService.getUriLabel(assertIsDefined(this.workingCopyResource)); + const sourceDescription = this.labelService.getUriLabel(assertReturnsDefined(this.workingCopyResource)); // Move all entries into the target folder so that we preserve // any existing history entries that might already be present - const sourceHistoryEntriesFolder = assertIsDefined(this.historyEntriesFolder); - const targetHistoryEntriesFolder = assertIsDefined(target.historyEntriesFolder); + const sourceHistoryEntriesFolder = assertReturnsDefined(this.historyEntriesFolder); + const targetHistoryEntriesFolder = assertReturnsDefined(target.historyEntriesFolder); try { for (const entry of this.entries) { await this.fileService.move(entry.location, joinPath(targetHistoryEntriesFolder, entry.id), true); @@ -393,11 +393,11 @@ export class WorkingCopyHistoryModel { const allEntries = distinct([...this.entries, ...target.entries], entry => entry.id).sort((entryA, entryB) => entryA.timestamp - entryB.timestamp); // Update our associated working copy - const targetWorkingCopyResource = assertIsDefined(target.workingCopyResource); + const targetWorkingCopyResource = assertReturnsDefined(target.workingCopyResource); this.setWorkingCopy(targetWorkingCopyResource); // Restore our entries and ensure correct metadata - const targetWorkingCopyName = assertIsDefined(target.workingCopyName); + const targetWorkingCopyName = assertReturnsDefined(target.workingCopyName); for (const entry of allEntries) { this.entries.push({ id: entry.id, @@ -441,7 +441,7 @@ export class WorkingCopyHistoryModel { } private async doStore(token: CancellationToken): Promise { - const historyEntriesFolder = assertIsDefined(this.historyEntriesFolder); + const historyEntriesFolder = assertReturnsDefined(this.historyEntriesFolder); // Make sure to await resolving when persisting await this.resolveEntriesOnce(); @@ -505,8 +505,8 @@ export class WorkingCopyHistoryModel { } private async writeEntriesFile(): Promise { - const workingCopyResource = assertIsDefined(this.workingCopyResource); - const historyEntriesListingFile = assertIsDefined(this.historyEntriesListingFile); + const workingCopyResource = assertReturnsDefined(this.workingCopyResource); + const historyEntriesListingFile = assertReturnsDefined(this.historyEntriesListingFile); const serializedModel: ISerializedWorkingCopyHistoryModel = { version: 1, @@ -525,7 +525,7 @@ export class WorkingCopyHistoryModel { } private async readEntriesFile(): Promise { - const historyEntriesListingFile = assertIsDefined(this.historyEntriesListingFile); + const historyEntriesListingFile = assertReturnsDefined(this.historyEntriesListingFile); let serializedModel: ISerializedWorkingCopyHistoryModel | undefined = undefined; try { @@ -540,8 +540,8 @@ export class WorkingCopyHistoryModel { } private async readEntriesFolder(): Promise { - const historyEntriesFolder = assertIsDefined(this.historyEntriesFolder); - const historyEntriesNameMatcher = assertIsDefined(this.historyEntriesNameMatcher); + const historyEntriesFolder = assertReturnsDefined(this.historyEntriesFolder); + const historyEntriesNameMatcher = assertReturnsDefined(this.historyEntriesNameMatcher); let rawEntries: IFileStatWithMetadata[] | undefined = undefined; diff --git a/src/vs/workbench/services/workingCopy/test/browser/storedFileWorkingCopy.test.ts b/src/vs/workbench/services/workingCopy/test/browser/storedFileWorkingCopy.test.ts index 7d4a030d363..62c7cd79ea9 100644 --- a/src/vs/workbench/services/workingCopy/test/browser/storedFileWorkingCopy.test.ts +++ b/src/vs/workbench/services/workingCopy/test/browser/storedFileWorkingCopy.test.ts @@ -20,7 +20,7 @@ import { consumeReadable, consumeStream, isReadableStream } from '../../../../.. import { runWithFakedTimers } from '../../../../../base/test/common/timeTravelScheduler.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; import { SnapshotContext } from '../../common/fileWorkingCopy.js'; -import { assertIsDefined } from '../../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../../base/common/types.js'; export class TestStoredFileWorkingCopyModel extends Disposable implements IStoredFileWorkingCopyModel { @@ -518,7 +518,7 @@ suite('StoredFileWorkingCopy', function () { await workingCopy.resolve(); - const stat = assertIsDefined(getLastResolvedFileStat(workingCopy)); + const stat = assertReturnsDefined(getLastResolvedFileStat(workingCopy)); try { accessor.fileService.readShouldThrowError = new NotModifiedSinceFileOperationError('error', { ...stat, mtime: stat.mtime - 1, readonly: !stat.readonly, locked: !stat.locked }); await workingCopy.resolve(); diff --git a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryTracker.test.ts b/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryTracker.test.ts index 82f53dbd286..3bc44671452 100644 --- a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryTracker.test.ts +++ b/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryTracker.test.ts @@ -23,7 +23,7 @@ import { TestDialogService } from '../../../../../platform/dialogs/test/common/t import { TestNotificationService } from '../../../../../platform/notification/test/common/testNotificationService.js'; import { CancellationToken } from '../../../../../base/common/cancellation.js'; import { IWorkingCopyHistoryEntry, IWorkingCopyHistoryEntryDescriptor } from '../../common/workingCopyHistory.js'; -import { assertIsDefined } from '../../../../../base/common/types.js'; +import { assertReturnsDefined } from '../../../../../base/common/types.js'; import { VSBuffer } from '../../../../../base/common/buffer.js'; import { DisposableStore } from '../../../../../base/common/lifecycle.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; @@ -63,7 +63,7 @@ suite('WorkingCopyHistoryTracker', () => { timestamp: increasingTimestampCounter++ // very important to get tests to not be flaky with stable sort order }, token); - return assertIsDefined(entry); + return assertReturnsDefined(entry); } setup(async () => { diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 0eddf27ee9f..b9f1daec9db 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -123,7 +123,7 @@ import { IEnterWorkspaceResult, IRecent, IRecentlyOpened, IWorkspaceFolderCreati import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from '../../../platform/workspace/common/workspaceTrust.js'; import { IExtensionTerminalProfile, IShellLaunchConfig, ITerminalBackend, ITerminalLogService, ITerminalProfile, TerminalIcon, TerminalLocation, TerminalShellType } from '../../../platform/terminal/common/terminal.js'; import { ICreateTerminalOptions, IDeserializedTerminalEditorInput, ITerminalConfigurationService, ITerminalEditorService, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, TerminalEditorLocation } from '../../contrib/terminal/browser/terminal.js'; -import { assertIsDefined, upcast } from '../../../base/common/types.js'; +import { assertReturnsDefined, upcast } from '../../../base/common/types.js'; import { IRegisterContributedProfileArgs, IShellLaunchConfigResolveOptions, ITerminalProfileProvider, ITerminalProfileResolverService, ITerminalProfileService, type ITerminalConfiguration } from '../../contrib/terminal/common/terminal.js'; import { EditorResolverService } from '../../services/editor/browser/editorResolverService.js'; import { FILE_EDITOR_INPUT_ID } from '../../contrib/files/common/files.js'; @@ -739,7 +739,7 @@ export class TestPaneCompositeService extends Disposable implements IPaneComposi } getPartByLocation(viewContainerLocation: ViewContainerLocation): IPaneCompositePart { - return assertIsDefined(this.parts.get(viewContainerLocation)); + return assertReturnsDefined(this.parts.get(viewContainerLocation)); } } From 45e745153a6c2751f6201f25899edc9ec2a353d2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 6 Jun 2025 16:09:13 +0200 Subject: [PATCH 075/236] chat - core provided chat submenus in components (#250851) --- .../chat/browser/actions/chatActions.ts | 30 ++++++++++++++++ .../contrib/chat/browser/chatSetup.ts | 35 +------------------ .../actions/common/menusExtensionPoint.ts | 21 +++++++++++ 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index 569f84fe774..e8c46616b85 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -1036,3 +1036,33 @@ export function shouldShowClearEditingSessionConfirmation(editingSession: IChatE return false; } + +// --- Chat Submenus in various Components + +const menuContext = ContextKeyExpr.and( + ChatContextKeys.Setup.hidden.negate(), + ChatContextKeys.Setup.disabled.negate() +); + +const title = localize('copilot', "Copilot"); + +MenuRegistry.appendMenuItem(MenuId.EditorContext, { + submenu: MenuId.ChatTextEditorMenu, + group: '1_copilot', + title, + when: menuContext +}); + +MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { + submenu: MenuId.ChatExplorerMenu, + group: '5_copilot', + title, + when: menuContext +}); + +MenuRegistry.appendMenuItem(MenuId.TerminalInstanceContext, { + submenu: MenuId.ChatTerminalMenu, + group: '2_copilot', + title, + when: menuContext +}); diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup.ts b/src/vs/workbench/contrib/chat/browser/chatSetup.ts index d9ef1a37fee..0883840ff6f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup.ts @@ -24,7 +24,7 @@ import { URI } from '../../../../base/common/uri.js'; import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js'; import { MarkdownRenderer } from '../../../../editor/browser/widget/markdownRenderer/browser/markdownRenderer.js'; import { localize, localize2 } from '../../../../nls.js'; -import { Action2, MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js'; +import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { ConfigurationTarget, IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js'; @@ -988,7 +988,6 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr this.registerSetupAgents(context, controller); this.registerActions(context, requests, controller); - this.registerMenus(); this.registerUrlLinkHandler(); } @@ -1294,38 +1293,6 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr registerAction2(EnableOveragesAction); } - private registerMenus(): void { - const menuContext = ContextKeyExpr.and( - // TODO@bpasero this needs to be revisited when the Copilot - // extension contributes this OOTB where this menu is also - // defined. - ChatContextKeys.Setup.installed.negate(), - ChatContextKeys.Setup.hidden.negate(), - ChatContextKeys.Setup.disabled.negate() - ); - - MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { - submenu: MenuId.ChatExplorerMenu, - group: '5_copilot', - title: localize('title4', "Copilot"), - when: menuContext - }); - - MenuRegistry.appendMenuItem(MenuId.EditorContext, { - submenu: MenuId.ChatTextEditorMenu, - group: '1_copilot', - title: localize('title4', "Copilot"), - when: menuContext - }); - - MenuRegistry.appendMenuItem(MenuId.TerminalInstanceContext, { - submenu: MenuId.ChatTerminalMenu, - group: '2_copilot', - title: localize('title4', "Copilot"), - when: menuContext - }); - } - private registerUrlLinkHandler(): void { this._register(ExtensionUrlHandlerOverrideRegistry.registerHandler({ canHandleURL: url => { diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index 0b925420ce3..26fb7ff3889 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -450,6 +450,27 @@ const apiMenus: IAPIMenu[] = [ description: localize('menus.chatModelPicker', "The chat model picker dropdown menu"), supportsSubmenus: false, proposed: 'chatParticipantPrivate' + }, + { + key: 'explorer/context/chat', + id: MenuId.ChatExplorerMenu, + description: localize('menus.chatExplorer', "The Chat submenu in the explorer context menu."), + supportsSubmenus: false, + proposed: 'chatParticipantPrivate' + }, + { + key: 'editor/context/chat', + id: MenuId.ChatTextEditorMenu, + description: localize('menus.chatTextEditor', "The Chat submenu in the text editor context menu."), + supportsSubmenus: false, + proposed: 'chatParticipantPrivate' + }, + { + key: 'terminal/context/chat', + id: MenuId.ChatTerminalMenu, + description: localize('menus.chatTerminal', "The Chat submenu in the terminal context menu."), + supportsSubmenus: false, + proposed: 'chatParticipantPrivate' } ]; From 74a9183a511a6bf718f9023966688a0f116f9497 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 6 Jun 2025 15:56:46 +0200 Subject: [PATCH 076/236] Fixes https://github.com/microsoft/vscode-copilot/issues/13637 --- .../components/accessibleDiffViewer.css | 107 +++++++++--------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/src/vs/editor/browser/widget/diffEditor/components/accessibleDiffViewer.css b/src/vs/editor/browser/widget/diffEditor/components/accessibleDiffViewer.css index 640909467f4..9e89061045d 100644 --- a/src/vs/editor/browser/widget/diffEditor/components/accessibleDiffViewer.css +++ b/src/vs/editor/browser/widget/diffEditor/components/accessibleDiffViewer.css @@ -3,70 +3,75 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-component.diff-review { - user-select: none; - -webkit-user-select: none; - z-index: 99; -} - .monaco-diff-editor .diff-review { position: absolute; } -.monaco-component.diff-review .diff-review-line-number { - text-align: right; - display: inline-block; - color: var(--vscode-editorLineNumber-foreground); -} +.monaco-component.diff-review { + user-select: none; + -webkit-user-select: none; + z-index: 99; -.monaco-component.diff-review .diff-review-summary { - padding-left: 10px; -} -.monaco-component.diff-review .diff-review-shadow { - position: absolute; - box-shadow: var(--vscode-scrollbar-shadow) 0 -6px 6px -6px inset; -} + .diff-review-line-number { + text-align: right; + display: inline-block; + color: var(--vscode-editorLineNumber-foreground); + } -.monaco-component.diff-review .diff-review-row { - white-space: pre; -} + .diff-review-summary { + padding-left: 10px; + } -.monaco-component.diff-review .diff-review-table { - display: table; - min-width: 100%; -} + .diff-review-shadow { + position: absolute; + box-shadow: var(--vscode-scrollbar-shadow) 0 -6px 6px -6px inset; + } -.monaco-component.diff-review .diff-review-row { - display: table-row; - width: 100%; -} + .diff-review-row { + white-space: pre; + } -.monaco-component.diff-review .diff-review-spacer { - display: inline-block; - width: 10px; - vertical-align: middle; -} + .diff-review-table { + display: table; + min-width: 100%; + } -.monaco-component.diff-review .diff-review-spacer > .codicon { - font-size: 9px !important; -} + .diff-review-row { + display: table-row; + width: 100%; + } -.monaco-component.diff-review .diff-review-actions { - display: inline-block; - position: absolute; - right: 10px; - top: 2px; - z-index: 100; -} + .diff-review-spacer { + display: inline-block; + width: 10px; + vertical-align: middle; + } -.monaco-component.diff-review .diff-review-actions .action-label { - width: 16px; - height: 16px; - margin: 2px 0; -} + .diff-review-spacer > .codicon { + font-size: 9px !important; + } -.monaco-component.diff-review .revertButton { - cursor: pointer; + .diff-review-actions { + display: inline-block; + position: absolute; + right: 10px; + top: 2px; + z-index: 100; + } + + .diff-review-actions .action-label { + width: 16px; + height: 16px; + margin: 2px 0; + } + + .revertButton { + cursor: pointer; + } + + .action-label { + background: var(--vscode-editorActionList-background); + } } From 13ff4544a729ebff787f1101878b36d8fdf2eb9d Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 6 Jun 2025 16:27:14 +0200 Subject: [PATCH 077/236] Fixes https://github.com/microsoft/vscode/issues/230056. (#250856) Co-authored-by: Dipta Mahardhika <146386738+d-mahard@users.noreply.github.com> --- .../editor/contrib/placeholderText/browser/placeholderText.css | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/editor/contrib/placeholderText/browser/placeholderText.css b/src/vs/editor/contrib/placeholderText/browser/placeholderText.css index 043b6f15632..0e533bad4c6 100644 --- a/src/vs/editor/contrib/placeholderText/browser/placeholderText.css +++ b/src/vs/editor/contrib/placeholderText/browser/placeholderText.css @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ .monaco-editor { - --vscode-editor-placeholder-foreground: var(--vscode-editorGhostText-foreground); - .editorPlaceholder { top: 0px; position: absolute; From 4ebad700d6e83ecc4ce25effe93b6b834946f64b Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 6 Jun 2025 16:18:05 +0200 Subject: [PATCH 078/236] SingleLineEdit -> LineReplacement --- src/vs/editor/common/core/edits/lineEdit.ts | 26 +++++++++---------- .../view/inlineEdits/inlineEditWithChanges.ts | 4 +-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/common/core/edits/lineEdit.ts b/src/vs/editor/common/core/edits/lineEdit.ts index c7dd4b6dd55..1d734579201 100644 --- a/src/vs/editor/common/core/edits/lineEdit.ts +++ b/src/vs/editor/common/core/edits/lineEdit.ts @@ -17,7 +17,7 @@ export class LineEdit { public static readonly empty = new LineEdit([]); public static deserialize(data: SerializedLineEdit): LineEdit { - return new LineEdit(data.map(e => SingleLineEdit.deserialize(e))); + return new LineEdit(data.map(e => LineReplacement.deserialize(e))); } public static fromEdit(edit: StringEdit, initialValue: AbstractText): LineEdit { @@ -28,7 +28,7 @@ export class LineEdit { public static fromTextEdit(edit: TextEdit, initialValue: AbstractText): LineEdit { const edits = edit.replacements; - const result: SingleLineEdit[] = []; + const result: LineReplacement[] = []; const currentEdits: TextReplacement[] = []; for (let i = 0; i < edits.length; i++) { @@ -42,14 +42,14 @@ export class LineEdit { const singleEdit = TextReplacement.joinReplacements(currentEdits, initialValue); currentEdits.length = 0; - const singleLineEdit = SingleLineEdit.fromSingleTextEdit(singleEdit, initialValue); + const singleLineEdit = LineReplacement.fromSingleTextEdit(singleEdit, initialValue); result.push(singleLineEdit); } return new LineEdit(result); } - public static createFromUnsorted(edits: readonly SingleLineEdit[]): LineEdit { + public static createFromUnsorted(edits: readonly LineReplacement[]): LineEdit { const result = edits.slice(); result.sort(compareBy(i => i.lineRange.startLineNumber, numberComparator)); return new LineEdit(result); @@ -59,7 +59,7 @@ export class LineEdit { /** * Have to be sorted by start line number and non-intersecting. */ - public readonly edits: readonly SingleLineEdit[] + public readonly edits: readonly LineReplacement[] ) { assert(checkAdjacentItems(edits, (i1, i2) => i1.lineRange.endLineNumberExclusive <= i2.lineRange.startLineNumber)); } @@ -112,7 +112,7 @@ export class LineEdit { public rebase(base: LineEdit): LineEdit { return new LineEdit( - this.edits.map(e => new SingleLineEdit(base.mapLineRange(e.lineRange), e.newLines)), + this.edits.map(e => new LineReplacement(base.mapLineRange(e.lineRange), e.newLines)), ); } @@ -208,15 +208,15 @@ export class LineEdit { } } -export class SingleLineEdit { - public static deserialize(e: SerializedSingleLineEdit): SingleLineEdit { - return new SingleLineEdit( +export class LineReplacement { + public static deserialize(e: SerializedSingleLineEdit): LineReplacement { + return new LineReplacement( LineRange.ofLength(e[0], e[1] - e[0]), e[2], ); } - public static fromSingleTextEdit(edit: TextReplacement, initialValue: AbstractText): SingleLineEdit { + public static fromSingleTextEdit(edit: TextReplacement, initialValue: AbstractText): LineReplacement { // 1: ab[cde // 2: fghijk // 3: lmn]opq @@ -262,7 +262,7 @@ export class SingleLineEdit { newLines.pop(); } - return new SingleLineEdit(new LineRange(startLineNumber, endLineNumberEx), newLines); + return new LineReplacement(new LineRange(startLineNumber, endLineNumberEx), newLines); } constructor( @@ -343,7 +343,7 @@ export class SingleLineEdit { ]; } - public removeCommonSuffixPrefixLines(initialValue: AbstractText): SingleLineEdit { + public removeCommonSuffixPrefixLines(initialValue: AbstractText): LineReplacement { let startLineNumber = this.lineRange.startLineNumber; let endLineNumberEx = this.lineRange.endLineNumberExclusive; @@ -368,7 +368,7 @@ export class SingleLineEdit { if (trimStartCount === 0 && trimEndCount === 0) { return this; } - return new SingleLineEdit(new LineRange(startLineNumber, endLineNumberEx), this.newLines.slice(trimStartCount, this.newLines.length - trimEndCount)); + return new LineReplacement(new LineRange(startLineNumber, endLineNumberEx), this.newLines.slice(trimStartCount, this.newLines.length - trimEndCount)); } public toLineEdit(): LineEdit { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts index cd19acc154f..de4b6963ab7 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SingleLineEdit } from '../../../../../common/core/edits/lineEdit.js'; +import { LineReplacement } from '../../../../../common/core/edits/lineEdit.js'; import { LineRange } from '../../../../../common/core/ranges/lineRange.js'; import { Position } from '../../../../../common/core/position.js'; import { TextEdit } from '../../../../../common/core/edits/textEdit.js'; @@ -13,7 +13,7 @@ import { InlineSuggestionItem } from '../../model/inlineSuggestionItem.js'; export class InlineEditWithChanges { public get lineEdit() { - return SingleLineEdit.fromSingleTextEdit(this.edit.toReplacement(this.originalText), this.originalText); + return LineReplacement.fromSingleTextEdit(this.edit.toReplacement(this.originalText), this.originalText); } public get originalLineRange() { return this.lineEdit.lineRange; } From 84200a82590a0ff046664428c85a86b941e9d6ff Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 16:59:51 +0200 Subject: [PATCH 079/236] chore - remove unused `toolSelectionIsExclusive` fyi @roblourens (#250860) --- src/vs/workbench/contrib/chat/common/chatAgents.ts | 1 - src/vs/workbench/contrib/chat/common/chatService.ts | 1 - src/vs/workbench/contrib/chat/common/chatServiceImpl.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index dc121f603ea..267ec6bd626 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -138,7 +138,6 @@ export interface IChatAgentRequest { userSelectedModelId?: string; userSelectedTools?: Record; modeInstructions?: string; - toolSelectionIsExclusive?: boolean; editedFileEvents?: IChatAgentEditedFileEvent[]; } diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index bdafb01973f..60c1f5d8684 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -489,7 +489,6 @@ export interface IChatSendRequestOptions { userSelectedModelId?: string; userSelectedTools?: Record; modeInstructions?: string; - toolSelectionIsExclusive?: boolean; location?: ChatAgentLocation; locationData?: IChatLocationData; parserContext?: IChatParserContext; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 33d0893be93..3be67300df2 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -772,7 +772,6 @@ export class ChatService extends Disposable implements IChatService { userSelectedModelId: options?.userSelectedModelId, userSelectedTools: options?.userSelectedTools, modeInstructions: options?.modeInstructions, - toolSelectionIsExclusive: options?.toolSelectionIsExclusive, editedFileEvents: request.editedFileEvents } satisfies IChatAgentRequest; }; From bd0a5481605a5ed4a79c65ffa26958b5fcd2db98 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 08:02:05 -0700 Subject: [PATCH 080/236] Ensure test cases use argument completion kind only --- .../browser/terminalCompletionModel.test.ts | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts index 873ba7b74c0..e2ca94ef776 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts @@ -301,10 +301,10 @@ suite('TerminalCompletionModel', function () { suite('git branch priority sorting', () => { test('should prioritize main and master branches for git commands', () => { const items = [ - createItem({ label: 'feature-branch' }), - createItem({ label: 'master' }), - createItem({ label: 'development' }), - createItem({ label: 'main' }) + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'feature-branch' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'master' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'development' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'main' }) ]; const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); assertItems(model, ['main', 'master', 'development', 'feature-branch']); @@ -312,10 +312,10 @@ suite('TerminalCompletionModel', function () { test('should prioritize main and master branches for git switch command', () => { const items = [ - createItem({ label: 'feature-branch' }), - createItem({ label: 'main' }), - createItem({ label: 'another-feature' }), - createItem({ label: 'master' }) + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'feature-branch' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'main' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'another-feature' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'master' }) ]; const model = new TerminalCompletionModel(items, new LineContext('git switch ', 0)); assertItems(model, ['main', 'master', 'another-feature', 'feature-branch']); @@ -323,9 +323,9 @@ suite('TerminalCompletionModel', function () { test('should not prioritize main and master for non-git commands', () => { const items = [ - createItem({ label: 'feature-branch' }), - createItem({ label: 'master' }), - createItem({ label: 'main' }) + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'feature-branch' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'master' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'main' }) ]; const model = new TerminalCompletionModel(items, new LineContext('ls ', 0)); assertItems(model, ['feature-branch', 'main', 'master']); @@ -333,9 +333,9 @@ suite('TerminalCompletionModel', function () { test('should handle git commands with leading whitespace', () => { const items = [ - createItem({ label: 'feature-branch' }), - createItem({ label: 'master' }), - createItem({ label: 'main' }) + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'feature-branch' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'master' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'main' }) ]; const model = new TerminalCompletionModel(items, new LineContext(' git checkout ', 0)); assertItems(model, ['main', 'master', 'feature-branch']); @@ -343,9 +343,9 @@ suite('TerminalCompletionModel', function () { test('should work with complex label objects', () => { const items = [ - createItem({ label: { label: 'feature-branch', description: 'Feature branch' } }), - createItem({ label: { label: 'master', description: 'Master branch' } }), - createItem({ label: { label: 'main', description: 'Main branch' } }) + createItem({ kind: TerminalCompletionItemKind.Argument, label: { label: 'feature-branch', description: 'Feature branch' } }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: { label: 'master', description: 'Master branch' } }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: { label: 'main', description: 'Main branch' } }) ]; const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); assertItems(model, [ From 34154920886b6c0281e93656dda9971bcea8d4fd Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 08:05:55 -0700 Subject: [PATCH 081/236] Add more test cases --- .../browser/terminalCompletionModel.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts index e2ca94ef776..e39bd78a386 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionModel.test.ts @@ -354,5 +354,26 @@ suite('TerminalCompletionModel', function () { { label: "feature-branch", description: "Feature branch" }, ]); }); + + test('should not prioritize branches with similar names', () => { + const items = [ + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'mainline' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'masterpiece' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'main' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'master' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext('git checkout ', 0)); + assertItems(model, ['main', 'master', 'mainline', 'masterpiece']); + }); + + test('should prioritize for git branch -d', () => { + const items = [ + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'main' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'master' }), + createItem({ kind: TerminalCompletionItemKind.Argument, label: 'dev' }) + ]; + const model = new TerminalCompletionModel(items, new LineContext('git branch -d ', 0)); + assertItems(model, ['main', 'master', 'dev']); + }); }); }); From fe00a26ec8a50c1e8d0b894bde893debb8d8129e Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 08:18:34 -0700 Subject: [PATCH 082/236] xterm@5.6.0-beta.110 Fixes #190629 --- package-lock.json | 96 ++++++++++++++++++------------------ package.json | 20 ++++---- remote/package-lock.json | 96 ++++++++++++++++++------------------ remote/package.json | 20 ++++---- remote/web/package-lock.json | 88 ++++++++++++++++----------------- remote/web/package.json | 18 +++---- 6 files changed, 169 insertions(+), 169 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e44da42eb6..a98acf27573 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,16 +27,16 @@ "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.90", - "@xterm/addon-image": "^0.9.0-beta.107", - "@xterm/addon-ligatures": "^0.10.0-beta.107", - "@xterm/addon-progress": "^0.2.0-beta.13", - "@xterm/addon-search": "^0.16.0-beta.107", - "@xterm/addon-serialize": "^0.14.0-beta.107", - "@xterm/addon-unicode11": "^0.9.0-beta.107", - "@xterm/addon-webgl": "^0.19.0-beta.107", - "@xterm/headless": "^5.6.0-beta.107", - "@xterm/xterm": "^5.6.0-beta.107", + "@xterm/addon-clipboard": "^0.2.0-beta.93", + "@xterm/addon-image": "^0.9.0-beta.110", + "@xterm/addon-ligatures": "^0.10.0-beta.110", + "@xterm/addon-progress": "^0.2.0-beta.16", + "@xterm/addon-search": "^0.16.0-beta.110", + "@xterm/addon-serialize": "^0.14.0-beta.110", + "@xterm/addon-unicode11": "^0.9.0-beta.110", + "@xterm/addon-webgl": "^0.19.0-beta.110", + "@xterm/headless": "^5.6.0-beta.110", + "@xterm/xterm": "^5.6.0-beta.110", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", @@ -3286,30 +3286,30 @@ } }, "node_modules/@xterm/addon-clipboard": { - "version": "0.2.0-beta.90", - "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.90.tgz", - "integrity": "sha512-2i7qtACRBYRTRba831ufEjQMeAvK4uuVPYPBkSXzKJ/dIAvhws5B6OOmxqZzR97OsmzUC/SrjHSujgwyD0MVVw==", + "version": "0.2.0-beta.93", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.93.tgz", + "integrity": "sha512-A+XZnJgROYtvcIVGGYM6lH5PbXdVoMz/c140Pq9wu0jq++z3zHkcfTIMWO8E/xrvCO9Op3LTv9fu5NEhOI2l3A==", "license": "MIT", "dependencies": { "js-base64": "^3.7.5" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-image": { - "version": "0.9.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.107.tgz", - "integrity": "sha512-/vqb2BhVjJeCcOIDSpjWrfXbhNTCse95qkKbpmzFkQJJEh0CyaqjSUBIAM+Qcl9f/x6H//O2wADnn3Wsn5qYsg==", + "version": "0.9.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.110.tgz", + "integrity": "sha512-mzs2nIWqVay/1q3H74UQZwE0/MU4pNTEIkle3n+sYYbFJh8ZVOPKQfnl5ze7DWnQnqm3hqg2FDXZKfXj8fkdEA==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-ligatures": { - "version": "0.10.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.10.0-beta.107.tgz", - "integrity": "sha512-3qQZz6dPS8XlGGwz1p5Bqjoosah6Km1GwGeNv7YxkCVU2kpTOymFH8BMUEOFC5WHdYseDXnz8hIEleexF9Pa2g==", + "version": "0.10.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.10.0-beta.110.tgz", + "integrity": "sha512-k8ILGtdbmUTJURGX0h857C3F6KXxIwrOpsfEC5v1k3ffW3mJn6qkKOTmOyS89QcpWXXbbqvLJRLQ7FWGKYvlgg==", "license": "MIT", "dependencies": { "font-finder": "^1.1.0", @@ -3319,64 +3319,64 @@ "node": ">8.0.0" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-progress": { - "version": "0.2.0-beta.13", - "resolved": "https://registry.npmjs.org/@xterm/addon-progress/-/addon-progress-0.2.0-beta.13.tgz", - "integrity": "sha512-BLmX+JdA+LLOMbVLQm+gPqieeKaVMiugBFpCtQtBus3kCs/2/F8pU/XNGV31CnXxDdRjptyOGrPVRreF/rDdcg==", + "version": "0.2.0-beta.16", + "resolved": "https://registry.npmjs.org/@xterm/addon-progress/-/addon-progress-0.2.0-beta.16.tgz", + "integrity": "sha512-VqxaYIMx8TjeL9s4CYxMP8kFOQPEhcjEzrSLqYmpvhY2RpCJrDjf0HPh/wy9HDADJIWLZE6Gjcva7yub02fJXg==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-search": { - "version": "0.16.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.107.tgz", - "integrity": "sha512-poHjeKjnTKtS6rHyu3r5lhW/0rdLcRMSJLDmT9xo9lfTuyhfcUl8gro44iPtscKY+LEtrhZcortTlElMewy/Bw==", + "version": "0.16.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.110.tgz", + "integrity": "sha512-f7pi12E/7lD5Oz/Wrt3DL6kXOU7jVjA6ZAXisznBQTH1M4vxY3agvgUYVHWYFHyY1uWwheL1K089nzfjT5A1Lg==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-serialize": { - "version": "0.14.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.107.tgz", - "integrity": "sha512-MGaoO2zlNuSGofX5Xfbw+MU2wgAApEsDOPeYoEBSQyLf5BR7Z2rGVCxFyF5zNsIhNDov7ptQIVpCfonMVAgUvg==", + "version": "0.14.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.110.tgz", + "integrity": "sha512-uCHdHwwp2HWTCSMavkmYylgebiCGW+P76XJp04uVJnMBIPTSLGKygiCRQbxDsRB6mblsYislMEw4P9egKl/eqA==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-unicode11": { - "version": "0.9.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.107.tgz", - "integrity": "sha512-XTfJ1G7u+8zOT6faCfEB49AbVFAX4XWUoiLtyXCfRvbrVuv5wv53T03dLtBtpwjWoFaveLKGl3ZiU7t3dpl0RA==", + "version": "0.9.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.110.tgz", + "integrity": "sha512-HMfvm7ZaUgN2I78Lk/YXazfnLTntCwZidi25BtVNJWy+ibgSM9EUfs/AsnDx8JbeTPqGpHxvybWaIUC3maNurQ==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-webgl": { - "version": "0.19.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.107.tgz", - "integrity": "sha512-wdUkYiV4PnR9+7+1giJoFm5xrguCOKTH4xdQ/6lYuSbgMS0y1ykpcQjDNshwHy0TyUuh4o4z1+rd48qNjqGM6Q==", + "version": "0.19.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.110.tgz", + "integrity": "sha512-1fVHcG5lKdencCBI6b6ZZwlTs54Ax3EtbngkgwVHnqVR4jMmHQ5E8G/AH6Vk+OpVNANW+//oArDtosFUIDFKWw==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/headless": { - "version": "5.6.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.107.tgz", - "integrity": "sha512-jFoJEPXjffcSzQyf/fTh3eZsXuHP/xQmkezkKbmrkzxw5h40NPbTPQbhTrsUCea2M12Mun1BrT8ScSYMjUCH3w==", + "version": "5.6.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.110.tgz", + "integrity": "sha512-3oT+fvaQ8kr6kBIuBhH28Npg0KYSCcR6Jz/nJ1f23N0ANBqDJV2Ou0VDqfX+KsxdReG5moYKcYzhlccpdoy34A==", "license": "MIT" }, "node_modules/@xterm/xterm": { - "version": "5.6.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.107.tgz", - "integrity": "sha512-7cuJFZtc7Rv9BEpf9UsvErfXhLKkEmogI0mizgri+nNjEENnpQcFOpx84GFTjax/Zta8MAxOMUP1XU5Guju80A==", + "version": "5.6.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.110.tgz", + "integrity": "sha512-FPIKLySxbyWaXoBVbnc1KtbJe6CUV9DxZ9LHSs2gNHMN2jPmBhtdpDppeMqWwdmuCDBk9OcMSTPQNHT+mI4gSw==", "license": "MIT" }, "node_modules/@xtuc/ieee754": { diff --git a/package.json b/package.json index c3170a7fc6d..b195779ddd0 100644 --- a/package.json +++ b/package.json @@ -86,16 +86,16 @@ "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.90", - "@xterm/addon-image": "^0.9.0-beta.107", - "@xterm/addon-ligatures": "^0.10.0-beta.107", - "@xterm/addon-progress": "^0.2.0-beta.13", - "@xterm/addon-search": "^0.16.0-beta.107", - "@xterm/addon-serialize": "^0.14.0-beta.107", - "@xterm/addon-unicode11": "^0.9.0-beta.107", - "@xterm/addon-webgl": "^0.19.0-beta.107", - "@xterm/headless": "^5.6.0-beta.107", - "@xterm/xterm": "^5.6.0-beta.107", + "@xterm/addon-clipboard": "^0.2.0-beta.93", + "@xterm/addon-image": "^0.9.0-beta.110", + "@xterm/addon-ligatures": "^0.10.0-beta.110", + "@xterm/addon-progress": "^0.2.0-beta.16", + "@xterm/addon-search": "^0.16.0-beta.110", + "@xterm/addon-serialize": "^0.14.0-beta.110", + "@xterm/addon-unicode11": "^0.9.0-beta.110", + "@xterm/addon-webgl": "^0.19.0-beta.110", + "@xterm/headless": "^5.6.0-beta.110", + "@xterm/xterm": "^5.6.0-beta.110", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", diff --git a/remote/package-lock.json b/remote/package-lock.json index a69a4a75ac4..22cf60e74b7 100644 --- a/remote/package-lock.json +++ b/remote/package-lock.json @@ -20,16 +20,16 @@ "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.90", - "@xterm/addon-image": "^0.9.0-beta.107", - "@xterm/addon-ligatures": "^0.10.0-beta.107", - "@xterm/addon-progress": "^0.2.0-beta.13", - "@xterm/addon-search": "^0.16.0-beta.107", - "@xterm/addon-serialize": "^0.14.0-beta.107", - "@xterm/addon-unicode11": "^0.9.0-beta.107", - "@xterm/addon-webgl": "^0.19.0-beta.107", - "@xterm/headless": "^5.6.0-beta.107", - "@xterm/xterm": "^5.6.0-beta.107", + "@xterm/addon-clipboard": "^0.2.0-beta.93", + "@xterm/addon-image": "^0.9.0-beta.110", + "@xterm/addon-ligatures": "^0.10.0-beta.110", + "@xterm/addon-progress": "^0.2.0-beta.16", + "@xterm/addon-search": "^0.16.0-beta.110", + "@xterm/addon-serialize": "^0.14.0-beta.110", + "@xterm/addon-unicode11": "^0.9.0-beta.110", + "@xterm/addon-webgl": "^0.19.0-beta.110", + "@xterm/headless": "^5.6.0-beta.110", + "@xterm/xterm": "^5.6.0-beta.110", "cookie": "^0.7.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", @@ -523,30 +523,30 @@ "hasInstallScript": true }, "node_modules/@xterm/addon-clipboard": { - "version": "0.2.0-beta.90", - "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.90.tgz", - "integrity": "sha512-2i7qtACRBYRTRba831ufEjQMeAvK4uuVPYPBkSXzKJ/dIAvhws5B6OOmxqZzR97OsmzUC/SrjHSujgwyD0MVVw==", + "version": "0.2.0-beta.93", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.93.tgz", + "integrity": "sha512-A+XZnJgROYtvcIVGGYM6lH5PbXdVoMz/c140Pq9wu0jq++z3zHkcfTIMWO8E/xrvCO9Op3LTv9fu5NEhOI2l3A==", "license": "MIT", "dependencies": { "js-base64": "^3.7.5" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-image": { - "version": "0.9.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.107.tgz", - "integrity": "sha512-/vqb2BhVjJeCcOIDSpjWrfXbhNTCse95qkKbpmzFkQJJEh0CyaqjSUBIAM+Qcl9f/x6H//O2wADnn3Wsn5qYsg==", + "version": "0.9.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.110.tgz", + "integrity": "sha512-mzs2nIWqVay/1q3H74UQZwE0/MU4pNTEIkle3n+sYYbFJh8ZVOPKQfnl5ze7DWnQnqm3hqg2FDXZKfXj8fkdEA==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-ligatures": { - "version": "0.10.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.10.0-beta.107.tgz", - "integrity": "sha512-3qQZz6dPS8XlGGwz1p5Bqjoosah6Km1GwGeNv7YxkCVU2kpTOymFH8BMUEOFC5WHdYseDXnz8hIEleexF9Pa2g==", + "version": "0.10.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.10.0-beta.110.tgz", + "integrity": "sha512-k8ILGtdbmUTJURGX0h857C3F6KXxIwrOpsfEC5v1k3ffW3mJn6qkKOTmOyS89QcpWXXbbqvLJRLQ7FWGKYvlgg==", "license": "MIT", "dependencies": { "font-finder": "^1.1.0", @@ -556,64 +556,64 @@ "node": ">8.0.0" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-progress": { - "version": "0.2.0-beta.13", - "resolved": "https://registry.npmjs.org/@xterm/addon-progress/-/addon-progress-0.2.0-beta.13.tgz", - "integrity": "sha512-BLmX+JdA+LLOMbVLQm+gPqieeKaVMiugBFpCtQtBus3kCs/2/F8pU/XNGV31CnXxDdRjptyOGrPVRreF/rDdcg==", + "version": "0.2.0-beta.16", + "resolved": "https://registry.npmjs.org/@xterm/addon-progress/-/addon-progress-0.2.0-beta.16.tgz", + "integrity": "sha512-VqxaYIMx8TjeL9s4CYxMP8kFOQPEhcjEzrSLqYmpvhY2RpCJrDjf0HPh/wy9HDADJIWLZE6Gjcva7yub02fJXg==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-search": { - "version": "0.16.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.107.tgz", - "integrity": "sha512-poHjeKjnTKtS6rHyu3r5lhW/0rdLcRMSJLDmT9xo9lfTuyhfcUl8gro44iPtscKY+LEtrhZcortTlElMewy/Bw==", + "version": "0.16.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.110.tgz", + "integrity": "sha512-f7pi12E/7lD5Oz/Wrt3DL6kXOU7jVjA6ZAXisznBQTH1M4vxY3agvgUYVHWYFHyY1uWwheL1K089nzfjT5A1Lg==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-serialize": { - "version": "0.14.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.107.tgz", - "integrity": "sha512-MGaoO2zlNuSGofX5Xfbw+MU2wgAApEsDOPeYoEBSQyLf5BR7Z2rGVCxFyF5zNsIhNDov7ptQIVpCfonMVAgUvg==", + "version": "0.14.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.110.tgz", + "integrity": "sha512-uCHdHwwp2HWTCSMavkmYylgebiCGW+P76XJp04uVJnMBIPTSLGKygiCRQbxDsRB6mblsYislMEw4P9egKl/eqA==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-unicode11": { - "version": "0.9.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.107.tgz", - "integrity": "sha512-XTfJ1G7u+8zOT6faCfEB49AbVFAX4XWUoiLtyXCfRvbrVuv5wv53T03dLtBtpwjWoFaveLKGl3ZiU7t3dpl0RA==", + "version": "0.9.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.110.tgz", + "integrity": "sha512-HMfvm7ZaUgN2I78Lk/YXazfnLTntCwZidi25BtVNJWy+ibgSM9EUfs/AsnDx8JbeTPqGpHxvybWaIUC3maNurQ==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-webgl": { - "version": "0.19.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.107.tgz", - "integrity": "sha512-wdUkYiV4PnR9+7+1giJoFm5xrguCOKTH4xdQ/6lYuSbgMS0y1ykpcQjDNshwHy0TyUuh4o4z1+rd48qNjqGM6Q==", + "version": "0.19.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.110.tgz", + "integrity": "sha512-1fVHcG5lKdencCBI6b6ZZwlTs54Ax3EtbngkgwVHnqVR4jMmHQ5E8G/AH6Vk+OpVNANW+//oArDtosFUIDFKWw==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/headless": { - "version": "5.6.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.107.tgz", - "integrity": "sha512-jFoJEPXjffcSzQyf/fTh3eZsXuHP/xQmkezkKbmrkzxw5h40NPbTPQbhTrsUCea2M12Mun1BrT8ScSYMjUCH3w==", + "version": "5.6.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-5.6.0-beta.110.tgz", + "integrity": "sha512-3oT+fvaQ8kr6kBIuBhH28Npg0KYSCcR6Jz/nJ1f23N0ANBqDJV2Ou0VDqfX+KsxdReG5moYKcYzhlccpdoy34A==", "license": "MIT" }, "node_modules/@xterm/xterm": { - "version": "5.6.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.107.tgz", - "integrity": "sha512-7cuJFZtc7Rv9BEpf9UsvErfXhLKkEmogI0mizgri+nNjEENnpQcFOpx84GFTjax/Zta8MAxOMUP1XU5Guju80A==", + "version": "5.6.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.110.tgz", + "integrity": "sha512-FPIKLySxbyWaXoBVbnc1KtbJe6CUV9DxZ9LHSs2gNHMN2jPmBhtdpDppeMqWwdmuCDBk9OcMSTPQNHT+mI4gSw==", "license": "MIT" }, "node_modules/agent-base": { diff --git a/remote/package.json b/remote/package.json index 81dfbc01cee..8eefceeca6d 100644 --- a/remote/package.json +++ b/remote/package.json @@ -15,16 +15,16 @@ "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "^0.2.0-beta.90", - "@xterm/addon-image": "^0.9.0-beta.107", - "@xterm/addon-ligatures": "^0.10.0-beta.107", - "@xterm/addon-progress": "^0.2.0-beta.13", - "@xterm/addon-search": "^0.16.0-beta.107", - "@xterm/addon-serialize": "^0.14.0-beta.107", - "@xterm/addon-unicode11": "^0.9.0-beta.107", - "@xterm/addon-webgl": "^0.19.0-beta.107", - "@xterm/headless": "^5.6.0-beta.107", - "@xterm/xterm": "^5.6.0-beta.107", + "@xterm/addon-clipboard": "^0.2.0-beta.93", + "@xterm/addon-image": "^0.9.0-beta.110", + "@xterm/addon-ligatures": "^0.10.0-beta.110", + "@xterm/addon-progress": "^0.2.0-beta.16", + "@xterm/addon-search": "^0.16.0-beta.110", + "@xterm/addon-serialize": "^0.14.0-beta.110", + "@xterm/addon-unicode11": "^0.9.0-beta.110", + "@xterm/addon-webgl": "^0.19.0-beta.110", + "@xterm/headless": "^5.6.0-beta.110", + "@xterm/xterm": "^5.6.0-beta.110", "cookie": "^0.7.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", diff --git a/remote/web/package-lock.json b/remote/web/package-lock.json index 68dc9987bcf..ae065ffef5a 100644 --- a/remote/web/package-lock.json +++ b/remote/web/package-lock.json @@ -13,15 +13,15 @@ "@vscode/iconv-lite-umd": "0.7.0", "@vscode/tree-sitter-wasm": "^0.1.4", "@vscode/vscode-languagedetection": "1.0.21", - "@xterm/addon-clipboard": "^0.2.0-beta.90", - "@xterm/addon-image": "^0.9.0-beta.107", - "@xterm/addon-ligatures": "^0.10.0-beta.107", - "@xterm/addon-progress": "^0.2.0-beta.13", - "@xterm/addon-search": "^0.16.0-beta.107", - "@xterm/addon-serialize": "^0.14.0-beta.107", - "@xterm/addon-unicode11": "^0.9.0-beta.107", - "@xterm/addon-webgl": "^0.19.0-beta.107", - "@xterm/xterm": "^5.6.0-beta.107", + "@xterm/addon-clipboard": "^0.2.0-beta.93", + "@xterm/addon-image": "^0.9.0-beta.110", + "@xterm/addon-ligatures": "^0.10.0-beta.110", + "@xterm/addon-progress": "^0.2.0-beta.16", + "@xterm/addon-search": "^0.16.0-beta.110", + "@xterm/addon-serialize": "^0.14.0-beta.110", + "@xterm/addon-unicode11": "^0.9.0-beta.110", + "@xterm/addon-webgl": "^0.19.0-beta.110", + "@xterm/xterm": "^5.6.0-beta.110", "jschardet": "3.1.4", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", @@ -90,30 +90,30 @@ } }, "node_modules/@xterm/addon-clipboard": { - "version": "0.2.0-beta.90", - "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.90.tgz", - "integrity": "sha512-2i7qtACRBYRTRba831ufEjQMeAvK4uuVPYPBkSXzKJ/dIAvhws5B6OOmxqZzR97OsmzUC/SrjHSujgwyD0MVVw==", + "version": "0.2.0-beta.93", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.93.tgz", + "integrity": "sha512-A+XZnJgROYtvcIVGGYM6lH5PbXdVoMz/c140Pq9wu0jq++z3zHkcfTIMWO8E/xrvCO9Op3LTv9fu5NEhOI2l3A==", "license": "MIT", "dependencies": { "js-base64": "^3.7.5" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-image": { - "version": "0.9.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.107.tgz", - "integrity": "sha512-/vqb2BhVjJeCcOIDSpjWrfXbhNTCse95qkKbpmzFkQJJEh0CyaqjSUBIAM+Qcl9f/x6H//O2wADnn3Wsn5qYsg==", + "version": "0.9.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.9.0-beta.110.tgz", + "integrity": "sha512-mzs2nIWqVay/1q3H74UQZwE0/MU4pNTEIkle3n+sYYbFJh8ZVOPKQfnl5ze7DWnQnqm3hqg2FDXZKfXj8fkdEA==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-ligatures": { - "version": "0.10.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.10.0-beta.107.tgz", - "integrity": "sha512-3qQZz6dPS8XlGGwz1p5Bqjoosah6Km1GwGeNv7YxkCVU2kpTOymFH8BMUEOFC5WHdYseDXnz8hIEleexF9Pa2g==", + "version": "0.10.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.10.0-beta.110.tgz", + "integrity": "sha512-k8ILGtdbmUTJURGX0h857C3F6KXxIwrOpsfEC5v1k3ffW3mJn6qkKOTmOyS89QcpWXXbbqvLJRLQ7FWGKYvlgg==", "license": "MIT", "dependencies": { "font-finder": "^1.1.0", @@ -123,58 +123,58 @@ "node": ">8.0.0" }, "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-progress": { - "version": "0.2.0-beta.13", - "resolved": "https://registry.npmjs.org/@xterm/addon-progress/-/addon-progress-0.2.0-beta.13.tgz", - "integrity": "sha512-BLmX+JdA+LLOMbVLQm+gPqieeKaVMiugBFpCtQtBus3kCs/2/F8pU/XNGV31CnXxDdRjptyOGrPVRreF/rDdcg==", + "version": "0.2.0-beta.16", + "resolved": "https://registry.npmjs.org/@xterm/addon-progress/-/addon-progress-0.2.0-beta.16.tgz", + "integrity": "sha512-VqxaYIMx8TjeL9s4CYxMP8kFOQPEhcjEzrSLqYmpvhY2RpCJrDjf0HPh/wy9HDADJIWLZE6Gjcva7yub02fJXg==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-search": { - "version": "0.16.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.107.tgz", - "integrity": "sha512-poHjeKjnTKtS6rHyu3r5lhW/0rdLcRMSJLDmT9xo9lfTuyhfcUl8gro44iPtscKY+LEtrhZcortTlElMewy/Bw==", + "version": "0.16.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0-beta.110.tgz", + "integrity": "sha512-f7pi12E/7lD5Oz/Wrt3DL6kXOU7jVjA6ZAXisznBQTH1M4vxY3agvgUYVHWYFHyY1uWwheL1K089nzfjT5A1Lg==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-serialize": { - "version": "0.14.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.107.tgz", - "integrity": "sha512-MGaoO2zlNuSGofX5Xfbw+MU2wgAApEsDOPeYoEBSQyLf5BR7Z2rGVCxFyF5zNsIhNDov7ptQIVpCfonMVAgUvg==", + "version": "0.14.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.110.tgz", + "integrity": "sha512-uCHdHwwp2HWTCSMavkmYylgebiCGW+P76XJp04uVJnMBIPTSLGKygiCRQbxDsRB6mblsYislMEw4P9egKl/eqA==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-unicode11": { - "version": "0.9.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.107.tgz", - "integrity": "sha512-XTfJ1G7u+8zOT6faCfEB49AbVFAX4XWUoiLtyXCfRvbrVuv5wv53T03dLtBtpwjWoFaveLKGl3ZiU7t3dpl0RA==", + "version": "0.9.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.110.tgz", + "integrity": "sha512-HMfvm7ZaUgN2I78Lk/YXazfnLTntCwZidi25BtVNJWy+ibgSM9EUfs/AsnDx8JbeTPqGpHxvybWaIUC3maNurQ==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/addon-webgl": { - "version": "0.19.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.107.tgz", - "integrity": "sha512-wdUkYiV4PnR9+7+1giJoFm5xrguCOKTH4xdQ/6lYuSbgMS0y1ykpcQjDNshwHy0TyUuh4o4z1+rd48qNjqGM6Q==", + "version": "0.19.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.110.tgz", + "integrity": "sha512-1fVHcG5lKdencCBI6b6ZZwlTs54Ax3EtbngkgwVHnqVR4jMmHQ5E8G/AH6Vk+OpVNANW+//oArDtosFUIDFKWw==", "license": "MIT", "peerDependencies": { - "@xterm/xterm": "^5.6.0-beta.107" + "@xterm/xterm": "^5.6.0-beta.110" } }, "node_modules/@xterm/xterm": { - "version": "5.6.0-beta.107", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.107.tgz", - "integrity": "sha512-7cuJFZtc7Rv9BEpf9UsvErfXhLKkEmogI0mizgri+nNjEENnpQcFOpx84GFTjax/Zta8MAxOMUP1XU5Guju80A==", + "version": "5.6.0-beta.110", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.6.0-beta.110.tgz", + "integrity": "sha512-FPIKLySxbyWaXoBVbnc1KtbJe6CUV9DxZ9LHSs2gNHMN2jPmBhtdpDppeMqWwdmuCDBk9OcMSTPQNHT+mI4gSw==", "license": "MIT" }, "node_modules/font-finder": { diff --git a/remote/web/package.json b/remote/web/package.json index 1f3b42ac717..b1430851c3d 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -8,15 +8,15 @@ "@vscode/iconv-lite-umd": "0.7.0", "@vscode/tree-sitter-wasm": "^0.1.4", "@vscode/vscode-languagedetection": "1.0.21", - "@xterm/addon-clipboard": "^0.2.0-beta.90", - "@xterm/addon-image": "^0.9.0-beta.107", - "@xterm/addon-ligatures": "^0.10.0-beta.107", - "@xterm/addon-progress": "^0.2.0-beta.13", - "@xterm/addon-search": "^0.16.0-beta.107", - "@xterm/addon-serialize": "^0.14.0-beta.107", - "@xterm/addon-unicode11": "^0.9.0-beta.107", - "@xterm/addon-webgl": "^0.19.0-beta.107", - "@xterm/xterm": "^5.6.0-beta.107", + "@xterm/addon-clipboard": "^0.2.0-beta.93", + "@xterm/addon-image": "^0.9.0-beta.110", + "@xterm/addon-ligatures": "^0.10.0-beta.110", + "@xterm/addon-progress": "^0.2.0-beta.16", + "@xterm/addon-search": "^0.16.0-beta.110", + "@xterm/addon-serialize": "^0.14.0-beta.110", + "@xterm/addon-unicode11": "^0.9.0-beta.110", + "@xterm/addon-webgl": "^0.19.0-beta.110", + "@xterm/xterm": "^5.6.0-beta.110", "jschardet": "3.1.4", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", From ac8b3ac9416363b67d58b4dd8cb3e85a50774f51 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:21:54 +0000 Subject: [PATCH 083/236] Fix hasErrors property for compound task problem matcher events (#250784) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com> Co-authored-by: meganrogge --- .../tasks/browser/terminalTaskSystem.ts | 51 +++++++++++++++++-- .../workbench/contrib/tasks/common/tasks.ts | 12 ++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index a2b242d65d1..5b2f568a3c3 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -184,6 +184,8 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { private _activeTasks: IStringDictionary; private _busyTasks: IStringDictionary; + private _taskErrors: IStringDictionary; // Tracks which tasks had errors from problem matchers + private _taskDependencies: IStringDictionary; // Tracks which tasks depend on which other tasks private _terminals: IStringDictionary; private _idleTaskTerminals: LinkedMap; private _sameTaskTerminals: IStringDictionary; @@ -243,6 +245,8 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this._activeTasks = Object.create(null); this._busyTasks = Object.create(null); + this._taskErrors = Object.create(null); + this._taskDependencies = Object.create(null); this._terminals = Object.create(null); this._idleTaskTerminals = new LinkedMap(); this._sameTaskTerminals = Object.create(null); @@ -528,6 +532,16 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { const dependencyTask = await resolver.resolve(dependency.uri, dependency.task); if (dependencyTask) { this._adoptConfigurationForDependencyTask(dependencyTask, task); + + // Track the dependency relationship + const taskMapKey = task.getMapKey(); + const dependencyMapKey = dependencyTask.getMapKey(); + if (!this._taskDependencies[taskMapKey]) { + this._taskDependencies[taskMapKey] = []; + } + if (!this._taskDependencies[taskMapKey].includes(dependencyMapKey)) { + this._taskDependencies[taskMapKey].push(dependencyMapKey); + } let taskResult; const commonKey = dependencyTask.getCommonTaskId(); if (nextLiveDependencies.has(commonKey)) { @@ -600,6 +614,33 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { }); } + private _taskHasErrors(task: Task): boolean { + const taskMapKey = task.getMapKey(); + + // Check if this task itself had errors + if (this._taskErrors[taskMapKey]) { + return true; + } + + // Check if any tracked dependencies had errors + const dependencies = this._taskDependencies[taskMapKey]; + if (dependencies) { + for (const dependencyMapKey of dependencies) { + if (this._taskErrors[dependencyMapKey]) { + return true; + } + } + } + + return false; + } + + private _cleanupTaskTracking(task: Task): void { + const taskMapKey = task.getMapKey(); + delete this._taskErrors[taskMapKey]; + delete this._taskDependencies[taskMapKey]; + } + private _adoptConfigurationForDependencyTask(dependencyTask: Task, task: Task): void { if (dependencyTask.configurationProperties.icon) { dependencyTask.configurationProperties.icon.id ||= task.configurationProperties.icon?.id; @@ -852,6 +893,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (eventCounter === 0) { if ((watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity && (watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error)) { + this._taskErrors[task.getMapKey()] = true; this._fireTaskEvent(TaskEvent.general(TaskEventKind.ProblemMatcherFoundErrors, task, terminal?.instanceId)); const reveal = task.command.presentation!.reveal; const revealProblems = task.command.presentation!.revealProblems; @@ -862,7 +904,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this._terminalGroupService.showPanel(false); } } else { - this._fireTaskEvent(TaskEvent.general(TaskEventKind.ProblemMatcherEnded, task, terminal?.instanceId)); + this._fireTaskEvent(TaskEvent.problemMatcherEnded(task, this._taskHasErrors(task), terminal?.instanceId)); } } } @@ -1000,9 +1042,10 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this._fireTaskEvent(TaskEvent.general(TaskEventKind.ProblemMatcherStarted, task, terminal?.instanceId)); } else if (event.kind === ProblemCollectorEventKind.BackgroundProcessingEnds) { if (startStopProblemMatcher.numberOfMatches && startStopProblemMatcher.maxMarkerSeverity && startStopProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error) { + this._taskErrors[task.getMapKey()] = true; this._fireTaskEvent(TaskEvent.general(TaskEventKind.ProblemMatcherFoundErrors, task, terminal?.instanceId)); } else { - this._fireTaskEvent(TaskEvent.general(TaskEventKind.ProblemMatcherEnded, task, terminal?.instanceId)); + this._fireTaskEvent(TaskEvent.problemMatcherEnded(task, this._taskHasErrors(task), terminal?.instanceId)); } } })); @@ -1069,11 +1112,13 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } this._fireTaskEvent(TaskEvent.general(TaskEventKind.Inactive, task, terminal?.instanceId)); if (startStopProblemMatcher.numberOfMatches && startStopProblemMatcher.maxMarkerSeverity && startStopProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error) { + this._taskErrors[task.getMapKey()] = true; this._fireTaskEvent(TaskEvent.general(TaskEventKind.ProblemMatcherFoundErrors, task, terminal?.instanceId)); } else { - this._fireTaskEvent(TaskEvent.general(TaskEventKind.ProblemMatcherEnded, task, terminal?.instanceId)); + this._fireTaskEvent(TaskEvent.problemMatcherEnded(task, this._taskHasErrors(task), terminal?.instanceId)); } this._fireTaskEvent(TaskEvent.general(TaskEventKind.End, task, terminal?.instanceId)); + this._cleanupTaskTracking(task); resolve({ exitCode: exitCode ?? undefined }); }); }); diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 5e15a9fd76f..f7acf37527e 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -1203,7 +1203,7 @@ export interface ITaskProblemMatcherEndedEvent extends ITaskCommon { } export interface ITaskGeneralEvent extends ITaskCommon { - kind: TaskEventKind.AcquiredInput | TaskEventKind.DependsOnStarted | TaskEventKind.Active | TaskEventKind.Inactive | TaskEventKind.End | TaskEventKind.ProblemMatcherEnded | TaskEventKind.ProblemMatcherStarted | TaskEventKind.ProblemMatcherFoundErrors; + kind: TaskEventKind.AcquiredInput | TaskEventKind.DependsOnStarted | TaskEventKind.Active | TaskEventKind.Inactive | TaskEventKind.End | TaskEventKind.ProblemMatcherStarted | TaskEventKind.ProblemMatcherFoundErrors; terminalId: number | undefined; } @@ -1270,7 +1270,7 @@ export namespace TaskEvent { }; } - export function general(kind: TaskEventKind.AcquiredInput | TaskEventKind.DependsOnStarted | TaskEventKind.Active | TaskEventKind.Inactive | TaskEventKind.End | TaskEventKind.ProblemMatcherEnded | TaskEventKind.ProblemMatcherStarted | TaskEventKind.ProblemMatcherFoundErrors, task: Task, terminalId?: number): ITaskGeneralEvent { + export function general(kind: TaskEventKind.AcquiredInput | TaskEventKind.DependsOnStarted | TaskEventKind.Active | TaskEventKind.Inactive | TaskEventKind.End | TaskEventKind.ProblemMatcherStarted | TaskEventKind.ProblemMatcherFoundErrors, task: Task, terminalId?: number): ITaskGeneralEvent { return { ...common(task), kind, @@ -1278,6 +1278,14 @@ export namespace TaskEvent { }; } + export function problemMatcherEnded(task: Task, hasErrors: boolean, terminalId?: number): ITaskProblemMatcherEndedEvent { + return { + ...common(task), + kind: TaskEventKind.ProblemMatcherEnded, + hasErrors, + }; + } + export function changed(): ITaskChangedEvent { return { kind: TaskEventKind.Changed }; } From a1d277fdfead4e14db4d4f7f409aa5fa4b2265fe Mon Sep 17 00:00:00 2001 From: DrSergei Date: Fri, 6 Jun 2025 18:38:27 +0300 Subject: [PATCH 084/236] Improve debug adapter capabilities checking (#250779) --- .../workbench/contrib/debug/browser/debug.contribution.ts | 8 ++++---- src/vs/workbench/contrib/debug/common/debug.ts | 1 + src/vs/workbench/contrib/debug/common/debugViewModel.ts | 5 ++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 255c41c225d..4a98431a021 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -28,7 +28,7 @@ import { IViewContainersRegistry, IViewsRegistry, ViewContainer, ViewContainerLo import { launchSchemaId } from '../../../services/configuration/common/configuration.js'; import { LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js'; import { COPY_NOTEBOOK_VARIABLE_VALUE_ID, COPY_NOTEBOOK_VARIABLE_VALUE_LABEL } from '../../notebook/browser/contrib/notebookVariables/notebookVariableCommands.js'; -import { BREAKPOINTS_VIEW_ID, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CALLSTACK_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_CAN_VIEW_MEMORY, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE, CONTEXT_DEBUG_UX, CONTEXT_EXPRESSION_SELECTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG, CONTEXT_HAS_DEBUGGED, CONTEXT_IN_DEBUG_MODE, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_SET_EXPRESSION_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_STACK_FRAME_SUPPORTS_RESTART, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, CONTEXT_VARIABLE_IS_READONLY, CONTEXT_VARIABLE_VALUE, CONTEXT_WATCH_ITEM_TYPE, DEBUG_PANEL_ID, DISASSEMBLY_VIEW_ID, EDITOR_CONTRIBUTION_ID, IDebugService, INTERNAL_CONSOLE_OPTIONS_SCHEMA, LOADED_SCRIPTS_VIEW_ID, REPL_VIEW_ID, State, VARIABLES_VIEW_ID, VIEWLET_ID, WATCH_VIEW_ID, getStateLabel } from '../common/debug.js'; +import { BREAKPOINTS_VIEW_ID, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CALLSTACK_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_CAN_VIEW_MEMORY, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE, CONTEXT_DEBUG_UX, CONTEXT_EXPRESSION_SELECTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG, CONTEXT_HAS_DEBUGGED, CONTEXT_IN_DEBUG_MODE, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_SET_EXPRESSION_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_STACK_FRAME_SUPPORTS_RESTART, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_THREADS_SUPPORTED, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, CONTEXT_VARIABLE_IS_READONLY, CONTEXT_VARIABLE_VALUE, CONTEXT_WATCH_ITEM_TYPE, DEBUG_PANEL_ID, DISASSEMBLY_VIEW_ID, EDITOR_CONTRIBUTION_ID, IDebugService, INTERNAL_CONSOLE_OPTIONS_SCHEMA, LOADED_SCRIPTS_VIEW_ID, REPL_VIEW_ID, State, VARIABLES_VIEW_ID, VIEWLET_ID, WATCH_VIEW_ID, getStateLabel } from '../common/debug.js'; import { DebugWatchAccessibilityAnnouncer } from '../common/debugAccessibilityAnnouncer.js'; import { DebugContentProvider } from '../common/debugContentProvider.js'; import { DebugLifecycle } from '../common/debugLifecycle.js'; @@ -123,7 +123,7 @@ const registerDebugCommandPaletteItem = (id: string, title: ICommandActionTitle, }; registerDebugCommandPaletteItem(RESTART_SESSION_ID, RESTART_LABEL); -registerDebugCommandPaletteItem(TERMINATE_THREAD_ID, nls.localize2('terminateThread', "Terminate Thread"), CONTEXT_IN_DEBUG_MODE); +registerDebugCommandPaletteItem(TERMINATE_THREAD_ID, nls.localize2('terminateThread', "Terminate Thread"), CONTEXT_IN_DEBUG_MODE, CONTEXT_TERMINATE_THREADS_SUPPORTED); registerDebugCommandPaletteItem(STEP_OVER_ID, STEP_OVER_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCommandPaletteItem(STEP_INTO_ID, STEP_INTO_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCommandPaletteItem(STEP_INTO_TARGET_ID, STEP_INTO_TARGET_LABEL, CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.and(CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); @@ -144,7 +144,7 @@ registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKe registerDebugCommandPaletteItem(SELECT_AND_START_ID, SELECT_AND_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); registerDebugCommandPaletteItem(NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL); registerDebugCommandPaletteItem(PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL); -registerDebugCommandPaletteItem(SHOW_LOADED_SCRIPTS_ID, OPEN_LOADED_SCRIPTS_LABEL, CONTEXT_IN_DEBUG_MODE); +registerDebugCommandPaletteItem(SHOW_LOADED_SCRIPTS_ID, OPEN_LOADED_SCRIPTS_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_LOADED_SCRIPTS_SUPPORTED); registerDebugCommandPaletteItem(SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL); registerDebugCommandPaletteItem(SELECT_DEBUG_SESSION_ID, SELECT_DEBUG_SESSION_LABEL); registerDebugCommandPaletteItem(CALLSTACK_TOP_ID, CALLSTACK_TOP_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); @@ -176,7 +176,7 @@ registerDebugViewMenuItem(MenuId.DebugCallStackContext, CONTINUE_ID, CONTINUE_LA registerDebugViewMenuItem(MenuId.DebugCallStackContext, STEP_OVER_ID, STEP_OVER_LABEL, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugViewMenuItem(MenuId.DebugCallStackContext, STEP_INTO_ID, STEP_INTO_LABEL, 30, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugViewMenuItem(MenuId.DebugCallStackContext, STEP_OUT_ID, STEP_OUT_LABEL, 40, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugViewMenuItem(MenuId.DebugCallStackContext, TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), undefined, 'termination'); +registerDebugViewMenuItem(MenuId.DebugCallStackContext, TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_TERMINATE_THREADS_SUPPORTED, 'termination'); registerDebugViewMenuItem(MenuId.DebugCallStackContext, RESTART_FRAME_ID, nls.localize('restartFrame', "Restart Frame"), 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), CONTEXT_RESTART_FRAME_SUPPORTED), CONTEXT_STACK_FRAME_SUPPORTS_RESTART); registerDebugViewMenuItem(MenuId.DebugCallStackContext, COPY_STACK_TRACE_ID, nls.localize('copyStackTrace', "Copy Call Stack"), 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), undefined, '3_modification'); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index a2b1a8b2c6b..4487bd487aa 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -89,6 +89,7 @@ export const CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED = new RawContextKey< export const CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED = new RawContextKey('breakWhenValueIsReadSupported', false, { type: 'boolean', description: nls.localize('breakWhenValueIsReadSupported', "True when the focused breakpoint supports to break when value is read.") }); export const CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED = new RawContextKey('terminateDebuggeeSupported', false, { type: 'boolean', description: nls.localize('terminateDebuggeeSupported', "True when the focused session supports the terminate debuggee capability.") }); export const CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED = new RawContextKey('suspendDebuggeeSupported', false, { type: 'boolean', description: nls.localize('suspendDebuggeeSupported', "True when the focused session supports the suspend debuggee capability.") }); +export const CONTEXT_TERMINATE_THREADS_SUPPORTED = new RawContextKey('terminateThreadsSupported', false, { type: 'boolean', description: nls.localize('terminateThreadsSupported', "True when the focused session supports the terminate threads capability.") }); export const CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT = new RawContextKey('variableEvaluateNamePresent', false, { type: 'boolean', description: nls.localize('variableEvaluateNamePresent', "True when the focused variable has an 'evalauteName' field set.") }); export const CONTEXT_VARIABLE_IS_READONLY = new RawContextKey('variableIsReadonly', false, { type: 'boolean', description: nls.localize('variableIsReadonly', "True when the focused variable is read-only.") }); export const CONTEXT_VARIABLE_VALUE = new RawContextKey('variableValue', false, { type: 'string', description: nls.localize('variableValue', "Value of the variable, present for debug visualization clauses.") }); diff --git a/src/vs/workbench/contrib/debug/common/debugViewModel.ts b/src/vs/workbench/contrib/debug/common/debugViewModel.ts index 9336c5448d1..20c2092da07 100644 --- a/src/vs/workbench/contrib/debug/common/debugViewModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugViewModel.ts @@ -5,7 +5,7 @@ import { Emitter, Event } from '../../../../base/common/event.js'; import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_EXPRESSION_SELECTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED, CONTEXT_SET_EXPRESSION_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, IDebugSession, IExpression, IExpressionContainer, IStackFrame, IThread, IViewModel } from './debug.js'; +import { CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_EXPRESSION_SELECTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED, CONTEXT_SET_EXPRESSION_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_THREADS_SUPPORTED, IDebugSession, IExpression, IExpressionContainer, IStackFrame, IThread, IViewModel } from './debug.js'; import { isSessionAttach } from './debugUtils.js'; export class ViewModel implements IViewModel { @@ -39,6 +39,7 @@ export class ViewModel implements IViewModel { private multiSessionDebug!: IContextKey; private terminateDebuggeeSupported!: IContextKey; private suspendDebuggeeSupported!: IContextKey; + private terminateThreadsSupported!: IContextKey; private disassembleRequestSupported!: IContextKey; private focusedStackFrameHasInstructionPointerReference!: IContextKey; @@ -58,6 +59,7 @@ export class ViewModel implements IViewModel { this.multiSessionDebug = CONTEXT_MULTI_SESSION_DEBUG.bindTo(contextKeyService); this.terminateDebuggeeSupported = CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED.bindTo(contextKeyService); this.suspendDebuggeeSupported = CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED.bindTo(contextKeyService); + this.terminateThreadsSupported = CONTEXT_TERMINATE_THREADS_SUPPORTED.bindTo(contextKeyService); this.disassembleRequestSupported = CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED.bindTo(contextKeyService); this.focusedStackFrameHasInstructionPointerReference = CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE.bindTo(contextKeyService); }); @@ -100,6 +102,7 @@ export class ViewModel implements IViewModel { this.setExpressionSupported.set(!!session?.capabilities.supportsSetExpression); this.terminateDebuggeeSupported.set(!!session?.capabilities.supportTerminateDebuggee); this.suspendDebuggeeSupported.set(!!session?.capabilities.supportSuspendDebuggee); + this.terminateThreadsSupported.set(!!session?.capabilities.supportsTerminateThreadsRequest); this.disassembleRequestSupported.set(!!session?.capabilities.supportsDisassembleRequest); this.focusedStackFrameHasInstructionPointerReference.set(!!stackFrame?.instructionPointerReference); const attach = !!session && isSessionAttach(session); From 56b510710f59498221d50a058c68d93ee6426d86 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 17:39:58 +0200 Subject: [PATCH 085/236] some tiny prep work for https://github.com/microsoft/vscode/issues/249519 (#250863) --- .../contrib/chat/common/chatModel.ts | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index d77b19bb594..1512b137bfc 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -33,19 +33,19 @@ import { IChatRequestVariableValue } from './chatVariables.js'; import { ChatAgentLocation, ChatMode } from './constants.js'; interface IBaseChatRequestVariableEntry { - id: string; - fullName?: string; - icon?: ThemeIcon; - name: string; - modelDescription?: string; + readonly id: string; + readonly fullName?: string; + readonly icon?: ThemeIcon; + readonly name: string; + readonly modelDescription?: string; /** * The offset-range in the prompt. This means this entry has been explicitly typed out * by the user. */ - range?: IOffsetRange; - value: IChatRequestVariableValue; - references?: IChatContentReference[]; + readonly range?: IOffsetRange; + readonly value: IChatRequestVariableValue; + readonly references?: IChatContentReference[]; omittedState?: OmittedState; } @@ -83,20 +83,20 @@ export interface IChatRequestImplicitVariableEntry extends IBaseChatRequestVaria readonly value: URI | Location | undefined; readonly isSelection: boolean; readonly isPromptFile: boolean; - enabled: boolean; + readonly enabled: boolean; } export interface IChatRequestPasteVariableEntry extends IBaseChatRequestVariableEntry { readonly kind: 'paste'; - code: string; - language: string; - pastedLines: string; + readonly code: string; + readonly language: string; + readonly pastedLines: string; // This is only used for old serialized data and should be removed once we no longer support it - fileName: string; + readonly fileName: string; // This is only undefined on old serialized data - copiedFrom: { + readonly copiedFrom: { readonly uri: URI; readonly range: IRange; } | undefined; @@ -119,7 +119,7 @@ export interface IImageVariableEntry extends IBaseChatRequestVariableEntry { readonly mimeType?: string; } -export interface INotebookOutputVariableEntry extends Omit { +export interface INotebookOutputVariableEntry extends IBaseChatRequestVariableEntry { readonly kind: 'notebookOutput'; readonly outputIndex?: number; readonly mimeType?: string; From a76a1c465094032c79b4ed5552a033cfa1d3e45d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 6 Jun 2025 17:47:24 +0200 Subject: [PATCH 086/236] don't animate visibility, opacity is enough (#250866) https://github.com/microsoft/vscode/issues/250746 --- .../editor/contrib/codelens/browser/codelensWidget.css | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/contrib/codelens/browser/codelensWidget.css b/src/vs/editor/contrib/codelens/browser/codelensWidget.css index adc19b13de6..a7ec91c06d9 100644 --- a/src/vs/editor/contrib/codelens/browser/codelensWidget.css +++ b/src/vs/editor/contrib/codelens/browser/codelensWidget.css @@ -54,14 +54,8 @@ } @keyframes fadein { - 0% { - opacity: 0; - visibility: visible; - } - - 100% { - opacity: 1; - } + 0% { opacity: 0;} + 100% { opacity: 1;} } .monaco-editor .codelens-decoration.fadein { From f8cc13b410918cd3d8225b1bf7fa87075840b423 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 09:19:01 -0700 Subject: [PATCH 087/236] Improve case where active instance already exists --- .../browser/terminal.history.contribution.ts | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts b/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts index c69662c95d4..7d4c178ef09 100644 --- a/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/history/browser/terminal.history.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js'; -import { Disposable } from '../../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js'; import { localize2 } from '../../../../../nls.js'; import { AccessibleViewProviderId } from '../../../../../platform/accessibility/browser/accessibleView.js'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../../platform/accessibility/common/accessibility.js'; @@ -147,21 +147,17 @@ registerTerminalAction({ } ], run: async (c, accessor) => { - // If there are no active instances, then create a new terminal instance - const activeInstance = await c.service.getActiveOrCreateInstance(); - // Newly created instances will not have a shell type set yet - // This will result in the command picker not showing up, so wait for it to be set - if (!activeInstance.shellType) { + let activeInstance = c.service.activeInstance; + // If an instanec doesn't exist, create one and wait for shell type to be set + if (!activeInstance) { + const newInstance = activeInstance = await c.service.getActiveOrCreateInstance(); await c.service.revealActiveTerminal(); - const wasDisposedPrematurely = await new Promise(resolve => { - activeInstance.onDidChangeShellType(() => { - resolve(false); - }); - activeInstance.onDisposed(() => { - resolve(true); - }); + const store = new DisposableStore(); + const wasDisposedPrematurely = await new Promise(r => { + store.add(newInstance.onDidChangeShellType(() => r(false))); + store.add(newInstance.onDisposed(() => r(true))); }); - // If the instance was disposed before the shell type was set, then exit + store.dispose(); if (wasDisposedPrematurely) { return; } From 95c9166d0b5ac029e3d022cdc4423b57b5055914 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 09:49:55 -0700 Subject: [PATCH 088/236] Revert "Merge pull request #250670 from microsoft/copilot/fix-250669" This reverts commit aa095f877eb2a3965c6ee8415e5aacb6a6fc9f27, reversing changes made to 13ff4544a729ebff787f1101878b36d8fdf2eb9d. --- .../terminal/browser/terminalActions.ts | 52 +++++-------------- .../terminal.developer.contribution.ts | 38 +++++++++++++- .../developer/common/terminal.developer.ts | 1 + test/automation/src/terminal.ts | 8 +-- .../terminal-shellIntegration.test.ts | 22 ++++---- .../terminal/terminal-stickyScroll.test.ts | 2 +- 6 files changed, 66 insertions(+), 57 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 184b520b373..320e96d86b5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -121,49 +121,20 @@ export async function getCwdForSplit( } export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { - const configurationResolverService = accessor.get(IConfigurationResolverService); - const historyService = accessor.get(IHistoryService); - const quickInputService = accessor.get(IQuickInputService); - const terminalService = accessor.get(ITerminalService); - const workspaceContextService = accessor.get(IWorkspaceContextService); - - const instance = terminalService.activeInstance || await terminalService.getActiveOrCreateInstance(); - if (!instance) { - return; - } - - let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; - - // If no text provided, prompt user for input - if (!text) { - text = await quickInputService.input({ - value: '', - placeHolder: 'Enter sequence to send (supports \\n, \\r, \\x escape sequences)', - prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), - }); + const instance = accessor.get(ITerminalService).activeInstance; + if (instance) { + const text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; if (!text) { return; } + const configurationResolverService = accessor.get(IConfigurationResolverService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const historyService = accessor.get(IHistoryService); + const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); + const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; + const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); + instance.sendText(resolvedText, false); } - - // Process escape sequences - let processedText = text - .replace(/\\n/g, '\n') - .replace(/\\r/g, '\r'); - - // Process hex escape sequences (\xNN) - while (true) { - const match = processedText.match(/\\x([0-9a-fA-F]{2})/); - if (match === null || match.index === undefined || match.length < 2) { - break; - } - processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); - } - - const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); - const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; - const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, processedText); - instance.sendText(resolvedText, false); }; export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => { @@ -1036,13 +1007,14 @@ export function registerTerminalActions() { registerTerminalAction({ id: TerminalCommandId.SendSequence, title: terminalStrings.sendSequence, - f1: true, + f1: false, metadata: { description: terminalStrings.sendSequence.value, args: [{ name: 'args', schema: { type: 'object', + required: ['text'], properties: { text: { description: localize('sendSequence', "The sequence of text to send to the terminal"), diff --git a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts index d2fc5dda4ca..067736bd947 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts @@ -17,11 +17,12 @@ import { IConfigurationService } from '../../../../../platform/configuration/com import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; import { IFileService } from '../../../../../platform/files/common/files.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; +import { IQuickInputService } from '../../../../../platform/quickinput/common/quickInput.js'; import { ITerminalCommand, TerminalCapability } from '../../../../../platform/terminal/common/capabilities/capabilities.js'; import { ITerminalLogService, TerminalSettingId } from '../../../../../platform/terminal/common/terminal.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { IStatusbarService, StatusbarAlignment, type IStatusbarEntry } from '../../../../services/statusbar/browser/statusbar.js'; -import { ITerminalContribution, ITerminalInstance, IXtermTerminal } from '../../../terminal/browser/terminal.js'; +import { IInternalXtermTerminal, ITerminalContribution, ITerminalInstance, IXtermTerminal } from '../../../terminal/browser/terminal.js'; import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js'; import { registerTerminalContribution, type ITerminalContributionContext } from '../../../terminal/browser/terminalExtensions.js'; import { TerminalContextKeys } from '../../../terminal/common/terminalContextKey.js'; @@ -60,6 +61,41 @@ registerTerminalAction({ } }); +registerTerminalAction({ + id: TerminalDeveloperCommandId.WriteDataToTerminal, + title: localize2('workbench.action.terminal.writeDataToTerminal', 'Write Data to Terminal'), + category: Categories.Developer, + run: async (c, accessor) => { + const quickInputService = accessor.get(IQuickInputService); + const instance = await c.service.getActiveOrCreateInstance(); + await c.service.revealActiveTerminal(); + await instance.processReady; + if (!instance.xterm) { + throw new Error('Cannot write data to terminal if xterm isn\'t initialized'); + } + const data = await quickInputService.input({ + value: '', + placeHolder: 'Enter data, use \\x to escape', + prompt: localize('workbench.action.terminal.writeDataToTerminal.prompt', "Enter data to write directly to the terminal, bypassing the pty"), + }); + if (!data) { + return; + } + let escapedData = data + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r'); + while (true) { + const match = escapedData.match(/\\x([0-9a-fA-F]{2})/); + if (match === null || match.index === undefined || match.length < 2) { + break; + } + escapedData = escapedData.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + escapedData.slice(match.index + 4); + } + const xterm = instance.xterm as any as IInternalXtermTerminal; + xterm._writeText(escapedData); + } +}); + registerTerminalAction({ id: TerminalDeveloperCommandId.RecordSession, title: localize2('workbench.action.terminal.recordSession', 'Record Terminal Session'), diff --git a/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts b/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts index 62afd2f42ed..a502cc23d9e 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/common/terminal.developer.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ export const enum TerminalDeveloperCommandId { + WriteDataToTerminal = 'workbench.action.terminal.writeDataToTerminal', RecordSession = 'workbench.action.terminal.recordSession', ShowTextureAtlas = 'workbench.action.terminal.showTextureAtlas', RestartPtyHost = 'workbench.action.terminal.restartPtyHost', diff --git a/test/automation/src/terminal.ts b/test/automation/src/terminal.ts index 6cd674c0b62..af2a152fb81 100644 --- a/test/automation/src/terminal.ts +++ b/test/automation/src/terminal.ts @@ -41,7 +41,7 @@ export enum TerminalCommandIdWithValue { NewWithProfile = 'workbench.action.terminal.newWithProfile', SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell', AttachToSession = 'workbench.action.terminal.attachToSession', - SendSequence = 'workbench.action.terminal.sendSequence' + WriteDataToTerminal = 'workbench.action.terminal.writeDataToTerminal' } /** @@ -156,7 +156,7 @@ export class Terminal { /** * Creates an empty terminal by opening a regular terminal and resetting its state such that it * essentially acts like an Pseudoterminal extension API-based terminal. This can then be paired - * with `TerminalCommandIdWithValue.SendSequence` to make more reliable tests. + * with `TerminalCommandIdWithValue.WriteDataToTerminal` to make more reliable tests. */ async createEmptyTerminal(expectedLocation?: 'editor' | 'panel'): Promise { await this.createTerminal(expectedLocation); @@ -167,11 +167,11 @@ export class Terminal { await this.waitForTerminalText(buffer => buffer.some(line => line.startsWith('initialized'))); // Erase all content and reset cursor to top - await this.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${csi('2J')}${csi('H')}`); + await this.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${csi('2J')}${csi('H')}`); // Force windows pty mode off; assume all sequences are rendered in correct position if (process.platform === 'win32') { - await this.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('P;IsWindows=False')}`); + await this.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('P;IsWindows=False')}`); } } diff --git a/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts b/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts index f89b59c4a5c..b0d0db48bf3 100644 --- a/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts +++ b/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts @@ -98,33 +98,33 @@ export function setup(options?: { skipSuite: boolean }) { // Use the simplest profile to get as little process interaction as possible await terminal.createEmptyTerminal(); // Erase all content and reset cursor to top - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${csi('2J')}${csi('H')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${csi('2J')}${csi('H')}`); }); describe('VS Code sequences', () => { it('should handle the simple case', async () => { - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}exitcode 0`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 0`); await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${vsc('C')}Success\\r\\n${vsc('D;0')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Success\\r\\n${vsc('D;0')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}exitcode 1`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 1`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${vsc('C')}Failure\\r\\n${vsc('D;1')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Failure\\r\\n${vsc('D;1')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }); }); }); describe('Final Term sequences', () => { it('should handle the simple case', async () => { - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 0`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 0`); await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${ft('C')}Success\\r\\n${ft('D;0')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Success\\r\\n${ft('D;0')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${ft('C')}Failure\\r\\n${ft('D;1')}`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Failure\\r\\n${ft('D;1')}`); await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 }); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`); await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }); }); }); diff --git a/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts b/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts index b079abd3e68..495a3bf033f 100644 --- a/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts +++ b/test/smoke/src/areas/terminal/terminal-stickyScroll.test.ts @@ -35,7 +35,7 @@ export function setup(options?: { skipSuite: boolean }) { expectedLineCount: number = 1 ): Promise { const data = generateCommandAndOutput(prompt, command, exitCode); - await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, data); + await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, data); // Verify line count await app.code.waitForElements('.terminal-sticky-scroll .xterm-rows > *', true, e => e.length === expectedLineCount); // Verify content From 7546740f42e6b21b0a0fa2705b3db49a45d4d868 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 09:56:25 -0700 Subject: [PATCH 089/236] Add picker to sendSequence command Fixes #250669 --- .../terminal/browser/terminalActions.ts | 42 +++++++++++++++---- .../terminal/common/terminalStrings.ts | 2 +- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 320e96d86b5..81e7fefe040 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -121,15 +121,43 @@ export async function getCwdForSplit( } export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { - const instance = accessor.get(ITerminalService).activeInstance; + const quickInputService = accessor.get(IQuickInputService); + const configurationResolverService = accessor.get(IConfigurationResolverService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const historyService = accessor.get(IHistoryService); + const terminalService = accessor.get(ITerminalService); + + const instance = terminalService.activeInstance; if (instance) { - const text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; + let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; + + // If no text provided, prompt user for input and process special characters if (!text) { - return; + text = await quickInputService.input({ + value: '', + placeHolder: 'Enter sequence to send (supports \\n, \\r, \\x{AB})', + prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), + }); + if (!text) { + return; + } + // Process escape sequences + let processedText = text + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r'); + + // Process hex escape sequences (\xNN) + while (true) { + const match = processedText.match(/\\x([0-9a-fA-F]{2})/); + if (match === null || match.index === undefined || match.length < 2) { + break; + } + processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); + } + + text = processedText; } - const configurationResolverService = accessor.get(IConfigurationResolverService); - const workspaceContextService = accessor.get(IWorkspaceContextService); - const historyService = accessor.get(IHistoryService); + const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); @@ -1007,7 +1035,7 @@ export function registerTerminalActions() { registerTerminalAction({ id: TerminalCommandId.SendSequence, title: terminalStrings.sendSequence, - f1: false, + f1: true, metadata: { description: terminalStrings.sendSequence.value, args: [{ diff --git a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts index 28cd7adacaa..d27977eb949 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts @@ -36,7 +36,7 @@ export const terminalStrings = { rename: localize2('workbench.action.terminal.rename', "Rename..."), toggleSizeToContentWidth: localize2('workbench.action.terminal.sizeToContentWidthInstance', "Toggle Size to Content Width"), focusHover: localize2('workbench.action.terminal.focusHover', "Focus Hover"), - sendSequence: localize2('workbench.action.terminal.sendSequence', "Send Custom Sequence to Terminal"), + sendSequence: localize2('workbench.action.terminal.sendSequence', "Send Sequence"), sendSignal: localize2('workbench.action.terminal.sendSignal', "Send Signal"), newWithCwd: localize2('workbench.action.terminal.newWithCwd', "Create New Terminal Starting in a Custom Working Directory"), renameWithArgs: localize2('workbench.action.terminal.renameWithArg', "Rename the Currently Active Terminal"), From 3c97875288c237ca3474a42ef381e7fe47e57483 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Jun 2025 16:59:18 +0000 Subject: [PATCH 090/236] Initial plan for issue From 4617bc7aa70388bc0eab38304fce7272a33419fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Jun 2025 17:06:22 +0000 Subject: [PATCH 091/236] Fix syntax error in quickPickPin.ts getItemIdentifier function Co-authored-by: Tyriar <2193314+Tyriar@users.noreply.github.com> --- src/vs/platform/quickinput/browser/quickPickPin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/quickinput/browser/quickPickPin.ts b/src/vs/platform/quickinput/browser/quickPickPin.ts index 3d5b87e6e65..c230a56dcc0 100644 --- a/src/vs/platform/quickinput/browser/quickPickPin.ts +++ b/src/vs/platform/quickinput/browser/quickPickPin.ts @@ -77,7 +77,7 @@ function _formatPinnedItems(storageKey: string, quickPick: IQuickPick Date: Fri, 6 Jun 2025 10:18:57 -0700 Subject: [PATCH 092/236] Add styling for label suffix in attached context attachments --- src/vs/workbench/contrib/chat/browser/media/chat.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index c18a98f24de..8fe84342976 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1158,6 +1158,10 @@ have to be updated for changes to the rules above, or to support more deeply nes border-color: var(--vscode-focusBorder); } +.chat-attached-context-attachment .label-suffix { + color: var(--vscode-peekViewTitleDescription-foreground); +} + .chat-notification-widget .chat-warning-codicon .codicon-warning, .chat-quota-error-widget .codicon-warning { color: var(--vscode-notificationsWarningIcon-foreground) !important; /* Have to override default styles which apply to all lists */ From 512c095c356efa392ca2c31694e6976bbce54536 Mon Sep 17 00:00:00 2001 From: Kaitlin Brooks Date: Fri, 6 Jun 2025 10:21:40 -0700 Subject: [PATCH 093/236] Update label suffix and description opacity to revert to previous styling. --- src/vs/base/browser/ui/iconLabel/iconlabel.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 9bf56cc9eb4..ed9278d7087 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -60,12 +60,12 @@ } .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-suffix-container > .label-suffix { - color: var(--vscode-peekViewTitleDescription-foreground); + opacity: .7; white-space: pre; } .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-description-container > .label-description { - color: var(--vscode-peekViewTitleDescription-foreground); + opacity: .7; margin-left: 0.5em; font-size: 0.9em; white-space: pre; /* enable to show labels that include multiple whitespaces */ From e7fe0ed244f0166997eb1a8014cfd3f9ca4cd640 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:27:57 -0700 Subject: [PATCH 094/236] Remove any unexpected properties when persisting pinned item --- src/vs/platform/quickinput/browser/quickPickPin.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/quickinput/browser/quickPickPin.ts b/src/vs/platform/quickinput/browser/quickPickPin.ts index c230a56dcc0..32f8c2d38e4 100644 --- a/src/vs/platform/quickinput/browser/quickPickPin.ts +++ b/src/vs/platform/quickinput/browser/quickPickPin.ts @@ -107,7 +107,7 @@ function updatePinnedItems(storageKey: string, changedItem: IQuickPickItem, stor } else { items.push(changedItem); } - storageService.store(storageKey, JSON.stringify(items), StorageScope.WORKSPACE, StorageTarget.MACHINE); + storageService.store(storageKey, JSON.stringify(items.map(formatPinnedItemForStorage)), StorageScope.WORKSPACE, StorageTarget.MACHINE); return items; } @@ -115,3 +115,11 @@ function getPinnedItems(storageKey: string, storageService: IStorageService): IQ const items = storageService.get(storageKey, StorageScope.WORKSPACE); return items ? JSON.parse(items) : []; } + +function formatPinnedItemForStorage(item: IQuickPickItem): IQuickPickItem { + return { + label: item.label, + description: item.description, + detail: item.detail, + }; +} From 15857a82d3b9e4174e5d3dccca60b2d9ea53ab59 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:30:50 -0700 Subject: [PATCH 095/236] Make write data and send seqeunce commands use same supprots label Part of #250669 --- src/vs/workbench/contrib/terminal/browser/terminalActions.ts | 2 +- .../developer/browser/terminal.developer.contribution.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 81e7fefe040..81a0dbddc3f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -135,7 +135,7 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar if (!text) { text = await quickInputService.input({ value: '', - placeHolder: 'Enter sequence to send (supports \\n, \\r, \\x{AB})', + placeHolder: 'Enter sequence to send (supports \\n, \\r, \\xAB)', prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), }); if (!text) { diff --git a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts index 067736bd947..0ad81a5b126 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts @@ -75,7 +75,7 @@ registerTerminalAction({ } const data = await quickInputService.input({ value: '', - placeHolder: 'Enter data, use \\x to escape', + placeHolder: 'Enter data (supports \\n, \\r, \\xAB)', prompt: localize('workbench.action.terminal.writeDataToTerminal.prompt', "Enter data to write directly to the terminal, bypassing the pty"), }); if (!data) { From 7dca3846a56d2a7c42da5dc543ae859913c4b2e1 Mon Sep 17 00:00:00 2001 From: Kaitlin Brooks Date: Fri, 6 Jun 2025 10:31:04 -0700 Subject: [PATCH 096/236] Set opacity to 1 for label suffix in chat attached context attachments --- src/vs/workbench/contrib/chat/browser/media/chat.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index dfc294b776b..4499f1b2683 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1184,6 +1184,7 @@ have to be updated for changes to the rules above, or to support more deeply nes .chat-attached-context-attachment .label-suffix { color: var(--vscode-peekViewTitleDescription-foreground); + opacity: 1; } .chat-notification-widget .chat-warning-codicon .codicon-warning, From 08cf925c03832ee1b9240ef01faf540b669d7e34 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:38:13 -0700 Subject: [PATCH 097/236] Move send signal/sequence into terminalContrib --- .../terminal/browser/terminalActions.ts | 198 +++--------------- .../terminal/common/terminalStrings.ts | 2 - .../contrib/terminal/terminal.all.ts | 1 + .../terminal.sendCommands.contribution.ts | 164 +++++++++++++++ .../common/terminal.sendCommands.ts | 9 + 5 files changed, 202 insertions(+), 172 deletions(-) create mode 100644 src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts create mode 100644 src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 81a0dbddc3f..f8a5da928f3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -3,65 +3,64 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { isKeyboardEvent, isMouseEvent, isPointerEvent } from '../../../../base/browser/dom.js'; import { Action } from '../../../../base/common/actions.js'; +import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Codicon } from '../../../../base/common/codicons.js'; +import { Iterable } from '../../../../base/common/iterator.js'; import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; -import { Schemas } from '../../../../base/common/network.js'; -import { isWindows } from '../../../../base/common/platform.js'; import { IDisposable } from '../../../../base/common/lifecycle.js'; +import { Schemas } from '../../../../base/common/network.js'; +import { isAbsolute } from '../../../../base/common/path.js'; +import { isWindows } from '../../../../base/common/platform.js'; +import { dirname } from '../../../../base/common/resources.js'; import { isObject, isString } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; +import { ILanguageService } from '../../../../editor/common/languages/language.js'; import { EndOfLinePreference } from '../../../../editor/common/model.js'; +import { getIconClasses } from '../../../../editor/common/services/getIconClasses.js'; +import { IModelService } from '../../../../editor/common/services/model.js'; import { localize, localize2 } from '../../../../nls.js'; +import { AccessibleViewProviderId } from '../../../../platform/accessibility/browser/accessibleView.js'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../platform/accessibility/common/accessibility.js'; -import { Action2, registerAction2, IAction2Options, MenuId } from '../../../../platform/actions/common/actions.js'; +import { Action2, IAction2Options, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; +import { FileKind } from '../../../../platform/files/common/files.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; import { ILabelService } from '../../../../platform/label/common/label.js'; import { IListService } from '../../../../platform/list/browser/listService.js'; import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; -import { IPickOptions, IQuickInputService, IQuickPickItem, QuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; +import { IPickOptions, IQuickInputService, IQuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; +import { TerminalCapability } from '../../../../platform/terminal/common/capabilities/capabilities.js'; import { ITerminalProfile, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalSettingId } from '../../../../platform/terminal/common/terminal.js'; +import { createProfileSchemaEnums } from '../../../../platform/terminal/common/terminalProfiles.js'; +import { IThemeService } from '../../../../platform/theme/common/themeService.js'; import { IWorkspaceContextService, IWorkspaceFolder } from '../../../../platform/workspace/common/workspace.js'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from '../../../browser/actions/workspaceCommands.js'; import { CLOSE_EDITOR_COMMAND_ID } from '../../../browser/parts/editor/editorCommands.js'; -import { Direction, ICreateTerminalOptions, IDetachedTerminalInstance, ITerminalConfigurationService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService, IXtermTerminal } from './terminal.js'; -import { IRemoteTerminalAttachTarget, ITerminalProfileResolverService, ITerminalProfileService, TERMINAL_VIEW_ID, TerminalCommandId } from '../common/terminal.js'; -import { TerminalContextKeys } from '../common/terminalContextKey.js'; -import { createProfileSchemaEnums } from '../../../../platform/terminal/common/terminalProfiles.js'; -import { terminalStrings } from '../common/terminalStrings.js'; import { IConfigurationResolverService } from '../../../services/configurationResolver/common/configurationResolver.js'; +import { ConfigurationResolverExpression } from '../../../services/configurationResolver/common/configurationResolverExpression.js'; +import { editorGroupToColumn } from '../../../services/editor/common/editorGroupColumn.js'; +import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; +import { SIDE_GROUP } from '../../../services/editor/common/editorService.js'; import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js'; -import { IHistoryService } from '../../../services/history/common/history.js'; import { IPreferencesService } from '../../../services/preferences/common/preferences.js'; import { IRemoteAgentService } from '../../../services/remote/common/remoteAgentService.js'; -import { SIDE_GROUP } from '../../../services/editor/common/editorService.js'; -import { isAbsolute } from '../../../../base/common/path.js'; -import { ITerminalQuickPickItem } from './terminalProfileQuickpick.js'; -import { IThemeService } from '../../../../platform/theme/common/themeService.js'; -import { getIconId, getColorClass, getUriClasses } from './terminalIcon.js'; -import { IModelService } from '../../../../editor/common/services/model.js'; -import { ILanguageService } from '../../../../editor/common/languages/language.js'; -import { CancellationToken } from '../../../../base/common/cancellation.js'; -import { dirname } from '../../../../base/common/resources.js'; -import { getIconClasses } from '../../../../editor/common/services/getIconClasses.js'; -import { FileKind } from '../../../../platform/files/common/files.js'; -import { TerminalCapability } from '../../../../platform/terminal/common/capabilities/capabilities.js'; -import { killTerminalIcon, newTerminalIcon } from './terminalIcons.js'; -import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; -import { Iterable } from '../../../../base/common/iterator.js'; import { accessibleViewCurrentProviderId, accessibleViewIsShown, accessibleViewOnLastLine } from '../../accessibility/browser/accessibilityConfiguration.js'; -import { isKeyboardEvent, isMouseEvent, isPointerEvent } from '../../../../base/browser/dom.js'; -import { editorGroupToColumn } from '../../../services/editor/common/editorGroupColumn.js'; +import { IRemoteTerminalAttachTarget, ITerminalProfileResolverService, ITerminalProfileService, TERMINAL_VIEW_ID, TerminalCommandId } from '../common/terminal.js'; +import { TerminalContextKeys } from '../common/terminalContextKey.js'; +import { terminalStrings } from '../common/terminalStrings.js'; +import { Direction, ICreateTerminalOptions, IDetachedTerminalInstance, ITerminalConfigurationService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService, IXtermTerminal } from './terminal.js'; import { InstanceContext } from './terminalContextMenu.js'; -import { AccessibleViewProviderId } from '../../../../platform/accessibility/browser/accessibleView.js'; +import { getColorClass, getIconId, getUriClasses } from './terminalIcon.js'; +import { killTerminalIcon, newTerminalIcon } from './terminalIcons.js'; +import { ITerminalQuickPickItem } from './terminalProfileQuickpick.js'; import { TerminalTabList } from './terminalTabsList.js'; -import { ConfigurationResolverExpression } from '../../../services/configurationResolver/common/configurationResolverExpression.js'; export const switchTerminalActionViewItemSeparator = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'; export const switchTerminalShowTabsTitle = localize('showTerminalTabs', "Show Tabs"); @@ -120,101 +119,6 @@ export async function getCwdForSplit( } } -export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { - const quickInputService = accessor.get(IQuickInputService); - const configurationResolverService = accessor.get(IConfigurationResolverService); - const workspaceContextService = accessor.get(IWorkspaceContextService); - const historyService = accessor.get(IHistoryService); - const terminalService = accessor.get(ITerminalService); - - const instance = terminalService.activeInstance; - if (instance) { - let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; - - // If no text provided, prompt user for input and process special characters - if (!text) { - text = await quickInputService.input({ - value: '', - placeHolder: 'Enter sequence to send (supports \\n, \\r, \\xAB)', - prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), - }); - if (!text) { - return; - } - // Process escape sequences - let processedText = text - .replace(/\\n/g, '\n') - .replace(/\\r/g, '\r'); - - // Process hex escape sequences (\xNN) - while (true) { - const match = processedText.match(/\\x([0-9a-fA-F]{2})/); - if (match === null || match.index === undefined || match.length < 2) { - break; - } - processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); - } - - text = processedText; - } - - const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); - const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; - const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); - instance.sendText(resolvedText, false); - } -}; - -export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => { - const quickInputService = accessor.get(IQuickInputService); - const instance = accessor.get(ITerminalService).activeInstance; - if (!instance) { - return; - } - - let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; - - if (!signal) { - const signalOptions: QuickPickItem[] = [ - { label: 'SIGINT', description: localize('SIGINT', 'Interrupt process (Ctrl+C)') }, - { label: 'SIGTERM', description: localize('SIGTERM', 'Terminate process gracefully') }, - { label: 'SIGKILL', description: localize('SIGKILL', 'Force kill process') }, - { label: 'SIGSTOP', description: localize('SIGSTOP', 'Stop process') }, - { label: 'SIGCONT', description: localize('SIGCONT', 'Continue process') }, - { label: 'SIGHUP', description: localize('SIGHUP', 'Hangup') }, - { label: 'SIGQUIT', description: localize('SIGQUIT', 'Quit process') }, - { label: 'SIGUSR1', description: localize('SIGUSR1', 'User-defined signal 1') }, - { label: 'SIGUSR2', description: localize('SIGUSR2', 'User-defined signal 2') }, - { type: 'separator' }, - { label: localize('manualSignal', 'Manually enter signal') } - ]; - - const selected = await quickInputService.pick(signalOptions, { - placeHolder: localize('selectSignal', 'Select signal to send to terminal process') - }); - - if (!selected) { - return; - } - - if (selected.label === localize('manualSignal', 'Manually enter signal')) { - const inputSignal = await quickInputService.input({ - prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), - }); - - if (!inputSignal) { - return; - } - - signal = inputSignal; - } else { - signal = selected.label; - } - } - - await instance.sendSignal(signal); -}; - export class TerminalLaunchHelpAction extends Action { constructor( @@ -1032,52 +936,6 @@ export function registerTerminalActions() { } }); - registerTerminalAction({ - id: TerminalCommandId.SendSequence, - title: terminalStrings.sendSequence, - f1: true, - metadata: { - description: terminalStrings.sendSequence.value, - args: [{ - name: 'args', - schema: { - type: 'object', - required: ['text'], - properties: { - text: { - description: localize('sendSequence', "The sequence of text to send to the terminal"), - type: 'string' - } - }, - } - }] - }, - run: (c, accessor, args) => terminalSendSequenceCommand(accessor, args) - }); - - registerTerminalAction({ - id: TerminalCommandId.SendSignal, - title: terminalStrings.sendSignal, - f1: !isWindows, - metadata: { - description: terminalStrings.sendSignal.value, - args: [{ - name: 'args', - schema: { - type: 'object', - required: ['signal'], - properties: { - signal: { - description: localize('sendSignal', "The signal to send to the terminal process (e.g., 'SIGTERM', 'SIGINT', 'SIGKILL')"), - type: 'string' - } - }, - } - }] - }, - run: (c, accessor, args) => terminalSendSignalCommand(accessor, args) - }); - registerTerminalAction({ id: TerminalCommandId.NewWithCwd, title: terminalStrings.newWithCwd, diff --git a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts index d27977eb949..5251fc9527a 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalStrings.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalStrings.ts @@ -36,8 +36,6 @@ export const terminalStrings = { rename: localize2('workbench.action.terminal.rename', "Rename..."), toggleSizeToContentWidth: localize2('workbench.action.terminal.sizeToContentWidthInstance', "Toggle Size to Content Width"), focusHover: localize2('workbench.action.terminal.focusHover', "Focus Hover"), - sendSequence: localize2('workbench.action.terminal.sendSequence', "Send Sequence"), - sendSignal: localize2('workbench.action.terminal.sendSignal', "Send Signal"), newWithCwd: localize2('workbench.action.terminal.newWithCwd', "Create New Terminal Starting in a Custom Working Directory"), renameWithArgs: localize2('workbench.action.terminal.renameWithArg', "Rename the Currently Active Terminal"), scrollToPreviousCommand: localize2('workbench.action.terminal.scrollToPreviousCommand', "Scroll to Previous Command"), diff --git a/src/vs/workbench/contrib/terminal/terminal.all.ts b/src/vs/workbench/contrib/terminal/terminal.all.ts index 69ba6694072..5ada9a8fe9b 100644 --- a/src/vs/workbench/contrib/terminal/terminal.all.ts +++ b/src/vs/workbench/contrib/terminal/terminal.all.ts @@ -27,6 +27,7 @@ import '../terminalContrib/stickyScroll/browser/terminal.stickyScroll.contributi import '../terminalContrib/quickAccess/browser/terminal.quickAccess.contribution.js'; import '../terminalContrib/quickFix/browser/terminal.quickFix.contribution.js'; import '../terminalContrib/typeAhead/browser/terminal.typeAhead.contribution.js'; +import '../terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.js'; import '../terminalContrib/suggest/browser/terminal.suggest.contribution.js'; import '../terminalContrib/chat/browser/terminal.initialHint.contribution.js'; import '../terminalContrib/wslRecommendation/browser/terminal.wslRecommendation.contribution.js'; diff --git a/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts b/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts new file mode 100644 index 00000000000..fa93732c1e5 --- /dev/null +++ b/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts @@ -0,0 +1,164 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Schemas } from '../../../../../base/common/network.js'; +import { isWindows } from '../../../../../base/common/platform.js'; +import { isObject, isString } from '../../../../../base/common/types.js'; +import { localize, localize2 } from '../../../../../nls.js'; +import type { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; +import { IQuickInputService, type QuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js'; +import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; +import { IConfigurationResolverService } from '../../../../services/configurationResolver/common/configurationResolver.js'; +import { IHistoryService } from '../../../../services/history/common/history.js'; +import { ITerminalService } from '../../../terminal/browser/terminal.js'; +import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js'; +import { TerminalSendCommandsCommandId } from '../common/terminal.sendCommands.js'; + +function toOptionalString(obj: unknown): string | undefined { + return isString(obj) ? obj : undefined; +} + +export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { + const quickInputService = accessor.get(IQuickInputService); + const configurationResolverService = accessor.get(IConfigurationResolverService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const historyService = accessor.get(IHistoryService); + const terminalService = accessor.get(ITerminalService); + + const instance = terminalService.activeInstance; + if (instance) { + let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; + + // If no text provided, prompt user for input and process special characters + if (!text) { + text = await quickInputService.input({ + value: '', + placeHolder: 'Enter sequence to send (supports \\n, \\r, \\xAB)', + prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), + }); + if (!text) { + return; + } + // Process escape sequences + let processedText = text + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r'); + + // Process hex escape sequences (\xNN) + while (true) { + const match = processedText.match(/\\x([0-9a-fA-F]{2})/); + if (match === null || match.index === undefined || match.length < 2) { + break; + } + processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); + } + + text = processedText; + } + + const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); + const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; + const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); + instance.sendText(resolvedText, false); + } +}; + +export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => { + const quickInputService = accessor.get(IQuickInputService); + const instance = accessor.get(ITerminalService).activeInstance; + if (!instance) { + return; + } + + let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; + + if (!signal) { + const signalOptions: QuickPickItem[] = [ + { label: 'SIGINT', description: localize('SIGINT', 'Interrupt process (Ctrl+C)') }, + { label: 'SIGTERM', description: localize('SIGTERM', 'Terminate process gracefully') }, + { label: 'SIGKILL', description: localize('SIGKILL', 'Force kill process') }, + { label: 'SIGSTOP', description: localize('SIGSTOP', 'Stop process') }, + { label: 'SIGCONT', description: localize('SIGCONT', 'Continue process') }, + { label: 'SIGHUP', description: localize('SIGHUP', 'Hangup') }, + { label: 'SIGQUIT', description: localize('SIGQUIT', 'Quit process') }, + { label: 'SIGUSR1', description: localize('SIGUSR1', 'User-defined signal 1') }, + { label: 'SIGUSR2', description: localize('SIGUSR2', 'User-defined signal 2') }, + { type: 'separator' }, + { label: localize('manualSignal', 'Manually enter signal') } + ]; + + const selected = await quickInputService.pick(signalOptions, { + placeHolder: localize('selectSignal', 'Select signal to send to terminal process') + }); + + if (!selected) { + return; + } + + if (selected.label === localize('manualSignal', 'Manually enter signal')) { + const inputSignal = await quickInputService.input({ + prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), + }); + + if (!inputSignal) { + return; + } + + signal = inputSignal; + } else { + signal = selected.label; + } + } + + await instance.sendSignal(signal); +}; + +const sendSequenceString = localize2('sendSequence', "Send Sequence"); +registerTerminalAction({ + id: TerminalSendCommandsCommandId.SendSequence, + title: sendSequenceString, + f1: true, + metadata: { + description: sendSequenceString.value, + args: [{ + name: 'args', + schema: { + type: 'object', + required: ['text'], + properties: { + text: { + description: localize('sendSequence.text.desc', "The sequence of text to send to the terminal"), + type: 'string' + } + }, + } + }] + }, + run: (c, accessor, args) => terminalSendSequenceCommand(accessor, args) +}); + +const sendSignalString = localize2('sendSignal', "Send Signal"); +registerTerminalAction({ + id: TerminalSendCommandsCommandId.SendSignal, + title: sendSignalString, + f1: !isWindows, + metadata: { + description: sendSignalString.value, + args: [{ + name: 'args', + schema: { + type: 'object', + required: ['signal'], + properties: { + signal: { + description: localize('sendSignal.signal.desc', "The signal to send to the terminal process (e.g., 'SIGTERM', 'SIGINT', 'SIGKILL')"), + type: 'string' + } + }, + } + }] + }, + run: (c, accessor, args) => terminalSendSignalCommand(accessor, args) +}); diff --git a/src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts b/src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts new file mode 100644 index 00000000000..8d444a7538f --- /dev/null +++ b/src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const enum TerminalSendCommandsCommandId { + SendSequence = 'workbench.action.terminal.sendSequence', + SendSignal = 'workbench.action.terminal.sendSignal', +} From f5ad8cd9c30a802ec3017b10b78f426a963dbf45 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:39:30 -0700 Subject: [PATCH 098/236] Inline implementations --- .../terminal.sendCommands.contribution.ts | 191 +++++++++--------- 1 file changed, 92 insertions(+), 99 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts b/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts index fa93732c1e5..c04e17ec368 100644 --- a/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts @@ -7,12 +7,10 @@ import { Schemas } from '../../../../../base/common/network.js'; import { isWindows } from '../../../../../base/common/platform.js'; import { isObject, isString } from '../../../../../base/common/types.js'; import { localize, localize2 } from '../../../../../nls.js'; -import type { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { IQuickInputService, type QuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { IConfigurationResolverService } from '../../../../services/configurationResolver/common/configurationResolver.js'; import { IHistoryService } from '../../../../services/history/common/history.js'; -import { ITerminalService } from '../../../terminal/browser/terminal.js'; import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js'; import { TerminalSendCommandsCommandId } from '../common/terminal.sendCommands.js'; @@ -20,101 +18,6 @@ function toOptionalString(obj: unknown): string | undefined { return isString(obj) ? obj : undefined; } -export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { - const quickInputService = accessor.get(IQuickInputService); - const configurationResolverService = accessor.get(IConfigurationResolverService); - const workspaceContextService = accessor.get(IWorkspaceContextService); - const historyService = accessor.get(IHistoryService); - const terminalService = accessor.get(ITerminalService); - - const instance = terminalService.activeInstance; - if (instance) { - let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; - - // If no text provided, prompt user for input and process special characters - if (!text) { - text = await quickInputService.input({ - value: '', - placeHolder: 'Enter sequence to send (supports \\n, \\r, \\xAB)', - prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), - }); - if (!text) { - return; - } - // Process escape sequences - let processedText = text - .replace(/\\n/g, '\n') - .replace(/\\r/g, '\r'); - - // Process hex escape sequences (\xNN) - while (true) { - const match = processedText.match(/\\x([0-9a-fA-F]{2})/); - if (match === null || match.index === undefined || match.length < 2) { - break; - } - processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); - } - - text = processedText; - } - - const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); - const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; - const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); - instance.sendText(resolvedText, false); - } -}; - -export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => { - const quickInputService = accessor.get(IQuickInputService); - const instance = accessor.get(ITerminalService).activeInstance; - if (!instance) { - return; - } - - let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; - - if (!signal) { - const signalOptions: QuickPickItem[] = [ - { label: 'SIGINT', description: localize('SIGINT', 'Interrupt process (Ctrl+C)') }, - { label: 'SIGTERM', description: localize('SIGTERM', 'Terminate process gracefully') }, - { label: 'SIGKILL', description: localize('SIGKILL', 'Force kill process') }, - { label: 'SIGSTOP', description: localize('SIGSTOP', 'Stop process') }, - { label: 'SIGCONT', description: localize('SIGCONT', 'Continue process') }, - { label: 'SIGHUP', description: localize('SIGHUP', 'Hangup') }, - { label: 'SIGQUIT', description: localize('SIGQUIT', 'Quit process') }, - { label: 'SIGUSR1', description: localize('SIGUSR1', 'User-defined signal 1') }, - { label: 'SIGUSR2', description: localize('SIGUSR2', 'User-defined signal 2') }, - { type: 'separator' }, - { label: localize('manualSignal', 'Manually enter signal') } - ]; - - const selected = await quickInputService.pick(signalOptions, { - placeHolder: localize('selectSignal', 'Select signal to send to terminal process') - }); - - if (!selected) { - return; - } - - if (selected.label === localize('manualSignal', 'Manually enter signal')) { - const inputSignal = await quickInputService.input({ - prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), - }); - - if (!inputSignal) { - return; - } - - signal = inputSignal; - } else { - signal = selected.label; - } - } - - await instance.sendSignal(signal); -}; - const sendSequenceString = localize2('sendSequence', "Send Sequence"); registerTerminalAction({ id: TerminalSendCommandsCommandId.SendSequence, @@ -136,7 +39,49 @@ registerTerminalAction({ } }] }, - run: (c, accessor, args) => terminalSendSequenceCommand(accessor, args) + run: async (c, accessor, args) => { + const quickInputService = accessor.get(IQuickInputService); + const configurationResolverService = accessor.get(IConfigurationResolverService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const historyService = accessor.get(IHistoryService); + + const instance = c.service.activeInstance; + if (instance) { + let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; + + // If no text provided, prompt user for input and process special characters + if (!text) { + text = await quickInputService.input({ + value: '', + placeHolder: 'Enter sequence to send (supports \\n, \\r, \\xAB)', + prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), + }); + if (!text) { + return; + } + // Process escape sequences + let processedText = text + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r'); + + // Process hex escape sequences (\xNN) + while (true) { + const match = processedText.match(/\\x([0-9a-fA-F]{2})/); + if (match === null || match.index === undefined || match.length < 2) { + break; + } + processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); + } + + text = processedText; + } + + const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); + const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; + const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); + instance.sendText(resolvedText, false); + } + } }); const sendSignalString = localize2('sendSignal', "Send Signal"); @@ -160,5 +105,53 @@ registerTerminalAction({ } }] }, - run: (c, accessor, args) => terminalSendSignalCommand(accessor, args) + run: async (c, accessor, args) => { + const quickInputService = accessor.get(IQuickInputService); + const instance = c.service.activeInstance; + if (!instance) { + return; + } + + let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; + + if (!signal) { + const signalOptions: QuickPickItem[] = [ + { label: 'SIGINT', description: localize('SIGINT', 'Interrupt process (Ctrl+C)') }, + { label: 'SIGTERM', description: localize('SIGTERM', 'Terminate process gracefully') }, + { label: 'SIGKILL', description: localize('SIGKILL', 'Force kill process') }, + { label: 'SIGSTOP', description: localize('SIGSTOP', 'Stop process') }, + { label: 'SIGCONT', description: localize('SIGCONT', 'Continue process') }, + { label: 'SIGHUP', description: localize('SIGHUP', 'Hangup') }, + { label: 'SIGQUIT', description: localize('SIGQUIT', 'Quit process') }, + { label: 'SIGUSR1', description: localize('SIGUSR1', 'User-defined signal 1') }, + { label: 'SIGUSR2', description: localize('SIGUSR2', 'User-defined signal 2') }, + { type: 'separator' }, + { label: localize('manualSignal', 'Manually enter signal') } + ]; + + const selected = await quickInputService.pick(signalOptions, { + placeHolder: localize('selectSignal', 'Select signal to send to terminal process') + }); + + if (!selected) { + return; + } + + if (selected.label === localize('manualSignal', 'Manually enter signal')) { + const inputSignal = await quickInputService.input({ + prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), + }); + + if (!inputSignal) { + return; + } + + signal = inputSignal; + } else { + signal = selected.label; + } + } + + await instance.sendSignal(signal); + } }); From 1affae0893aedd0cb4f519cc75b42ccc98122f5a Mon Sep 17 00:00:00 2001 From: Kaitlin Brooks Date: Fri, 6 Jun 2025 10:45:11 -0700 Subject: [PATCH 099/236] Refactor label suffix selector for chat attached context attachments --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 4499f1b2683..ce7d837ef98 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1182,7 +1182,7 @@ have to be updated for changes to the rules above, or to support more deeply nes border-color: var(--vscode-focusBorder); } -.chat-attached-context-attachment .label-suffix { +.chat-attached-context-attachment .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-suffix-container > .label-suffix { color: var(--vscode-peekViewTitleDescription-foreground); opacity: 1; } From c87100c1dedbd0d348bbcbbd6ec8c152b8e0aee2 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:48:55 -0700 Subject: [PATCH 100/236] Move send sequence keybindings into terminalcontrib --- .../terminal/browser/terminal.contribution.ts | 137 +---------- .../terminal/browser/terminalKeybindings.ts | 24 -- .../terminal.sendCommands.contribution.ts | 226 ++++++++++++++---- 3 files changed, 192 insertions(+), 195 deletions(-) delete mode 100644 src/vs/workbench/contrib/terminal/browser/terminalKeybindings.ts diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 4a4236d5ee5..08df4db79e3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -6,20 +6,13 @@ import { getFontSnippets } from '../../../../base/browser/fonts.js'; import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import { Schemas } from '../../../../base/common/network.js'; -import { isIOS, isWindows } from '../../../../base/common/platform.js'; import { URI } from '../../../../base/common/uri.js'; -import './media/terminal.css'; -import './media/terminalVoice.css'; -import './media/widgets.css'; -import './media/xterm.css'; import * as nls from '../../../../nls.js'; -import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../platform/accessibility/common/accessibility.js'; -import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; import { Extensions as DragAndDropExtensions, IDragAndDropContributionRegistry, IDraggedResourceEditorInput } from '../../../../platform/dnd/browser/dnd.js'; import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; -import { GeneralShellType, ITerminalLogService, WindowsShellType } from '../../../../platform/terminal/common/terminal.js'; +import { ITerminalLogService } from '../../../../platform/terminal/common/terminal.js'; import { TerminalLogService } from '../../../../platform/terminal/common/terminalLogService.js'; import { registerTerminalPlatformConfiguration } from '../../../../platform/terminal/common/terminalPlatformConfiguration.js'; import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js'; @@ -27,6 +20,14 @@ import { ViewPaneContainer } from '../../../browser/parts/views/viewPaneContaine import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js'; import { EditorExtensions, IEditorFactoryRegistry } from '../../../common/editor.js'; import { IViewContainersRegistry, IViewsRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation } from '../../../common/views.js'; +import { ITerminalProfileService, TERMINAL_VIEW_ID, TerminalCommandId } from '../common/terminal.js'; +import { registerColors } from '../common/terminalColorRegistry.js'; +import { registerTerminalConfiguration } from '../common/terminalConfiguration.js'; +import { terminalStrings } from '../common/terminalStrings.js'; +import './media/terminal.css'; +import './media/terminalVoice.css'; +import './media/widgets.css'; +import './media/xterm.css'; import { RemoteTerminalBackendContribution } from './remoteTerminalBackend.js'; import { ITerminalConfigurationService, ITerminalEditorService, ITerminalGroupService, ITerminalInstanceService, ITerminalService, TerminalDataTransfers, terminalEditorId } from './terminal.js'; import { registerTerminalActions } from './terminalActions.js'; @@ -43,14 +44,8 @@ import { TerminalMainContribution } from './terminalMainContribution.js'; import { setupTerminalMenus } from './terminalMenus.js'; import { TerminalProfileService } from './terminalProfileService.js'; import { TerminalService } from './terminalService.js'; -import { TerminalViewPane } from './terminalView.js'; -import { ITerminalProfileService, TERMINAL_VIEW_ID, TerminalCommandId } from '../common/terminal.js'; -import { registerColors } from '../common/terminalColorRegistry.js'; -import { registerTerminalConfiguration } from '../common/terminalConfiguration.js'; -import { TerminalContextKeyStrings, TerminalContextKeys } from '../common/terminalContextKey.js'; -import { terminalStrings } from '../common/terminalStrings.js'; -import { registerSendSequenceKeybinding } from './terminalKeybindings.js'; import { TerminalTelemetryContribution } from './terminalTelemetry.js'; +import { TerminalViewPane } from './terminalView.js'; // Register services registerSingleton(ITerminalLogService, TerminalLogService, InstantiationType.Delayed); @@ -133,120 +128,8 @@ Registry.as(ViewContainerExtensions.ViewsRegistry).registerViews } }], VIEW_CONTAINER); -// Register actions registerTerminalActions(); -const enum Constants { - /** The text representation of `^` is `'A'.charCodeAt(0) + 1`. */ - CtrlLetterOffset = 64 -} - -// An extra Windows-only ctrl+v keybinding is used for pwsh that sends ctrl+v directly to the -// shell, this gets handled by PSReadLine which properly handles multi-line pastes. This is -// disabled in accessibility mode as PowerShell does not run PSReadLine when it detects a screen -// reader. This works even when clipboard.readText is not supported. -if (isWindows) { - registerSendSequenceKeybinding(String.fromCharCode('V'.charCodeAt(0) - Constants.CtrlLetterOffset), { // ctrl+v - when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), - primary: KeyMod.CtrlCmd | KeyCode.KeyV - }); -} - -// Map certain keybindings in pwsh to unused keys which get handled by PSReadLine handlers in the -// shell integration script. This allows keystrokes that cannot be sent via VT sequences to work. -// See https://github.com/microsoft/terminal/issues/879#issuecomment-497775007 -registerSendSequenceKeybinding('\x1b[24~a', { // F12,a -> ctrl+space (MenuComplete) - when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), - primary: KeyMod.CtrlCmd | KeyCode.Space, - mac: { primary: KeyMod.WinCtrl | KeyCode.Space } -}); -registerSendSequenceKeybinding('\x1b[24~b', { // F12,b -> alt+space (SetMark) - when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), - primary: KeyMod.Alt | KeyCode.Space -}); -registerSendSequenceKeybinding('\x1b[24~c', { // F12,c -> shift+enter (AddLine) - when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), - primary: KeyMod.Shift | KeyCode.Enter -}); -registerSendSequenceKeybinding('\x1b[24~d', { // F12,d -> shift+end (SelectLine) - HACK: \x1b[1;2F is supposed to work but it doesn't - when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), - mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.RightArrow } -}); - -// Always on pwsh keybindings -registerSendSequenceKeybinding('\x1b[1;2H', { // Shift+home - when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell)), - mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.LeftArrow } -}); - -// Map ctrl+alt+r -> ctrl+r when in accessibility mode due to default run recent command keybinding -registerSendSequenceKeybinding('\x12', { - when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED), - primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyR, - mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyR } -}); - -// Map ctrl+alt+g -> ctrl+g due to default go to recent directory keybinding -registerSendSequenceKeybinding('\x07', { - when: TerminalContextKeys.focus, - primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyG, - mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyG } -}); - -// send ctrl+c to the iPad when the terminal is focused and ctrl+c is pressed to kill the process (work around for #114009) -if (isIOS) { - registerSendSequenceKeybinding(String.fromCharCode('C'.charCodeAt(0) - Constants.CtrlLetterOffset), { // ctrl+c - when: ContextKeyExpr.and(TerminalContextKeys.focus), - primary: KeyMod.WinCtrl | KeyCode.KeyC - }); -} - -// Delete word left: ctrl+w -registerSendSequenceKeybinding(String.fromCharCode('W'.charCodeAt(0) - Constants.CtrlLetterOffset), { - primary: KeyMod.CtrlCmd | KeyCode.Backspace, - mac: { primary: KeyMod.Alt | KeyCode.Backspace } -}); -if (isWindows) { - // Delete word left: ctrl+h - // Windows cmd.exe requires ^H to delete full word left - registerSendSequenceKeybinding(String.fromCharCode('H'.charCodeAt(0) - Constants.CtrlLetterOffset), { - when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.CommandPrompt)), - primary: KeyMod.CtrlCmd | KeyCode.Backspace, - }); -} -// Delete word right: alt+d [27, 100] -registerSendSequenceKeybinding('\u001bd', { - primary: KeyMod.CtrlCmd | KeyCode.Delete, - mac: { primary: KeyMod.Alt | KeyCode.Delete } -}); -// Delete to line start: ctrl+u -registerSendSequenceKeybinding('\u0015', { - mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace } -}); -// Move to line start: ctrl+A -registerSendSequenceKeybinding(String.fromCharCode('A'.charCodeAt(0) - 64), { - mac: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow } -}); -// Move to line end: ctrl+E -registerSendSequenceKeybinding(String.fromCharCode('E'.charCodeAt(0) - 64), { - mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow } -}); -// NUL: ctrl+shift+2 -registerSendSequenceKeybinding('\u0000', { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Digit2, - mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Digit2 } -}); -// RS: ctrl+shift+6 -registerSendSequenceKeybinding('\u001e', { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Digit6, - mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Digit6 } -}); -// US (Undo): ctrl+/ -registerSendSequenceKeybinding('\u001f', { - primary: KeyMod.CtrlCmd | KeyCode.Slash, - mac: { primary: KeyMod.WinCtrl | KeyCode.Slash } -}); - setupTerminalCommands(); setupTerminalMenus(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalKeybindings.ts b/src/vs/workbench/contrib/terminal/browser/terminalKeybindings.ts deleted file mode 100644 index 39aad28d17d..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/terminalKeybindings.ts +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ContextKeyExpression } from '../../../../platform/contextkey/common/contextkey.js'; -import { IKeybindings, KeybindingWeight, KeybindingsRegistry } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; -import { TerminalCommandId } from '../common/terminal.js'; -import { TerminalContextKeys } from '../common/terminalContextKey.js'; -import { terminalSendSequenceCommand } from './terminalActions.js'; - -export function registerSendSequenceKeybinding(text: string, rule: { when?: ContextKeyExpression } & IKeybindings): void { - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: TerminalCommandId.SendSequence, - weight: KeybindingWeight.WorkbenchContrib, - when: rule.when || TerminalContextKeys.focus, - primary: rule.primary, - mac: rule.mac, - linux: rule.linux, - win: rule.win, - handler: terminalSendSequenceCommand, - args: { text } - }); -} diff --git a/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts b/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts index c04e17ec368..96d85cf671e 100644 --- a/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts @@ -3,21 +3,74 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js'; import { Schemas } from '../../../../../base/common/network.js'; -import { isWindows } from '../../../../../base/common/platform.js'; +import { isIOS, isWindows } from '../../../../../base/common/platform.js'; import { isObject, isString } from '../../../../../base/common/types.js'; import { localize, localize2 } from '../../../../../nls.js'; +import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../../platform/accessibility/common/accessibility.js'; +import { ContextKeyExpr, type ContextKeyExpression } from '../../../../../platform/contextkey/common/contextkey.js'; +import type { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; +import { KeybindingsRegistry, type IKeybindings, KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { IQuickInputService, type QuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js'; +import { GeneralShellType, WindowsShellType } from '../../../../../platform/terminal/common/terminal.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { IConfigurationResolverService } from '../../../../services/configurationResolver/common/configurationResolver.js'; import { IHistoryService } from '../../../../services/history/common/history.js'; +import { ITerminalService } from '../../../terminal/browser/terminal.js'; import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js'; +import { TerminalContextKeys, TerminalContextKeyStrings } from '../../../terminal/common/terminalContextKey.js'; import { TerminalSendCommandsCommandId } from '../common/terminal.sendCommands.js'; function toOptionalString(obj: unknown): string | undefined { return isString(obj) ? obj : undefined; } +export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => { + const quickInputService = accessor.get(IQuickInputService); + const configurationResolverService = accessor.get(IConfigurationResolverService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const historyService = accessor.get(IHistoryService); + const terminalService = accessor.get(ITerminalService); + + const instance = terminalService.activeInstance; + if (instance) { + let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; + + // If no text provided, prompt user for input and process special characters + if (!text) { + text = await quickInputService.input({ + value: '', + placeHolder: 'Enter sequence to send (supports \\n, \\r, \\xAB)', + prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), + }); + if (!text) { + return; + } + // Process escape sequences + let processedText = text + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r'); + + // Process hex escape sequences (\xNN) + while (true) { + const match = processedText.match(/\\x([0-9a-fA-F]{2})/); + if (match === null || match.index === undefined || match.length < 2) { + break; + } + processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); + } + + text = processedText; + } + + const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); + const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; + const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); + instance.sendText(resolvedText, false); + } +}; + const sendSequenceString = localize2('sendSequence', "Send Sequence"); registerTerminalAction({ id: TerminalSendCommandsCommandId.SendSequence, @@ -39,49 +92,7 @@ registerTerminalAction({ } }] }, - run: async (c, accessor, args) => { - const quickInputService = accessor.get(IQuickInputService); - const configurationResolverService = accessor.get(IConfigurationResolverService); - const workspaceContextService = accessor.get(IWorkspaceContextService); - const historyService = accessor.get(IHistoryService); - - const instance = c.service.activeInstance; - if (instance) { - let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined; - - // If no text provided, prompt user for input and process special characters - if (!text) { - text = await quickInputService.input({ - value: '', - placeHolder: 'Enter sequence to send (supports \\n, \\r, \\xAB)', - prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"), - }); - if (!text) { - return; - } - // Process escape sequences - let processedText = text - .replace(/\\n/g, '\n') - .replace(/\\r/g, '\r'); - - // Process hex escape sequences (\xNN) - while (true) { - const match = processedText.match(/\\x([0-9a-fA-F]{2})/); - if (match === null || match.index === undefined || match.length < 2) { - break; - } - processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4); - } - - text = processedText; - } - - const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file); - const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined; - const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text); - instance.sendText(resolvedText, false); - } - } + run: (c, accessor, args) => terminalSendSequenceCommand(accessor, args) }); const sendSignalString = localize2('sendSignal', "Send Signal"); @@ -155,3 +166,130 @@ registerTerminalAction({ await instance.sendSignal(signal); } }); + +export function registerSendSequenceKeybinding(text: string, rule: { when?: ContextKeyExpression } & IKeybindings): void { + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: TerminalSendCommandsCommandId.SendSequence, + weight: KeybindingWeight.WorkbenchContrib, + when: rule.when || TerminalContextKeys.focus, + primary: rule.primary, + mac: rule.mac, + linux: rule.linux, + win: rule.win, + handler: terminalSendSequenceCommand, + args: { text } + }); +} + + + +const enum Constants { + /** The text representation of `^` is `'A'.charCodeAt(0) + 1`. */ + CtrlLetterOffset = 64 +} + +// An extra Windows-only ctrl+v keybinding is used for pwsh that sends ctrl+v directly to the +// shell, this gets handled by PSReadLine which properly handles multi-line pastes. This is +// disabled in accessibility mode as PowerShell does not run PSReadLine when it detects a screen +// reader. This works even when clipboard.readText is not supported. +if (isWindows) { + registerSendSequenceKeybinding(String.fromCharCode('V'.charCodeAt(0) - Constants.CtrlLetterOffset), { // ctrl+v + when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), + primary: KeyMod.CtrlCmd | KeyCode.KeyV + }); +} + +// Map certain keybindings in pwsh to unused keys which get handled by PSReadLine handlers in the +// shell integration script. This allows keystrokes that cannot be sent via VT sequences to work. +// See https://github.com/microsoft/terminal/issues/879#issuecomment-497775007 +registerSendSequenceKeybinding('\x1b[24~a', { // F12,a -> ctrl+space (MenuComplete) + when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), + primary: KeyMod.CtrlCmd | KeyCode.Space, + mac: { primary: KeyMod.WinCtrl | KeyCode.Space } +}); +registerSendSequenceKeybinding('\x1b[24~b', { // F12,b -> alt+space (SetMark) + when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), + primary: KeyMod.Alt | KeyCode.Space +}); +registerSendSequenceKeybinding('\x1b[24~c', { // F12,c -> shift+enter (AddLine) + when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), + primary: KeyMod.Shift | KeyCode.Enter +}); +registerSendSequenceKeybinding('\x1b[24~d', { // F12,d -> shift+end (SelectLine) - HACK: \x1b[1;2F is supposed to work but it doesn't + when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), + mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.RightArrow } +}); + +// Always on pwsh keybindings +registerSendSequenceKeybinding('\x1b[1;2H', { // Shift+home + when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, GeneralShellType.PowerShell)), + mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.LeftArrow } +}); + +// Map ctrl+alt+r -> ctrl+r when in accessibility mode due to default run recent command keybinding +registerSendSequenceKeybinding('\x12', { + when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED), + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyR, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyR } +}); + +// Map ctrl+alt+g -> ctrl+g due to default go to recent directory keybinding +registerSendSequenceKeybinding('\x07', { + when: TerminalContextKeys.focus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyG, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyG } +}); + +// send ctrl+c to the iPad when the terminal is focused and ctrl+c is pressed to kill the process (work around for #114009) +if (isIOS) { + registerSendSequenceKeybinding(String.fromCharCode('C'.charCodeAt(0) - Constants.CtrlLetterOffset), { // ctrl+c + when: ContextKeyExpr.and(TerminalContextKeys.focus), + primary: KeyMod.WinCtrl | KeyCode.KeyC + }); +} + +// Delete word left: ctrl+w +registerSendSequenceKeybinding(String.fromCharCode('W'.charCodeAt(0) - Constants.CtrlLetterOffset), { + primary: KeyMod.CtrlCmd | KeyCode.Backspace, + mac: { primary: KeyMod.Alt | KeyCode.Backspace } +}); +if (isWindows) { + // Delete word left: ctrl+h + // Windows cmd.exe requires ^H to delete full word left + registerSendSequenceKeybinding(String.fromCharCode('H'.charCodeAt(0) - Constants.CtrlLetterOffset), { + when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.CommandPrompt)), + primary: KeyMod.CtrlCmd | KeyCode.Backspace, + }); +} +// Delete word right: alt+d [27, 100] +registerSendSequenceKeybinding('\u001bd', { + primary: KeyMod.CtrlCmd | KeyCode.Delete, + mac: { primary: KeyMod.Alt | KeyCode.Delete } +}); +// Delete to line start: ctrl+u +registerSendSequenceKeybinding('\u0015', { + mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace } +}); +// Move to line start: ctrl+A +registerSendSequenceKeybinding(String.fromCharCode('A'.charCodeAt(0) - 64), { + mac: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow } +}); +// Move to line end: ctrl+E +registerSendSequenceKeybinding(String.fromCharCode('E'.charCodeAt(0) - 64), { + mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow } +}); +// NUL: ctrl+shift+2 +registerSendSequenceKeybinding('\u0000', { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Digit2, + mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Digit2 } +}); +// RS: ctrl+shift+6 +registerSendSequenceKeybinding('\u001e', { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Digit6, + mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Digit6 } +}); +// US (Undo): ctrl+/ +registerSendSequenceKeybinding('\u001f', { + primary: KeyMod.CtrlCmd | KeyCode.Slash, + mac: { primary: KeyMod.WinCtrl | KeyCode.Slash } +}); From e07f67764b01115f84027867d328692410aba3d9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:52:31 -0700 Subject: [PATCH 101/236] Split send signal and sequence into own contribs --- .../contrib/terminal/terminal.all.ts | 3 +- .../common/terminal.sendCommands.ts | 9 -- .../terminal.sendSequence.contribution.ts} | 85 ++---------------- .../terminal.sendSignal.contribution.ts | 90 +++++++++++++++++++ 4 files changed, 100 insertions(+), 87 deletions(-) delete mode 100644 src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts rename src/vs/workbench/contrib/terminalContrib/{sendCommands/browser/terminal.sendCommands.contribution.ts => sendSequence/browser/terminal.sendSequence.contribution.ts} (79%) create mode 100644 src/vs/workbench/contrib/terminalContrib/sendSignal/browser/terminal.sendSignal.contribution.ts diff --git a/src/vs/workbench/contrib/terminal/terminal.all.ts b/src/vs/workbench/contrib/terminal/terminal.all.ts index 5ada9a8fe9b..5189ed4a3a2 100644 --- a/src/vs/workbench/contrib/terminal/terminal.all.ts +++ b/src/vs/workbench/contrib/terminal/terminal.all.ts @@ -27,7 +27,8 @@ import '../terminalContrib/stickyScroll/browser/terminal.stickyScroll.contributi import '../terminalContrib/quickAccess/browser/terminal.quickAccess.contribution.js'; import '../terminalContrib/quickFix/browser/terminal.quickFix.contribution.js'; import '../terminalContrib/typeAhead/browser/terminal.typeAhead.contribution.js'; -import '../terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.js'; +import '../terminalContrib/sendSequence/browser/terminal.sendSequence.contribution.js'; +import '../terminalContrib/sendSignal/browser/terminal.sendSignal.contribution.js'; import '../terminalContrib/suggest/browser/terminal.suggest.contribution.js'; import '../terminalContrib/chat/browser/terminal.initialHint.contribution.js'; import '../terminalContrib/wslRecommendation/browser/terminal.wslRecommendation.contribution.js'; diff --git a/src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts b/src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts deleted file mode 100644 index 8d444a7538f..00000000000 --- a/src/vs/workbench/contrib/terminalContrib/sendCommands/common/terminal.sendCommands.ts +++ /dev/null @@ -1,9 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -export const enum TerminalSendCommandsCommandId { - SendSequence = 'workbench.action.terminal.sendSequence', - SendSignal = 'workbench.action.terminal.sendSignal', -} diff --git a/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts b/src/vs/workbench/contrib/terminalContrib/sendSequence/browser/terminal.sendSequence.contribution.ts similarity index 79% rename from src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts rename to src/vs/workbench/contrib/terminalContrib/sendSequence/browser/terminal.sendSequence.contribution.ts index 96d85cf671e..ee7f21b223c 100644 --- a/src/vs/workbench/contrib/terminalContrib/sendCommands/browser/terminal.sendCommands.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/sendSequence/browser/terminal.sendSequence.contribution.ts @@ -11,8 +11,8 @@ import { localize, localize2 } from '../../../../../nls.js'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../../platform/accessibility/common/accessibility.js'; import { ContextKeyExpr, type ContextKeyExpression } from '../../../../../platform/contextkey/common/contextkey.js'; import type { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; -import { KeybindingsRegistry, type IKeybindings, KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; -import { IQuickInputService, type QuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js'; +import { KeybindingsRegistry, KeybindingWeight, type IKeybindings } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { IQuickInputService } from '../../../../../platform/quickinput/common/quickInput.js'; import { GeneralShellType, WindowsShellType } from '../../../../../platform/terminal/common/terminal.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { IConfigurationResolverService } from '../../../../services/configurationResolver/common/configurationResolver.js'; @@ -20,7 +20,10 @@ import { IHistoryService } from '../../../../services/history/common/history.js' import { ITerminalService } from '../../../terminal/browser/terminal.js'; import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js'; import { TerminalContextKeys, TerminalContextKeyStrings } from '../../../terminal/common/terminalContextKey.js'; -import { TerminalSendCommandsCommandId } from '../common/terminal.sendCommands.js'; + +export const enum TerminalSendSequenceCommandId { + SendSequence = 'workbench.action.terminal.sendSequence', +} function toOptionalString(obj: unknown): string | undefined { return isString(obj) ? obj : undefined; @@ -73,7 +76,7 @@ export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, ar const sendSequenceString = localize2('sendSequence', "Send Sequence"); registerTerminalAction({ - id: TerminalSendCommandsCommandId.SendSequence, + id: TerminalSendSequenceCommandId.SendSequence, title: sendSequenceString, f1: true, metadata: { @@ -95,81 +98,9 @@ registerTerminalAction({ run: (c, accessor, args) => terminalSendSequenceCommand(accessor, args) }); -const sendSignalString = localize2('sendSignal', "Send Signal"); -registerTerminalAction({ - id: TerminalSendCommandsCommandId.SendSignal, - title: sendSignalString, - f1: !isWindows, - metadata: { - description: sendSignalString.value, - args: [{ - name: 'args', - schema: { - type: 'object', - required: ['signal'], - properties: { - signal: { - description: localize('sendSignal.signal.desc', "The signal to send to the terminal process (e.g., 'SIGTERM', 'SIGINT', 'SIGKILL')"), - type: 'string' - } - }, - } - }] - }, - run: async (c, accessor, args) => { - const quickInputService = accessor.get(IQuickInputService); - const instance = c.service.activeInstance; - if (!instance) { - return; - } - - let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; - - if (!signal) { - const signalOptions: QuickPickItem[] = [ - { label: 'SIGINT', description: localize('SIGINT', 'Interrupt process (Ctrl+C)') }, - { label: 'SIGTERM', description: localize('SIGTERM', 'Terminate process gracefully') }, - { label: 'SIGKILL', description: localize('SIGKILL', 'Force kill process') }, - { label: 'SIGSTOP', description: localize('SIGSTOP', 'Stop process') }, - { label: 'SIGCONT', description: localize('SIGCONT', 'Continue process') }, - { label: 'SIGHUP', description: localize('SIGHUP', 'Hangup') }, - { label: 'SIGQUIT', description: localize('SIGQUIT', 'Quit process') }, - { label: 'SIGUSR1', description: localize('SIGUSR1', 'User-defined signal 1') }, - { label: 'SIGUSR2', description: localize('SIGUSR2', 'User-defined signal 2') }, - { type: 'separator' }, - { label: localize('manualSignal', 'Manually enter signal') } - ]; - - const selected = await quickInputService.pick(signalOptions, { - placeHolder: localize('selectSignal', 'Select signal to send to terminal process') - }); - - if (!selected) { - return; - } - - if (selected.label === localize('manualSignal', 'Manually enter signal')) { - const inputSignal = await quickInputService.input({ - prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), - }); - - if (!inputSignal) { - return; - } - - signal = inputSignal; - } else { - signal = selected.label; - } - } - - await instance.sendSignal(signal); - } -}); - export function registerSendSequenceKeybinding(text: string, rule: { when?: ContextKeyExpression } & IKeybindings): void { KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: TerminalSendCommandsCommandId.SendSequence, + id: TerminalSendSequenceCommandId.SendSequence, weight: KeybindingWeight.WorkbenchContrib, when: rule.when || TerminalContextKeys.focus, primary: rule.primary, diff --git a/src/vs/workbench/contrib/terminalContrib/sendSignal/browser/terminal.sendSignal.contribution.ts b/src/vs/workbench/contrib/terminalContrib/sendSignal/browser/terminal.sendSignal.contribution.ts new file mode 100644 index 00000000000..5891e34fdb6 --- /dev/null +++ b/src/vs/workbench/contrib/terminalContrib/sendSignal/browser/terminal.sendSignal.contribution.ts @@ -0,0 +1,90 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { isWindows } from '../../../../../base/common/platform.js'; +import { isObject, isString } from '../../../../../base/common/types.js'; +import { localize, localize2 } from '../../../../../nls.js'; +import { IQuickInputService, type QuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js'; +import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js'; + +export const enum TerminalSendSignalCommandId { + SendSignal = 'workbench.action.terminal.sendSignal', +} + +function toOptionalString(obj: unknown): string | undefined { + return isString(obj) ? obj : undefined; +} + +const sendSignalString = localize2('sendSignal', "Send Signal"); +registerTerminalAction({ + id: TerminalSendSignalCommandId.SendSignal, + title: sendSignalString, + f1: !isWindows, + metadata: { + description: sendSignalString.value, + args: [{ + name: 'args', + schema: { + type: 'object', + required: ['signal'], + properties: { + signal: { + description: localize('sendSignal.signal.desc', "The signal to send to the terminal process (e.g., 'SIGTERM', 'SIGINT', 'SIGKILL')"), + type: 'string' + } + }, + } + }] + }, + run: async (c, accessor, args) => { + const quickInputService = accessor.get(IQuickInputService); + const instance = c.service.activeInstance; + if (!instance) { + return; + } + + let signal = isObject(args) && 'signal' in args ? toOptionalString(args.signal) : undefined; + + if (!signal) { + const signalOptions: QuickPickItem[] = [ + { label: 'SIGINT', description: localize('SIGINT', 'Interrupt process (Ctrl+C)') }, + { label: 'SIGTERM', description: localize('SIGTERM', 'Terminate process gracefully') }, + { label: 'SIGKILL', description: localize('SIGKILL', 'Force kill process') }, + { label: 'SIGSTOP', description: localize('SIGSTOP', 'Stop process') }, + { label: 'SIGCONT', description: localize('SIGCONT', 'Continue process') }, + { label: 'SIGHUP', description: localize('SIGHUP', 'Hangup') }, + { label: 'SIGQUIT', description: localize('SIGQUIT', 'Quit process') }, + { label: 'SIGUSR1', description: localize('SIGUSR1', 'User-defined signal 1') }, + { label: 'SIGUSR2', description: localize('SIGUSR2', 'User-defined signal 2') }, + { type: 'separator' }, + { label: localize('manualSignal', 'Manually enter signal') } + ]; + + const selected = await quickInputService.pick(signalOptions, { + placeHolder: localize('selectSignal', 'Select signal to send to terminal process') + }); + + if (!selected) { + return; + } + + if (selected.label === localize('manualSignal', 'Manually enter signal')) { + const inputSignal = await quickInputService.input({ + prompt: localize('enterSignal', 'Enter signal name (e.g., SIGTERM, SIGKILL)'), + }); + + if (!inputSignal) { + return; + } + + signal = inputSignal; + } else { + signal = selected.label; + } + } + + await instance.sendSignal(signal); + } +}); From 814579dd49c035398e50fee6ebd63a3d9998b3e3 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 6 Jun 2025 12:25:06 -0700 Subject: [PATCH 102/236] mcp: fix resource picker sometimes is empty (#250892) We didn't trigger a 'change' after the promise resolved, so if we resolve rec.templates and rec.resources synchronously (for a server with no mcp resources) then we could end before publishing everything Refs #250890 --- src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts b/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts index 2946ced9d69..d844736de57 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts @@ -329,6 +329,7 @@ export class McpResourcePickHelper { rec.templates.complete([]); rec.resources.complete([]); } + publish(); })).finally(() => { store.dispose(); }); From aed60d29b92e46785190f29e40f21c1e7a5abe66 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 6 Jun 2025 12:27:17 -0700 Subject: [PATCH 103/236] mcp: fix resource picker sometimes is empty (#250891) We didn't trigger a 'change' after the promise resolved, so if we resolve rec.templates and rec.resources synchronously (for a server with no mcp resources) then we could end before publishing everything Refs #250890 From ddb8c8bd13fba584d27c89a1c94d9e940e244fc4 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Sat, 7 Jun 2025 00:00:35 +0200 Subject: [PATCH 104/236] move platform/prompts to vs/workbench/contrib/chat/common/promptSyntax (#250889) * move platform/prompts to vs/workbench/contrib/chat/common/promptSyntax * promptSync: bring back extension check --- .../common/promptsSync/promptsSync.ts | 14 +- .../promptInstructionsCollectionWidget.ts | 2 +- .../promptInstructionsWidget.ts | 2 +- .../contrib/chat/browser/chat.contribution.ts | 12 +- .../chatPromptAttachmentsCollection.ts | 2 +- .../contrib/chat/browser/chatWidget.ts | 4 +- .../browser/contrib/chatDynamicVariables.ts | 2 +- .../browser/contrib/chatImplicitContext.ts | 4 +- .../browser/contrib/chatInputCompletions.ts | 2 +- .../modelPicker/modePickerActionItem.ts | 2 +- .../promptSyntax/attachInstructionsAction.ts | 8 +- .../browser/promptSyntax/chatModeActions.ts | 4 +- .../promptSyntax/newPromptFileActions.ts | 5 +- .../promptSyntax/pickers/askForPromptName.ts | 3 +- .../pickers/askForPromptSourceFolder.ts | 5 +- .../promptSyntax/pickers/promptFilePickers.ts | 6 +- .../promptToolsCodeLensProvider.ts | 4 +- .../browser/promptSyntax/runPromptAction.ts | 7 +- .../promptSyntax/saveToPromptAction.ts | 4 +- .../contrib/chat/common/chatModes.ts | 2 +- .../contrib/chat/common/chatParserTypes.ts | 2 +- .../contrib/chat/common/chatRequestParser.ts | 2 +- .../common/promptSyntax/config}/config.ts | 76 ++- .../configMigration.ts | 17 +- .../config/promptFileLocations.ts} | 66 +-- .../filePromptContentsProvider.ts | 4 +- .../promptContentsProviderBase.ts | 15 +- .../textModelContentsProvider.ts | 12 +- .../promptSyntax/contentProviders/types.ts | 2 +- .../promptSyntax/contributions/index.ts | 39 -- .../contributions/languageFeatures/index.ts | 43 -- .../decorations/utils/index.ts | 18 - .../decorations/frontMatterDecoration.ts | 15 +- .../frontMatterMarkerDecoration.ts | 5 +- .../decorations/utils/decorationBase.ts | 10 +- .../utils/reactiveDecorationBase.ts | 4 +- .../decorations/utils/types.ts | 2 +- .../promptDecorationsProvider.ts | 17 +- .../decorationsProvider/types.ts | 4 +- .../promptHeaderDiagnosticsProvider.ts | 12 +- .../promptLinkDiagnosticsProvider.ts | 14 +- .../promptLinkProvider.ts | 25 +- .../promptPathAutocompletion.ts | 30 +- .../providerInstanceBase.ts | 8 +- .../providerInstanceManagerBase.ts | 24 +- .../promptSyntax/parsers/basePromptParser.ts | 4 +- .../promptHeader/instructionsHeader.ts | 2 +- .../parsers/promptHeader/metadata/applyTo.ts | 2 +- .../parsers/promptHeader/modeHeader.ts | 2 +- .../parsers/promptHeader/promptHeader.ts | 2 +- .../promptSyntax/parsers/promptParser.ts | 4 +- .../promptSyntax/promptFileContributions.ts | 60 ++ .../{constants.ts => promptTypes.ts} | 13 +- .../promptSyntax/service/promptsService.ts | 518 ++++++------------ .../service/promptsServiceImpl.ts | 382 +++++++++++++ .../chat/common/promptSyntax/service/types.ts | 224 -------- .../promptSyntax/utils/promptFilesLocator.ts | 7 +- .../test/common/chatRequestParser.test.ts | 2 +- .../chat/test/common/config}/config.test.ts | 13 +- .../test/common/config}/constants.test.ts | 8 +- .../test/common/config/utils/mock.test.ts | 194 +++++++ .../chat/test/common/mockPromptsService.ts | 4 +- .../common/promptSyntax/config/config.test.ts | 461 ++++++++++++++++ .../promptSyntax/config/constants.test.ts | 89 +++ .../parsers/textModelPromptParser.test.ts | 4 +- .../promptSyntax/promptFileReference.test.ts | 43 +- .../service/promptsService.test.ts | 38 +- .../common/promptSyntax}/utils/mock.test.ts | 8 +- .../test/common/promptSyntax}/utils/mock.ts | 6 +- .../utils/promptFilesLocator.test.ts | 28 +- .../browser/inlineChatCurrentLine.ts | 4 +- .../test/browser/inlineChatController.test.ts | 2 +- .../userDataSync/browser/userDataSync.ts | 16 +- 73 files changed, 1684 insertions(+), 1016 deletions(-) rename src/vs/{platform/prompts/common => workbench/contrib/chat/common/promptSyntax/config}/config.ts (65%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions => config}/configMigration.ts (83%) rename src/vs/{platform/prompts/common/prompts.ts => workbench/contrib/chat/common/promptSyntax/config/promptFileLocations.ts} (66%) delete mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/contributions/index.ts delete mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/index.ts delete mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/index.ts rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/decorationsProvider/decorations/frontMatterDecoration.ts (84%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/decorationsProvider/decorations/frontMatterMarkerDecoration.ts (85%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/decorationsProvider/decorations/utils/decorationBase.ts (89%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/decorationsProvider/decorations/utils/reactiveDecorationBase.ts (96%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/decorationsProvider/decorations/utils/types.ts (97%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/decorationsProvider/promptDecorationsProvider.ts (87%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/decorationsProvider/types.ts (85%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/promptHeaderDiagnosticsProvider.ts (88%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/promptLinkDiagnosticsProvider.ts (88%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/promptLinkProvider.ts (63%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/promptPathAutocompletion.ts (89%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/providerInstanceBase.ts (84%) rename src/vs/workbench/contrib/chat/common/promptSyntax/{contributions/languageFeatures/providers => languageProviders}/providerInstanceManagerBase.ts (83%) create mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts rename src/vs/workbench/contrib/chat/common/promptSyntax/{constants.ts => promptTypes.ts} (85%) create mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts delete mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts rename src/vs/{platform/prompts/test/common => workbench/contrib/chat/test/common/config}/config.test.ts (97%) rename src/vs/{platform/prompts/test/common => workbench/contrib/chat/test/common/config}/constants.test.ts (91%) create mode 100644 src/vs/workbench/contrib/chat/test/common/config/utils/mock.test.ts create mode 100644 src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts create mode 100644 src/vs/workbench/contrib/chat/test/common/promptSyntax/config/constants.test.ts rename src/vs/{platform/prompts/test/common => workbench/contrib/chat/test/common/promptSyntax}/utils/mock.test.ts (94%) rename src/vs/{platform/prompts/test/common => workbench/contrib/chat/test/common/promptSyntax}/utils/mock.ts (93%) diff --git a/src/vs/platform/userDataSync/common/promptsSync/promptsSync.ts b/src/vs/platform/userDataSync/common/promptsSync/promptsSync.ts index 4dd6fbe6823..a1f1b54b5f1 100644 --- a/src/vs/platform/userDataSync/common/promptsSync/promptsSync.ts +++ b/src/vs/platform/userDataSync/common/promptsSync/promptsSync.ts @@ -13,7 +13,7 @@ import { IStringDictionary } from '../../../../base/common/collections.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; import { IUriIdentityService } from '../../../uriIdentity/common/uriIdentity.js'; import { IEnvironmentService } from '../../../environment/common/environment.js'; -import { isPromptOrInstructionsFile } from '../../../prompts/common/prompts.js'; + import { IUserDataProfile } from '../../../userDataProfile/common/userDataProfile.js'; import { IConfigurationService } from '../../../configuration/common/configuration.js'; import { areSame, IMergeResult as IPromptsMergeResult, merge } from './promptsMerge.js'; @@ -516,14 +516,12 @@ export class PromptsSynchronizer extends AbstractSynchroniser implements IUserDa } for (const entry of stat.children || []) { const resource = entry.resource; - - if (isPromptOrInstructionsFile(resource) === false) { - continue; + const path = resource.path; + if (['.prompt.md', '.instructions.md', '.chatmode.md'].some(ext => path.endsWith(ext))) { + const key = this.extUri.relativePath(this.promptsFolder, resource)!; + const content = await this.fileService.readFile(resource); + prompts[key] = content; } - - const key = this.extUri.relativePath(this.promptsFolder, resource)!; - const content = await this.fileService.readFile(resource); - prompts[key] = content; } return prompts; diff --git a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts index ab0820b7bc8..c396b55a253 100644 --- a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts @@ -10,7 +10,7 @@ import { Disposable } from '../../../../../../base/common/lifecycle.js'; import { ILogService } from '../../../../../../platform/log/common/log.js'; import { InstructionsAttachmentWidget } from './promptInstructionsWidget.js'; import { IModelService } from '../../../../../../editor/common/services/model.js'; -import { INSTRUCTIONS_LANGUAGE_ID } from '../../../common/promptSyntax/constants.js'; +import { INSTRUCTIONS_LANGUAGE_ID } from '../../../common/promptSyntax/promptTypes.js'; import { ILanguageService } from '../../../../../../editor/common/languages/language.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { ChatPromptAttachmentsCollection } from '../../chatAttachmentModel/chatPromptAttachmentsCollection.js'; diff --git a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts index 2282a3f6a4c..0478cf49691 100644 --- a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts @@ -20,7 +20,7 @@ import { IHoverService } from '../../../../../../platform/hover/browser/hover.js import { ILanguageService } from '../../../../../../editor/common/languages/language.js'; import { FileKind, IFileService } from '../../../../../../platform/files/common/files.js'; import { IMenuService, MenuId } from '../../../../../../platform/actions/common/actions.js'; -import { getCleanPromptName } from '../../../../../../platform/prompts/common/prompts.js'; +import { getCleanPromptName } from '../../../common/promptSyntax/config/promptFileLocations.js'; import { ObservableDisposable } from '../../../common/promptSyntax/utils/observableDisposable.js'; import { IContextKeyService } from '../../../../../../platform/contextkey/common/contextkey.js'; import { ChatPromptAttachmentModel } from '../../chatAttachmentModel/chatPromptAttachmentModel.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 359dc97c4df..be5215d19e5 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -20,8 +20,8 @@ import { SyncDescriptor } from '../../../../platform/instantiation/common/descri import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { mcpGalleryServiceUrlConfig } from '../../../../platform/mcp/common/mcpManagement.js'; -import { PromptsConfig } from '../../../../platform/prompts/common/config.js'; -import { INSTRUCTIONS_DEFAULT_SOURCE_FOLDER, INSTRUCTION_FILE_EXTENSION, MODE_DEFAULT_SOURCE_FOLDER, MODE_FILE_EXTENSION, PROMPT_DEFAULT_SOURCE_FOLDER, PROMPT_FILE_EXTENSION } from '../../../../platform/prompts/common/prompts.js'; +import { PromptsConfig } from '../common/promptSyntax/config/config.js'; +import { INSTRUCTIONS_DEFAULT_SOURCE_FOLDER, INSTRUCTION_FILE_EXTENSION, MODE_DEFAULT_SOURCE_FOLDER, MODE_FILE_EXTENSION, PROMPT_DEFAULT_SOURCE_FOLDER, PROMPT_FILE_EXTENSION } from '../common/promptSyntax/config/promptFileLocations.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js'; import { Extensions, IConfigurationMigrationRegistry } from '../../../common/configuration.js'; @@ -48,10 +48,10 @@ import { ILanguageModelIgnoredFilesService, LanguageModelIgnoredFilesService } f import { ILanguageModelsService, LanguageModelsService } from '../common/languageModels.js'; import { ILanguageModelStatsService, LanguageModelStatsService } from '../common/languageModelStats.js'; import { ILanguageModelToolsService } from '../common/languageModelToolsService.js'; -import { INSTRUCTIONS_DOCUMENTATION_URL, MODE_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../common/promptSyntax/constants.js'; -import { registerPromptFileContributions } from '../common/promptSyntax/contributions/index.js'; -import { PromptsService } from '../common/promptSyntax/service/promptsService.js'; -import { IPromptsService } from '../common/promptSyntax/service/types.js'; +import { INSTRUCTIONS_DOCUMENTATION_URL, MODE_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../common/promptSyntax/promptTypes.js'; +import { registerPromptFileContributions } from '../common/promptSyntax/promptFileContributions.js'; +import { PromptsService } from '../common/promptSyntax/service/promptsServiceImpl.js'; +import { IPromptsService } from '../common/promptSyntax/service/promptsService.js'; import { LanguageModelToolsExtensionPointHandler } from '../common/tools/languageModelToolsContribution.js'; import { BuiltinToolsContribution } from '../common/tools/tools.js'; import { ConfigureToolSets, UserToolSetsContributions } from './tools/toolSetsContribution.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts index 94393439c16..bab83dc9130 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts @@ -7,7 +7,7 @@ import { URI } from '../../../../../base/common/uri.js'; import { Emitter } from '../../../../../base/common/event.js'; import { basename, isEqual } from '../../../../../base/common/resources.js'; import { ChatPromptAttachmentModel } from './chatPromptAttachmentModel.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IPromptFileReference } from '../../common/promptSyntax/parsers/types.js'; import { Disposable, DisposableMap } from '../../../../../base/common/lifecycle.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index ec29789b0f1..d56b717e5fb 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -34,7 +34,7 @@ import { ServiceCollection } from '../../../../platform/instantiation/common/ser import { WorkbenchObjectTree } from '../../../../platform/list/browser/listService.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { bindContextKey } from '../../../../platform/observable/common/platformObservableUtils.js'; -import { PromptsType } from '../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../common/promptSyntax/promptTypes.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground } from '../../../../platform/theme/common/colorRegistry.js'; import { asCssVariable } from '../../../../platform/theme/common/colorUtils.js'; @@ -54,7 +54,7 @@ import { CodeBlockModelCollection } from '../common/codeBlockModelCollection.js' import { ChatAgentLocation, ChatMode } from '../common/constants.js'; import { ILanguageModelToolsService, IToolData, ToolSet } from '../common/languageModelToolsService.js'; import { type TPromptMetadata } from '../common/promptSyntax/parsers/promptHeader/promptHeader.js'; -import { IMetadata, IPromptsService } from '../common/promptSyntax/service/types.js'; +import { IMetadata, IPromptsService } from '../common/promptSyntax/service/promptsService.js'; import { handleModeSwitch } from './actions/chatActions.js'; import { ChatTreeItem, IChatAcceptInputOptions, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileTreeInfo, IChatListItemRendererOptions, IChatWidget, IChatWidgetService, IChatWidgetViewContext, IChatWidgetViewOptions } from './chat.js'; import { ChatAccessibilityProvider } from './chatAccessibilityProvider.js'; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts index 8c3f93517f1..3fafbb4cbc0 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts @@ -15,7 +15,7 @@ import { ICommandService } from '../../../../../platform/commands/common/command import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IChatRequestVariableValue, IDynamicVariable } from '../../common/chatVariables.js'; import { IChatWidget } from '../chat.js'; import { ChatWidget, IChatWidgetContrib } from '../chatWidget.js'; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts index ef5a6cfc78a..15e36a441f6 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts @@ -25,8 +25,8 @@ import { IChatRequestFileEntry, IChatRequestImplicitVariableEntry } from '../../ import { IChatService } from '../../common/chatService.js'; import { ChatAgentLocation } from '../../common/constants.js'; import { ILanguageModelIgnoredFilesService } from '../../common/ignoredFiles.js'; -import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/constants.js'; -import { IPromptsService, TSharedPrompt } from '../../common/promptSyntax/service/types.js'; +import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/promptTypes.js'; +import { IPromptsService, TSharedPrompt } from '../../common/promptSyntax/service/promptsService.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; import { toChatVariable } from '../chatAttachmentModel/chatPromptAttachmentsCollection.js'; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts index 8c765ee7f36..04d8f730e70 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts @@ -52,7 +52,7 @@ import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; import { IDynamicVariable } from '../../common/chatVariables.js'; import { ChatAgentLocation, ChatMode } from '../../common/constants.js'; import { ToolSet } from '../../common/languageModelToolsService.js'; -import { IPromptsService } from '../../common/promptSyntax/service/types.js'; +import { IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; import { ChatSubmitAction } from '../actions/chatExecuteActions.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; import { ChatInputPart } from '../chatInputPart.js'; diff --git a/src/vs/workbench/contrib/chat/browser/modelPicker/modePickerActionItem.ts b/src/vs/workbench/contrib/chat/browser/modelPicker/modePickerActionItem.ts index 83fe032ddbd..d9d7dedff14 100644 --- a/src/vs/workbench/contrib/chat/browser/modelPicker/modePickerActionItem.ts +++ b/src/vs/workbench/contrib/chat/browser/modelPicker/modePickerActionItem.ts @@ -19,7 +19,7 @@ import { IKeybindingService } from '../../../../../platform/keybinding/common/ke import { IChatAgentService } from '../../common/chatAgents.js'; import { IChatMode, IChatModeService } from '../../common/chatModes.js'; import { ChatAgentLocation, ChatMode, modeToString } from '../../common/constants.js'; -import { IPromptsService } from '../../common/promptSyntax/service/types.js'; +import { IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; import { getOpenChatActionIdForMode } from '../actions/chatActions.js'; import { IToggleChatModeArgs } from '../actions/chatExecuteActions.js'; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts index 3994c454e7f..48d57addab3 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts @@ -8,8 +8,8 @@ import { CHAT_CATEGORY } from '../actions/chatActions.js'; import { URI } from '../../../../../base/common/uri.js'; import { localize, localize2 } from '../../../../../nls.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; -import { IPromptsService } from '../../common/promptSyntax/service/types.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { PromptFilePickers } from './pickers/promptFilePickers.js'; import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; @@ -19,7 +19,8 @@ import { IInstantiationService } from '../../../../../platform/instantiation/com import { ChatContextPick, IChatContextPickerItem, IChatContextPickerPickItem } from '../chatContextPickService.js'; import { IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js'; import { Codicon } from '../../../../../base/common/codicons.js'; -import { getCleanPromptName, PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { getCleanPromptName } from '../../common/promptSyntax/config/promptFileLocations.js'; +import { INSTRUCTIONS_LANGUAGE_ID, PromptsType } from '../../common/promptSyntax/promptTypes.js'; import { compare } from '../../../../../base/common/strings.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; import { dirname } from '../../../../../base/common/resources.js'; @@ -27,7 +28,6 @@ import { IPromptFileVariableEntry } from '../../common/chatModel.js'; import { KeyMod, KeyCode } from '../../../../../base/common/keyCodes.js'; import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; -import { INSTRUCTIONS_LANGUAGE_ID } from '../../common/promptSyntax/constants.js'; import { CancellationToken } from '../../../../../base/common/cancellation.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts index 8ff2232a697..20a976612c3 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts @@ -7,13 +7,13 @@ import { CHAT_CATEGORY } from '../actions/chatActions.js'; import { Codicon } from '../../../../../base/common/codicons.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { localize, localize2 } from '../../../../../nls.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { PromptFilePickers } from './pickers/promptFilePickers.js'; import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; -import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../../common/promptSyntax/promptTypes.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; import { ChatViewId } from '../chat.js'; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/newPromptFileActions.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/newPromptFileActions.ts index 44242df33bb..7f3a512661f 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/newPromptFileActions.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/newPromptFileActions.ts @@ -17,14 +17,13 @@ import { KeybindingWeight } from '../../../../../platform/keybinding/common/keyb import { ILogService } from '../../../../../platform/log/common/log.js'; import { INotificationService, NeverShowAgainScope, Severity } from '../../../../../platform/notification/common/notification.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; -import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; +import { getLanguageIdForPromptsType, PromptsType } from '../../common/promptSyntax/promptTypes.js'; import { IUserDataSyncEnablementService, SyncResource } from '../../../../../platform/userDataSync/common/userDataSync.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { CONFIGURE_SYNC_COMMAND_ID } from '../../../../services/userDataSync/common/userDataSync.js'; import { ISnippetsService } from '../../../snippets/browser/snippets.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; -import { getLanguageIdForPromptsType } from '../../common/promptSyntax/constants.js'; import { CHAT_CATEGORY } from '../actions/chatActions.js'; import { askForPromptFileName } from './pickers/askForPromptName.js'; import { askForPromptSourceFolder } from './pickers/askForPromptSourceFolder.js'; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptName.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptName.ts index b0a3210efbe..af69d44f8ee 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptName.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptName.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from '../../../../../../nls.js'; -import { getPromptFileExtension, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { getPromptFileExtension } from '../../../common/promptSyntax/config/promptFileLocations.js'; +import { PromptsType } from '../../../common/promptSyntax/promptTypes.js'; import { IQuickInputService } from '../../../../../../platform/quickinput/common/quickInput.js'; import { URI } from '../../../../../../base/common/uri.js'; import { IFileService } from '../../../../../../platform/files/common/files.js'; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptSourceFolder.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptSourceFolder.ts index b488f643466..00c45a3d4c3 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptSourceFolder.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/askForPromptSourceFolder.ts @@ -9,11 +9,10 @@ import { ServicesAccessor } from '../../../../../../editor/browser/editorExtensi import { localize } from '../../../../../../nls.js'; import { ILabelService } from '../../../../../../platform/label/common/label.js'; import { IOpenerService } from '../../../../../../platform/opener/common/opener.js'; -import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { PROMPT_DOCUMENTATION_URL, PromptsType } from '../../../common/promptSyntax/promptTypes.js'; import { IPickOptions, IQuickInputService, IQuickPickItem } from '../../../../../../platform/quickinput/common/quickInput.js'; import { IWorkspaceContextService } from '../../../../../../platform/workspace/common/workspace.js'; -import { PROMPT_DOCUMENTATION_URL } from '../../../common/promptSyntax/constants.js'; -import { IPromptPath, IPromptsService } from '../../../common/promptSyntax/service/types.js'; +import { IPromptPath, IPromptsService } from '../../../common/promptSyntax/service/promptsService.js'; interface IFolderQuickPickItem extends IQuickPickItem { diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/promptFilePickers.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/promptFilePickers.ts index cc93b1d078b..32464f5b4b0 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/promptFilePickers.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/pickers/promptFilePickers.ts @@ -8,7 +8,7 @@ import { URI } from '../../../../../../base/common/uri.js'; import { assert } from '../../../../../../base/common/assert.js'; import { Codicon } from '../../../../../../base/common/codicons.js'; import { ThemeIcon } from '../../../../../../base/common/themables.js'; -import { IPromptPath, IPromptsService } from '../../../common/promptSyntax/service/types.js'; +import { IPromptPath, IPromptsService } from '../../../common/promptSyntax/service/promptsService.js'; import { dirname, extUri, joinPath } from '../../../../../../base/common/resources.js'; import { DisposableStore } from '../../../../../../base/common/lifecycle.js'; import { IFileService } from '../../../../../../platform/files/common/files.js'; @@ -16,8 +16,8 @@ import { ILabelService } from '../../../../../../platform/label/common/label.js' import { IOpenerService } from '../../../../../../platform/opener/common/opener.js'; import { IDialogService } from '../../../../../../platform/dialogs/common/dialogs.js'; import { ICommandService } from '../../../../../../platform/commands/common/commands.js'; -import { getCleanPromptName, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { INSTRUCTIONS_DOCUMENTATION_URL, MODE_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../../../common/promptSyntax/constants.js'; +import { getCleanPromptName } from '../../../common/promptSyntax/config/promptFileLocations.js'; +import { PromptsType, INSTRUCTIONS_DOCUMENTATION_URL, MODE_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../../../common/promptSyntax/promptTypes.js'; import { NEW_PROMPT_COMMAND_ID, NEW_INSTRUCTIONS_COMMAND_ID, NEW_MODE_COMMAND_ID } from '../newPromptFileActions.js'; import { IKeyMods, IQuickInputButton, IQuickInputService, IQuickPick, IQuickPickItem, IQuickPickItemButtonEvent } from '../../../../../../platform/quickinput/common/quickInput.js'; import { askForPromptFileName } from './askForPromptName.js'; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts index 9a0e2cb461c..8f359d3c4c5 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts @@ -15,9 +15,9 @@ import { CommandsRegistry } from '../../../../../platform/commands/common/comman import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { showToolsPicker } from '../actions/chatToolPicker.js'; import { ILanguageModelToolsService, IToolData, ToolSet } from '../../common/languageModelToolsService.js'; -import { ALL_PROMPTS_LANGUAGE_SELECTOR } from '../../common/promptSyntax/constants.js'; +import { ALL_PROMPTS_LANGUAGE_SELECTOR } from '../../common/promptSyntax/promptTypes.js'; import { PromptToolsMetadata } from '../../common/promptSyntax/parsers/promptHeader/metadata/tools.js'; -import { IPromptsService } from '../../common/promptSyntax/service/types.js'; +import { IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; import { registerEditorFeature } from '../../../../../editor/common/editorFeatures.js'; class PromptToolsCodeLensProvider extends Disposable implements CodeLensProvider { diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.ts index d58eddbcd61..b64d3c2a9d9 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.ts @@ -13,11 +13,11 @@ import { assertDefined } from '../../../../../base/common/types.js'; import { ThemeIcon } from '../../../../../base/common/themables.js'; import { ResourceContextKey } from '../../../../common/contextkeys.js'; import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js'; -import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/constants.js'; +import { PromptsType, PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/promptTypes.js'; import { ILocalizedString, localize, localize2 } from '../../../../../nls.js'; import { UILabelProvider } from '../../../../../base/common/keybindingLabels.js'; import { ICommandAction } from '../../../../../platform/action/common/action.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { PromptFilePickers } from './pickers/promptFilePickers.js'; import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; @@ -28,9 +28,8 @@ import { ICodeEditorService } from '../../../../../editor/browser/services/codeE import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; -import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; -import { getPromptCommandName } from '../../common/promptSyntax/service/promptsService.js'; +import { getPromptCommandName } from '../../common/promptSyntax/service/promptsServiceImpl.js'; /** * Condition for the `Run Current Prompt` action. diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts index 1a95f50de6c..39c7c0c21b6 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts @@ -10,13 +10,13 @@ import { ICommandService } from '../../../../../platform/commands/common/command import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { ILogService } from '../../../../../platform/log/common/log.js'; -import { PromptsConfig } from '../../../../../platform/prompts/common/config.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IEditorPane } from '../../../../common/editor.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { chatSubcommandLeader, IParsedChatRequest } from '../../common/chatParserTypes.js'; import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; -import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/constants.js'; +import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/promptTypes.js'; import { CHAT_CATEGORY } from '../actions/chatActions.js'; import { IChatWidget } from '../chat.js'; diff --git a/src/vs/workbench/contrib/chat/common/chatModes.ts b/src/vs/workbench/contrib/chat/common/chatModes.ts index 5ac1a617205..1d7812c5245 100644 --- a/src/vs/workbench/contrib/chat/common/chatModes.ts +++ b/src/vs/workbench/contrib/chat/common/chatModes.ts @@ -12,7 +12,7 @@ import { ILogService } from '../../../../platform/log/common/log.js'; import { IChatAgentService } from './chatAgents.js'; import { ChatContextKeys } from './chatContextKeys.js'; import { ChatMode, modeToString } from './constants.js'; -import { ICustomChatMode, IPromptsService } from './promptSyntax/service/types.js'; +import { ICustomChatMode, IPromptsService } from './promptSyntax/service/promptsService.js'; export const IChatModeService = createDecorator('chatModeService'); export interface IChatModeService { diff --git a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts index b13aa5c8a11..d53289147c7 100644 --- a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts @@ -13,7 +13,7 @@ import { IChatSlashData } from './chatSlashCommands.js'; import { IChatRequestProblemsVariable, IChatRequestVariableValue } from './chatVariables.js'; import { ChatAgentLocation } from './constants.js'; import { IToolData } from './languageModelToolsService.js'; -import { IChatPromptSlashCommand } from './promptSyntax/service/types.js'; +import { IChatPromptSlashCommand } from './promptSyntax/service/promptsService.js'; // These are in a separate file to avoid circular dependencies with the dependencies of the parser diff --git a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts index dec8164ba76..37856c73242 100644 --- a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts +++ b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts @@ -12,7 +12,7 @@ import { IChatSlashCommandService } from './chatSlashCommands.js'; import { IChatVariablesService, IDynamicVariable } from './chatVariables.js'; import { ChatAgentLocation, ChatMode } from './constants.js'; import { IToolData, ToolSet } from './languageModelToolsService.js'; -import { IPromptsService } from './promptSyntax/service/types.js'; +import { IPromptsService } from './promptSyntax/service/promptsService.js'; const agentReg = /^@([\w_\-\.]+)(?=(\s|$|\b))/i; // An @-agent const variableReg = /^#([\w_\-]+)(:\d+)?(?=(\s|$|\b))/i; // A #-variable with an optional numeric : arg (@response:2) diff --git a/src/vs/platform/prompts/common/config.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/config/config.ts similarity index 65% rename from src/vs/platform/prompts/common/config.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/config/config.ts index b5c8ad3494d..e1ee3ea8a2a 100644 --- a/src/vs/platform/prompts/common/config.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/config/config.ts @@ -3,13 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ContextKeyExpr } from '../../contextkey/common/contextkey.js'; -import type { IConfigurationService } from '../../configuration/common/configuration.js'; -import { CONFIG_KEY, PROMPT_DEFAULT_SOURCE_FOLDER, INSTRUCTIONS_LOCATIONS_CONFIG_KEY, PROMPT_LOCATIONS_CONFIG_KEY, INSTRUCTIONS_DEFAULT_SOURCE_FOLDER, PromptsType, getPromptFileDefaultLocation, MODE_LOCATIONS_CONFIG_KEY, getPromptFileLocationsConfigKey } from './prompts.js'; +import type { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; +import { ContextKeyExpr } from '../../../../../../platform/contextkey/common/contextkey.js'; +import { PromptsType } from '../promptTypes.js'; +import { INSTRUCTIONS_DEFAULT_SOURCE_FOLDER, PROMPT_DEFAULT_SOURCE_FOLDER, getPromptFileDefaultLocation } from './promptFileLocations.js'; /** * Configuration helper for the `reusable prompts` feature. - * @see {@link CONFIG_KEY}, {@link PROMPT_LOCATIONS_CONFIG_KEY}, {@link INSTRUCTIONS_LOCATIONS_CONFIG_KEY} or {@link MODE_LOCATIONS_CONFIG_KEY}. + * @see {@link PromptsConfig.KEY}, {@link PromptsConfig.PROMPT_LOCATIONS_KEY}, {@link PromptsConfig.INSTRUCTIONS_LOCATION_KEY} or {@link PromptsConfig.MODE_LOCATION_KEY}. * * ### Functions * @@ -28,36 +29,46 @@ import { CONFIG_KEY, PROMPT_DEFAULT_SOURCE_FOLDER, INSTRUCTIONS_LOCATIONS_CONFIG * - current root folder (if a single folder is open) */ export namespace PromptsConfig { - export const KEY = CONFIG_KEY; - export const PROMPT_LOCATIONS_KEY = PROMPT_LOCATIONS_CONFIG_KEY; - export const INSTRUCTIONS_LOCATION_KEY = INSTRUCTIONS_LOCATIONS_CONFIG_KEY; - export const MODE_LOCATION_KEY = MODE_LOCATIONS_CONFIG_KEY; + /** + * Configuration key for the `reusable prompts` feature + * (also known as `prompt files`, `prompt instructions`, etc.). + */ + export const KEY = 'chat.promptFiles'; + + /** + * Configuration key for the locations of reusable prompt files. + */ + export const PROMPT_LOCATIONS_KEY = 'chat.promptFilesLocations'; + + /** + * Configuration key for the locations of instructions files. + */ + export const INSTRUCTIONS_LOCATION_KEY = 'chat.instructionsFilesLocations'; + /** + * Configuration key for the locations of mode files. + */ + export const MODE_LOCATION_KEY = 'chat.modeFilesLocations'; /** * Checks if the feature is enabled. - * @see {@link CONFIG_KEY}. + * @see {@link PromptsConfig.KEY}. */ - export const enabled = ( - configService: IConfigurationService, - ): boolean => { - const enabledValue = configService.getValue(CONFIG_KEY); + export function enabled(configService: IConfigurationService): boolean { + const enabledValue = configService.getValue(PromptsConfig.KEY); return asBoolean(enabledValue) ?? false; - }; + } /** * Context key expression for the `reusable prompts` feature `enabled` status. */ - export const enabledCtx = ContextKeyExpr.equals(`config.${CONFIG_KEY}`, true); + export const enabledCtx = ContextKeyExpr.equals(`config.${PromptsConfig.KEY}`, true); /** * Get value of the `reusable prompt locations` configuration setting. * @see {@link PROMPT_LOCATIONS_CONFIG_KEY}, {@link INSTRUCTIONS_LOCATIONS_CONFIG_KEY}, {@link MODE_LOCATIONS_CONFIG_KEY}. */ - export const getLocationsValue = ( - configService: IConfigurationService, - type: PromptsType - ): Record | undefined => { + export function getLocationsValue(configService: IConfigurationService, type: PromptsType): Record | undefined { const key = getPromptFileLocationsConfigKey(type); const configValue = configService.getValue(key); @@ -85,16 +96,13 @@ export namespace PromptsConfig { } return undefined; - }; + } /** * Gets list of source folders for prompt files. * Defaults to {@link PROMPT_DEFAULT_SOURCE_FOLDER}, {@link INSTRUCTIONS_DEFAULT_SOURCE_FOLDER} or {@link MODE_DEFAULT_SOURCE_FOLDER}. */ - export const promptSourceFolders = ( - configService: IConfigurationService, - type: PromptsType - ): string[] => { + export function promptSourceFolders(configService: IConfigurationService, type: PromptsType): string[] { const value = getLocationsValue(configService, type); const defaultSourceFolder = getPromptFileDefaultLocation(type); @@ -122,7 +130,21 @@ export namespace PromptsConfig { // `undefined`, `null`, and `false` cases return []; - }; + } + +} + +export function getPromptFileLocationsConfigKey(type: PromptsType): string { + switch (type) { + case PromptsType.instructions: + return PromptsConfig.INSTRUCTIONS_LOCATION_KEY; + case PromptsType.prompt: + return PromptsConfig.PROMPT_LOCATIONS_KEY; + case PromptsType.mode: + return PromptsConfig.MODE_LOCATION_KEY; + default: + throw new Error('Unknown prompt type'); + } } /** @@ -133,7 +155,7 @@ export namespace PromptsConfig { * be clearly mapped to a boolean (e.g., `"true"`, `"TRUE"`, `"FaLSe"`, etc.), * `undefined` for rest of the values */ -export const asBoolean = (value: unknown): boolean | undefined => { +export function asBoolean(value: unknown): boolean | undefined { if (typeof value === 'boolean') { return value; } @@ -152,4 +174,4 @@ export const asBoolean = (value: unknown): boolean | undefined => { } return undefined; -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/configMigration.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/config/configMigration.ts similarity index 83% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/configMigration.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/config/configMigration.ts index f52d6269f8e..38d47d6dd1c 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/configMigration.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/config/configMigration.ts @@ -5,10 +5,9 @@ import { assert } from '../../../../../../base/common/assert.js'; import { ILogService } from '../../../../../../platform/log/common/log.js'; -import { asBoolean } from '../../../../../../platform/prompts/common/config.js'; +import { asBoolean, PromptsConfig } from './config.js'; import { IWorkbenchContribution } from '../../../../../common/contributions.js'; import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; -import { CONFIG_KEY, PROMPT_LOCATIONS_CONFIG_KEY } from '../../../../../../platform/prompts/common/prompts.js'; /** * Contribution that migrates the old config setting value to a new one. @@ -31,7 +30,7 @@ export class ConfigMigration implements IWorkbenchContribution { * The main function that implements the migration logic. */ private async migrateConfig(): Promise { - const value = await this.configService.getValue(CONFIG_KEY); + const value = await this.configService.getValue(PromptsConfig.KEY); // if setting is not set, nothing to do if ((value === undefined) || (value === null)) { @@ -62,8 +61,8 @@ export class ConfigMigration implements IWorkbenchContribution { locationsValue[trimmedValue] = true; } - await this.configService.updateValue(CONFIG_KEY, true); - await this.configService.updateValue(PROMPT_LOCATIONS_CONFIG_KEY, locationsValue); + await this.configService.updateValue(PromptsConfig.KEY, true); + await this.configService.updateValue(PromptsConfig.PROMPT_LOCATIONS_KEY, locationsValue); return; } @@ -95,8 +94,8 @@ export class ConfigMigration implements IWorkbenchContribution { locationsValue[trimmedValue] = enabled; } - await this.configService.updateValue(CONFIG_KEY, true); - await this.configService.updateValue(PROMPT_LOCATIONS_CONFIG_KEY, locationsValue); + await this.configService.updateValue(PromptsConfig.KEY, true); + await this.configService.updateValue(PromptsConfig.PROMPT_LOCATIONS_KEY, locationsValue); return; } @@ -112,8 +111,8 @@ export class ConfigMigration implements IWorkbenchContribution { `String value must not be a boolean, got '${value}'.`, ); - await this.configService.updateValue(CONFIG_KEY, true); - await this.configService.updateValue(PROMPT_LOCATIONS_CONFIG_KEY, { [value]: true }); + await this.configService.updateValue(PromptsConfig.KEY, true); + await this.configService.updateValue(PromptsConfig.PROMPT_LOCATIONS_KEY, { [value]: true }); return; } } diff --git a/src/vs/platform/prompts/common/prompts.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/config/promptFileLocations.ts similarity index 66% rename from src/vs/platform/prompts/common/prompts.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/config/promptFileLocations.ts index 620a2109b7b..fbdf2df20aa 100644 --- a/src/vs/platform/prompts/common/prompts.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/config/promptFileLocations.ts @@ -3,21 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from '../../../base/common/uri.js'; -import { basename } from '../../../base/common/path.js'; - -/** - * What the prompt is used for. - */ -export enum PromptsType { - instructions = 'instructions', - prompt = 'prompt', - mode = 'mode' -} - -export function isValidPromptType(type: string): type is PromptsType { - return Object.values(PromptsType).includes(type as PromptsType); -} +import { URI } from '../../../../../../base/common/uri.js'; +import { basename } from '../../../../../../base/common/path.js'; +import { PromptsType } from '../promptTypes.js'; /** * File extension for the reusable prompt files. @@ -39,26 +27,6 @@ export const MODE_FILE_EXTENSION = '.chatmode.md'; */ export const COPILOT_CUSTOM_INSTRUCTIONS_FILENAME = 'copilot-instructions.md'; -/** - * Configuration key for the `reusable prompts` feature - * (also known as `prompt files`, `prompt instructions`, etc.). - */ -export const CONFIG_KEY: string = 'chat.promptFiles'; - -/** - * Configuration key for the locations of reusable prompt files. - */ -export const PROMPT_LOCATIONS_CONFIG_KEY: string = 'chat.promptFilesLocations'; - -/** - * Configuration key for the locations of instructions files. - */ -export const INSTRUCTIONS_LOCATIONS_CONFIG_KEY: string = 'chat.instructionsFilesLocations'; - -/** - * Configuration key for the locations of mode files. - */ -export const MODE_LOCATIONS_CONFIG_KEY: string = 'chat.modeFilesLocations'; /** * Default reusable prompt files source folder. @@ -129,35 +97,11 @@ export function getPromptFileDefaultLocation(type: PromptsType): string { } } -export function getPromptFileLocationsConfigKey(type: PromptsType): string { - switch (type) { - case PromptsType.instructions: - return INSTRUCTIONS_LOCATIONS_CONFIG_KEY; - case PromptsType.prompt: - return PROMPT_LOCATIONS_CONFIG_KEY; - case PromptsType.mode: - return MODE_LOCATIONS_CONFIG_KEY; - default: - throw new Error('Unknown prompt type'); - } -} - - -/** - * Check whether provided URI belongs to an `untitled` document. - */ -export const isUntitled = ( - fileUri: URI, -): boolean => { - return fileUri.scheme === 'untitled'; -}; /** * Gets clean prompt name without file extension. */ -export const getCleanPromptName = ( - fileUri: URI, -): string => { +export function getCleanPromptName(fileUri: URI): string { const fileName = basename(fileUri.path); const extensions = [ @@ -181,4 +125,4 @@ export const getCleanPromptName = ( // to account for that, we return the full file name including the file // extension for all other cases return basename(fileUri.path); -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/filePromptContentsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/filePromptContentsProvider.ts index 9b8774efccb..831fd7cbe49 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/filePromptContentsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/filePromptContentsProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { PROMPT_LANGUAGE_ID } from '../constants.js'; +import { PROMPT_LANGUAGE_ID } from '../promptTypes.js'; import { IPromptContentsProvider } from './types.js'; import { URI } from '../../../../../../base/common/uri.js'; import { assert } from '../../../../../../base/common/assert.js'; @@ -12,7 +12,7 @@ import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js' import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { IModelService } from '../../../../../../editor/common/services/model.js'; import { ILanguageService } from '../../../../../../editor/common/languages/language.js'; -import { isPromptOrInstructionsFile } from '../../../../../../platform/prompts/common/prompts.js'; +import { isPromptOrInstructionsFile } from '../config/promptFileLocations.js'; import { IPromptContentsProviderOptions, PromptContentsProviderBase } from './promptContentsProviderBase.js'; import { OpenFailed, NotPromptFile, ResolveError, FolderReference } from '../../promptFileReferenceErrors.js'; import { FileChangesEvent, FileChangeType, IFileService } from '../../../../../../platform/files/common/files.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts index b34815a0e7d..7d301ad5545 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts @@ -3,18 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptContentsProvider } from './types.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import { Emitter } from '../../../../../../base/common/event.js'; import { assert } from '../../../../../../base/common/assert.js'; -import { CancellationError } from '../../../../../../base/common/errors.js'; import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; -import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { ObservableDisposable } from '../utils/observableDisposable.js'; -import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../constants.js'; -import { FailedToResolveContentsStream, ResolveError } from '../../promptFileReferenceErrors.js'; import { cancelPreviousCalls } from '../../../../../../base/common/decorators/cancelPreviousCalls.js'; +import { CancellationError } from '../../../../../../base/common/errors.js'; +import { Emitter } from '../../../../../../base/common/event.js'; +import { URI } from '../../../../../../base/common/uri.js'; +import { FailedToResolveContentsStream, ResolveError } from '../../promptFileReferenceErrors.js'; +import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID, PromptsType } from '../promptTypes.js'; +import { ObservableDisposable } from '../utils/observableDisposable.js'; +import { IPromptContentsProvider } from './types.js'; /** * Options of the {@link PromptContentsProviderBase} class. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts index fcc277f99ea..cef4a267200 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts @@ -3,17 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptContentsProvider } from './types.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import { ITextModel } from '../../../../../../editor/common/model.js'; -import { FilePromptContentProvider } from './filePromptContentsProvider.js'; -import { TextModel } from '../../../../../../editor/common/model/textModel.js'; import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; +import { URI } from '../../../../../../base/common/uri.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { TextModel } from '../../../../../../editor/common/model/textModel.js'; import { IModelContentChangedEvent } from '../../../../../../editor/common/textModelEvents.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { IPromptContentsProviderOptions, PromptContentsProviderBase } from './promptContentsProviderBase.js'; import { objectStreamFromTextModel } from '../codecs/base/utils/objectStreamFromTextModel.js'; +import { FilePromptContentProvider } from './filePromptContentsProvider.js'; +import { IPromptContentsProviderOptions, PromptContentsProviderBase } from './promptContentsProviderBase.js'; +import { IPromptContentsProvider } from './types.js'; /** * Prompt contents provider for a {@link ITextModel} instance. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts index a99407f610e..be572215a4f 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts @@ -8,7 +8,7 @@ import { Event } from '../../../../../../base/common/event.js'; import { ResolveError } from '../../promptFileReferenceErrors.js'; import { IDisposable } from '../../../../../../base/common/lifecycle.js'; import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js'; -import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../promptTypes.js'; /** * Interface for a prompt contents provider. Prompt contents providers are diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/index.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/index.ts deleted file mode 100644 index 538fb25ab05..00000000000 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ConfigMigration } from './configMigration.js'; -import { LANGUAGE_FEATURE_CONTRIBUTIONS } from './languageFeatures/index.js'; -import { Registry } from '../../../../../../platform/registry/common/platform.js'; -import { LifecyclePhase } from '../../../../../services/lifecycle/common/lifecycle.js'; -import { IWorkbenchContributionsRegistry, Extensions, IWorkbenchContribution } from '../../../../../common/contributions.js'; - -/** - * Function that registers all prompt-file related contributions. - */ -export const registerPromptFileContributions = (): void => { - registerContributions(LANGUAGE_FEATURE_CONTRIBUTIONS); - registerContribution(ConfigMigration); -}; - -/** - * Type for a generic workbench contribution. - */ -export type TContribution = new (...args: any[]) => IWorkbenchContribution; - -/** - * Register a specific workbench contribution. - */ -const registerContribution = (contribution: TContribution): void => { - Registry.as(Extensions.Workbench) - .registerWorkbenchContribution(contribution, LifecyclePhase.Eventually); -}; - -/** - * Register a specific workbench contribution. - */ -const registerContributions = (contributions: readonly TContribution[]): void => { - contributions - .forEach(registerContribution); -}; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/index.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/index.ts deleted file mode 100644 index 05481cc7058..00000000000 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TContribution } from '../index.js'; -import { PromptLinkProvider } from './providers/promptLinkProvider.js'; -import { isWindows } from '../../../../../../../base/common/platform.js'; -import { PromptPathAutocompletion } from './providers/promptPathAutocompletion.js'; -import { PromptLinkDiagnosticsInstanceManager } from './providers/promptLinkDiagnosticsProvider.js'; -import { PromptHeaderDiagnosticsInstanceManager } from './providers/promptHeaderDiagnosticsProvider.js'; - -/** - * Base list of language feature contributions. - */ -const CONTRIBUTIONS: TContribution[] = [ - PromptLinkProvider, - PromptLinkDiagnosticsInstanceManager, - PromptHeaderDiagnosticsInstanceManager, - /** - * PromptDecorationsProviderInstanceManager is currently disabled because the only currently - * available decoration is the Front Matter header, which we decided to disable for now. - * Add it back when more decorations are needed. - */ - // PromptDecorationsProviderInstanceManager, -]; - -/** - * We restrict this provider to `Unix` machines for now because of - * the filesystem paths differences on `Windows` operating system. - * - * Notes on `Windows` support: - * - we add the `./` for the first path component, which may not work on `Windows` - * - the first path component of the absolute paths must be a drive letter - */ -if (isWindows === false) { - CONTRIBUTIONS.push(PromptPathAutocompletion); -} - -/** - * List of language feature contributions for the prompt files. - */ -export const LANGUAGE_FEATURE_CONTRIBUTIONS = Object.freeze(CONTRIBUTIONS); diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/index.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/index.ts deleted file mode 100644 index 3980294fc1a..00000000000 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ColorIdentifier } from '../../../../../../../../../../../platform/theme/common/colorUtils.js'; - -/** - * Convert a registered color to a CSS variable string. - */ -export const asCssVariable = (color: ColorIdentifier): string => { - return `var(--vscode-${color.replaceAll('.', '-')})`; -}; - -export type * from './types.js'; -export { DecorationBase, type TDecorationClass } from './decorationBase.js'; -export { ReactiveDecorationBase, type TChangedDecorator } from './reactiveDecorationBase.js'; - diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterDecoration.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/frontMatterDecoration.ts similarity index 84% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterDecoration.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/frontMatterDecoration.ts index 3ccfec56ba0..d07720eff5b 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterDecoration.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/frontMatterDecoration.ts @@ -3,15 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Position } from '../../../../../../../../editor/common/core/position.js'; +import { localize } from '../../../../../../../../nls.js'; +import { contrastBorder, editorBackground } from '../../../../../../../../platform/theme/common/colorRegistry.js'; +import { asCssVariable, ColorIdentifier, darken, registerColor } from '../../../../../../../../platform/theme/common/colorUtils.js'; +import { BaseToken } from '../../../codecs/base/baseToken.js'; +import { FrontMatterHeader } from '../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; import { CssClassModifiers } from '../types.js'; -import { localize } from '../../../../../../../../../../nls.js'; import { FrontMatterMarkerDecoration } from './frontMatterMarkerDecoration.js'; -import { Position } from '../../../../../../../../../../editor/common/core/position.js'; -import { BaseToken } from '../../../../../codecs/base/baseToken.js'; -import { contrastBorder, editorBackground } from '../../../../../../../../../../platform/theme/common/colorRegistry.js'; -import { ColorIdentifier, darken, registerColor } from '../../../../../../../../../../platform/theme/common/colorUtils.js'; -import { TAddAccessor, TDecorationStyles, ReactiveDecorationBase, asCssVariable, IReactiveDecorationClassNames } from './utils/index.js'; -import { FrontMatterHeader } from '../../../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { ReactiveDecorationBase } from './utils/reactiveDecorationBase.js'; +import { IReactiveDecorationClassNames, TAddAccessor, TDecorationStyles } from './utils/types.js'; /** * Decoration CSS class names. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterMarkerDecoration.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/frontMatterMarkerDecoration.ts similarity index 85% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterMarkerDecoration.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/frontMatterMarkerDecoration.ts index bde8c4bbafd..2a4a174c9f4 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/frontMatterMarkerDecoration.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/frontMatterMarkerDecoration.ts @@ -4,8 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { CssClassModifiers } from '../types.js'; -import { TDecorationStyles, ReactiveDecorationBase, IReactiveDecorationClassNames } from './utils/index.js'; -import { FrontMatterMarker } from '../../../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterMarker.js'; +import { TDecorationStyles, IReactiveDecorationClassNames } from './utils/types.js'; +import { FrontMatterMarker } from '../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterMarker.js'; +import { ReactiveDecorationBase } from './utils/reactiveDecorationBase.js'; /** * Decoration CSS class names. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/decorationBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/decorationBase.ts similarity index 89% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/decorationBase.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/decorationBase.ts index 6f375c8cba4..8f28ec33247 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/decorationBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/decorationBase.ts @@ -3,12 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Range } from '../../../../../../../../../../../editor/common/core/range.js'; -import { IMarkdownString } from '../../../../../../../../../../../base/common/htmlContent.js'; -import { BaseToken } from '../../../../../../codecs/base/baseToken.js'; -import { TrackedRangeStickiness } from '../../../../../../../../../../../editor/common/model.js'; +import { Range } from '../../../../../../../../../editor/common/core/range.js'; +import { IMarkdownString } from '../../../../../../../../../base/common/htmlContent.js'; +import { BaseToken } from '../../../../codecs/base/baseToken.js'; +import { TrackedRangeStickiness } from '../../../../../../../../../editor/common/model.js'; import type { TAddAccessor, TChangeAccessor, TDecorationStyles, TRemoveAccessor } from './types.js'; -import { ModelDecorationOptions } from '../../../../../../../../../../../editor/common/model/textModel.js'; +import { ModelDecorationOptions } from '../../../../../../../../../editor/common/model/textModel.js'; /** * Base class for all editor decorations. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/reactiveDecorationBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/reactiveDecorationBase.ts similarity index 96% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/reactiveDecorationBase.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/reactiveDecorationBase.ts index e27e80a46a3..42533aea5fe 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/reactiveDecorationBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/reactiveDecorationBase.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { DecorationBase } from './decorationBase.js'; -import { Position } from '../../../../../../../../../../../editor/common/core/position.js'; -import { BaseToken } from '../../../../../../codecs/base/baseToken.js'; +import { Position } from '../../../../../../../../../editor/common/core/position.js'; +import { BaseToken } from '../../../../codecs/base/baseToken.js'; import type { IReactiveDecorationClassNames, TAddAccessor, TChangeAccessor, TRemoveAccessor } from './types.js'; /** diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/types.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/types.ts similarity index 97% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/types.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/types.ts index 0f5aaee01a2..1ca7e270d3f 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/decorations/utils/types.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/decorations/utils/types.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IModelDecorationsChangeAccessor } from '../../../../../../../../../../../editor/common/model.js'; +import { IModelDecorationsChangeAccessor } from '../../../../../../../../../editor/common/model.js'; /** * CSS class names of a `reactive` decoration. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/promptDecorationsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/promptDecorationsProvider.ts similarity index 87% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/promptDecorationsProvider.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/promptDecorationsProvider.ts index e8e55dc534b..ce87f6accb8 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/promptDecorationsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/promptDecorationsProvider.ts @@ -3,17 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptsService } from '../../../../service/types.js'; +import { IPromptsService } from '../../service/promptsService.js'; import { ProviderInstanceBase } from '../providerInstanceBase.js'; -import { ITextModel } from '../../../../../../../../../editor/common/model.js'; +import { ITextModel } from '../../../../../../../editor/common/model.js'; import { FrontMatterDecoration } from './decorations/frontMatterDecoration.js'; -import { toDisposable } from '../../../../../../../../../base/common/lifecycle.js'; -import { Position } from '../../../../../../../../../editor/common/core/position.js'; -import { BaseToken } from '../../../../codecs/base/baseToken.js'; +import { toDisposable } from '../../../../../../../base/common/lifecycle.js'; +import { Position } from '../../../../../../../editor/common/core/position.js'; +import { BaseToken } from '../../codecs/base/baseToken.js'; import { ProviderInstanceManagerBase, TProviderClass } from '../providerInstanceManagerBase.js'; -import { registerThemingParticipant } from '../../../../../../../../../platform/theme/common/themeService.js'; -import { DecorationBase, ReactiveDecorationBase, type TDecorationClass, type TChangedDecorator } from './decorations/utils/index.js'; -import { FrontMatterHeader } from '../../../../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { registerThemingParticipant } from '../../../../../../../platform/theme/common/themeService.js'; +import { FrontMatterHeader } from '../../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; +import { ReactiveDecorationBase, TChangedDecorator } from './decorations/utils/reactiveDecorationBase.js'; +import { DecorationBase, TDecorationClass } from './decorations/utils/decorationBase.js'; /** * Prompt tokens that are decorated by this provider. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/types.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/types.ts similarity index 85% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/types.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/types.ts index 366a0c33150..fb3ef81b122 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/decorationsProvider/types.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/decorationsProvider/types.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IRange } from '../../../../../../../../../editor/common/core/range.js'; -import { ModelDecorationOptions } from '../../../../../../../../../editor/common/model/textModel.js'; +import { IRange } from '../../../../../../../editor/common/core/range.js'; +import { ModelDecorationOptions } from '../../../../../../../editor/common/model/textModel.js'; /** * Decoration object. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptHeaderDiagnosticsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderDiagnosticsProvider.ts similarity index 88% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptHeaderDiagnosticsProvider.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderDiagnosticsProvider.ts index 5500f832d49..6743bf70277 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptHeaderDiagnosticsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderDiagnosticsProvider.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptsService } from '../../../service/types.js'; +import { IPromptsService } from '../service/promptsService.js'; import { ProviderInstanceBase } from './providerInstanceBase.js'; -import { ITextModel } from '../../../../../../../../editor/common/model.js'; -import { assertNever } from '../../../../../../../../base/common/assert.js'; -import { CancellationToken } from '../../../../../../../../base/common/cancellation.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { assertNever } from '../../../../../../base/common/assert.js'; +import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { ProviderInstanceManagerBase, TProviderClass } from './providerInstanceManagerBase.js'; -import { TDiagnostic, PromptMetadataError, PromptMetadataWarning } from '../../../parsers/promptHeader/diagnostics.js'; -import { IMarkerData, IMarkerService, MarkerSeverity } from '../../../../../../../../platform/markers/common/markers.js'; +import { TDiagnostic, PromptMetadataError, PromptMetadataWarning } from '../parsers/promptHeader/diagnostics.js'; +import { IMarkerData, IMarkerService, MarkerSeverity } from '../../../../../../platform/markers/common/markers.js'; /** * Unique ID of the markers provider class. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptLinkDiagnosticsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkDiagnosticsProvider.ts similarity index 88% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptLinkDiagnosticsProvider.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkDiagnosticsProvider.ts index 1d43958165f..2d8f8902aae 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptLinkDiagnosticsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkDiagnosticsProvider.ts @@ -3,15 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptsService } from '../../../service/types.js'; -import { IPromptFileReference } from '../../../parsers/types.js'; +import { IPromptsService } from '../service/promptsService.js'; +import { IPromptFileReference } from '../parsers/types.js'; import { ProviderInstanceBase } from './providerInstanceBase.js'; -import { assert } from '../../../../../../../../base/common/assert.js'; -import { NotPromptFile } from '../../../../promptFileReferenceErrors.js'; -import { ITextModel } from '../../../../../../../../editor/common/model.js'; -import { assertDefined } from '../../../../../../../../base/common/types.js'; +import { assert } from '../../../../../../base/common/assert.js'; +import { NotPromptFile } from '../../promptFileReferenceErrors.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { assertDefined } from '../../../../../../base/common/types.js'; import { ProviderInstanceManagerBase, TProviderClass } from './providerInstanceManagerBase.js'; -import { IMarkerData, IMarkerService, MarkerSeverity } from '../../../../../../../../platform/markers/common/markers.js'; +import { IMarkerData, IMarkerService, MarkerSeverity } from '../../../../../../platform/markers/common/markers.js'; /** * Unique ID of the markers provider class. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptLinkProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkProvider.ts similarity index 63% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptLinkProvider.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkProvider.ts index c71d5fa387d..275682fdc8b 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptLinkProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkProvider.ts @@ -3,29 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptsService } from '../../../service/types.js'; -import { assert } from '../../../../../../../../base/common/assert.js'; -import { ITextModel } from '../../../../../../../../editor/common/model.js'; -import { assertDefined } from '../../../../../../../../base/common/types.js'; -import { Disposable } from '../../../../../../../../base/common/lifecycle.js'; -import { CancellationError } from '../../../../../../../../base/common/errors.js'; -import { ALL_PROMPTS_LANGUAGE_SELECTOR } from '../../../constants.js'; -import { CancellationToken } from '../../../../../../../../base/common/cancellation.js'; -import { FolderReference, NotPromptFile } from '../../../../promptFileReferenceErrors.js'; -import { ILink, ILinksList, LinkProvider } from '../../../../../../../../editor/common/languages.js'; -import { ILanguageFeaturesService } from '../../../../../../../../editor/common/services/languageFeatures.js'; +import { IPromptsService } from '../service/promptsService.js'; +import { assert } from '../../../../../../base/common/assert.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { assertDefined } from '../../../../../../base/common/types.js'; +import { CancellationError } from '../../../../../../base/common/errors.js'; +import { CancellationToken } from '../../../../../../base/common/cancellation.js'; +import { FolderReference, NotPromptFile } from '../../promptFileReferenceErrors.js'; +import { ILink, ILinksList, LinkProvider } from '../../../../../../editor/common/languages.js'; /** * Provides link references for prompt files. */ -export class PromptLinkProvider extends Disposable implements LinkProvider { +export class PromptLinkProvider implements LinkProvider { constructor( @IPromptsService private readonly promptsService: IPromptsService, - @ILanguageFeaturesService private readonly languageService: ILanguageFeaturesService, ) { - super(); - - this._register(this.languageService.linkProvider.register(ALL_PROMPTS_LANGUAGE_SELECTOR, this)); } /** diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptPathAutocompletion.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts similarity index 89% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptPathAutocompletion.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts index a9849e899d9..4a7f7c4be51 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/promptPathAutocompletion.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts @@ -14,21 +14,21 @@ * - add `Windows` support */ -import { IPromptsService } from '../../../service/types.js'; -import { URI } from '../../../../../../../../base/common/uri.js'; -import { isOneOf } from '../../../../../../../../base/common/types.js'; -import { extUri } from '../../../../../../../../base/common/resources.js'; -import { ITextModel } from '../../../../../../../../editor/common/model.js'; -import { Disposable } from '../../../../../../../../base/common/lifecycle.js'; -import { CancellationError } from '../../../../../../../../base/common/errors.js'; -import { ALL_PROMPTS_LANGUAGE_SELECTOR } from '../../../constants.js'; -import { Position } from '../../../../../../../../editor/common/core/position.js'; -import { IPromptFileReference, TPromptReference } from '../../../parsers/types.js'; -import { assert, assertNever } from '../../../../../../../../base/common/assert.js'; -import { IFileService } from '../../../../../../../../platform/files/common/files.js'; -import { CancellationToken } from '../../../../../../../../base/common/cancellation.js'; -import { ILanguageFeaturesService } from '../../../../../../../../editor/common/services/languageFeatures.js'; -import { CompletionContext, CompletionItem, CompletionItemKind, CompletionItemProvider, CompletionList } from '../../../../../../../../editor/common/languages.js'; +import { IPromptsService } from '../service/promptsService.js'; +import { URI } from '../../../../../../base/common/uri.js'; +import { isOneOf } from '../../../../../../base/common/types.js'; +import { extUri } from '../../../../../../base/common/resources.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { CancellationError } from '../../../../../../base/common/errors.js'; +import { ALL_PROMPTS_LANGUAGE_SELECTOR } from '../promptTypes.js'; +import { Position } from '../../../../../../editor/common/core/position.js'; +import { IPromptFileReference, TPromptReference } from '../parsers/types.js'; +import { assert, assertNever } from '../../../../../../base/common/assert.js'; +import { IFileService } from '../../../../../../platform/files/common/files.js'; +import { CancellationToken } from '../../../../../../base/common/cancellation.js'; +import { ILanguageFeaturesService } from '../../../../../../editor/common/services/languageFeatures.js'; +import { CompletionContext, CompletionItem, CompletionItemKind, CompletionItemProvider, CompletionList } from '../../../../../../editor/common/languages.js'; /** * Type for a filesystem completion item - the one that has its {@link CompletionItem.kind kind} set diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceBase.ts similarity index 84% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceBase.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceBase.ts index 470744d7d82..8742fef0a7c 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceBase.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPromptsService, TSharedPrompt } from '../../../service/types.js'; -import { ITextModel } from '../../../../../../../../editor/common/model.js'; -import { ObservableDisposable } from '../../../utils/observableDisposable.js'; -import { CancellationToken, CancellationTokenSource } from '../../../../../../../../base/common/cancellation.js'; +import { IPromptsService, TSharedPrompt } from '../service/promptsService.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { ObservableDisposable } from '../utils/observableDisposable.js'; +import { CancellationToken, CancellationTokenSource } from '../../../../../../base/common/cancellation.js'; /** * Abstract base class for all reusable prompt file providers. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceManagerBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceManagerBase.ts similarity index 83% rename from src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceManagerBase.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceManagerBase.ts index 1ac1564defe..51a50e801d1 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contributions/languageFeatures/providers/providerInstanceManagerBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceManagerBase.ts @@ -4,18 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { ProviderInstanceBase } from './providerInstanceBase.js'; -import { assert } from '../../../../../../../../base/common/assert.js'; -import { ITextModel } from '../../../../../../../../editor/common/model.js'; -import { assertDefined } from '../../../../../../../../base/common/types.js'; -import { Disposable } from '../../../../../../../../base/common/lifecycle.js'; -import { ObjectCache } from '../../../utils/objectCache.js'; -import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../../../constants.js'; -import { IModelService } from '../../../../../../../../editor/common/services/model.js'; -import { PromptsConfig } from '../../../../../../../../platform/prompts/common/config.js'; -import { IEditorService } from '../../../../../../../services/editor/common/editorService.js'; -import { IDiffEditor, IEditor, IEditorModel } from '../../../../../../../../editor/common/editorCommon.js'; -import { IInstantiationService } from '../../../../../../../../platform/instantiation/common/instantiation.js'; -import { IConfigurationService } from '../../../../../../../../platform/configuration/common/configuration.js'; +import { assert } from '../../../../../../base/common/assert.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { assertDefined } from '../../../../../../base/common/types.js'; +import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { ObjectCache } from '../utils/objectCache.js'; +import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../promptTypes.js'; +import { IModelService } from '../../../../../../editor/common/services/model.js'; +import { PromptsConfig } from '../config/config.js'; +import { IEditorService } from '../../../../../services/editor/common/editorService.js'; +import { IDiffEditor, IEditor, IEditorModel } from '../../../../../../editor/common/editorCommon.js'; +import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; +import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; /** * Type for a text editor that is used for reusable prompt files. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts index 7562e42fae4..c5436bd295e 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts @@ -29,13 +29,13 @@ import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js' import { type IRange, Range } from '../../../../../../editor/common/core/range.js'; import { PromptHeader, type TPromptMetadata } from './promptHeader/promptHeader.js'; import { ObservableDisposable } from '../utils/observableDisposable.js'; -import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../constants.js'; +import { PromptsType, INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../promptTypes.js'; import { LinesDecoder } from '../codecs/base/linesCodec/linesDecoder.js'; import { IWorkspaceContextService } from '../../../../../../platform/workspace/common/workspace.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { MarkdownLink } from '../codecs/base/markdownCodec/tokens/markdownLink.js'; import { MarkdownToken } from '../codecs/base/markdownCodec/tokens/markdownToken.js'; -import { isPromptOrInstructionsFile, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { isPromptOrInstructionsFile } from '../config/promptFileLocations.js'; import { FrontMatterHeader } from '../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; import { OpenFailed, NotPromptFile, RecursiveReference, FolderReference, ResolveError } from '../../promptFileReferenceErrors.js'; import { type IPromptContentsProviderOptions, DEFAULT_OPTIONS as CONTENTS_PROVIDER_DEFAULT_OPTIONS } from '../contentProviders/promptContentsProviderBase.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts index 2d4137d8c43..1f13901f960 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/instructionsHeader.ts @@ -5,7 +5,7 @@ import { PromptApplyToMetadata } from './metadata/applyTo.js'; import { HeaderBase, IHeaderMetadata, type TDehydrated } from './headerBase.js'; -import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../../promptTypes.js'; import { FrontMatterRecord } from '../../codecs/base/frontMatterCodec/tokens/index.js'; /** diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts index e3fc03d9e3a..b4dfa24bdc0 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts @@ -5,7 +5,7 @@ import { PromptStringMetadata } from './base/string.js'; import { localize } from '../../../../../../../../nls.js'; -import { INSTRUCTIONS_LANGUAGE_ID } from '../../../constants.js'; +import { INSTRUCTIONS_LANGUAGE_ID } from '../../../promptTypes.js'; import { isEmptyPattern, parse, splitGlobAware } from '../../../../../../../../base/common/glob.js'; import { PromptMetadataDiagnostic, PromptMetadataError, PromptMetadataWarning } from '../diagnostics.js'; import { FrontMatterRecord, FrontMatterToken } from '../../../codecs/base/frontMatterCodec/tokens/index.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/modeHeader.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/modeHeader.ts index 6f87a5f1331..822d78f1b6c 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/modeHeader.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/modeHeader.ts @@ -5,7 +5,7 @@ import { type TDehydrated } from './headerBase.js'; import { PromptHeader, type IPromptMetadata } from './promptHeader.js'; -import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../../promptTypes.js'; /** * Metadata utility object for mode files. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts index 9181fd57b15..a6ed0357158 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/promptHeader.ts @@ -10,7 +10,7 @@ import { assert } from '../../../../../../../base/common/assert.js'; import { assertDefined } from '../../../../../../../base/common/types.js'; import { PromptToolsMetadata, PromptModeMetadata } from './metadata/index.js'; import { HeaderBase, IHeaderMetadata, type TDehydrated } from './headerBase.js'; -import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../../promptTypes.js'; import { FrontMatterRecord } from '../../codecs/base/frontMatterCodec/tokens/index.js'; /** diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts index c9f4407f01d..0d336cb5609 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts @@ -9,11 +9,11 @@ import { IPromptContentsProvider } from '../contentProviders/types.js'; import { ILogService } from '../../../../../../platform/log/common/log.js'; import { BasePromptParser, IPromptParserOptions } from './basePromptParser.js'; import { IModelService } from '../../../../../../editor/common/services/model.js'; -import { isUntitled } from '../../../../../../platform/prompts/common/prompts.js'; import { TextModelContentsProvider } from '../contentProviders/textModelContentsProvider.js'; import { FilePromptContentProvider } from '../contentProviders/filePromptContentsProvider.js'; import { IWorkspaceContextService } from '../../../../../../platform/workspace/common/workspace.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; +import { Schemas } from '../../../../../../base/common/network.js'; /** * Get prompt contents provider object based on the prompt type. @@ -25,7 +25,7 @@ const getContentsProvider = ( instaService: IInstantiationService, ): IPromptContentsProvider => { // use text model contents provider for `untitled` documents - if (isUntitled(uri)) { + if (uri.scheme === Schemas.untitled) { const model = modelService.getModel(uri); assertDefined( diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts new file mode 100644 index 00000000000..5521717d439 --- /dev/null +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ConfigMigration } from './config/configMigration.js'; +import { Registry } from '../../../../../platform/registry/common/platform.js'; +import { LifecyclePhase } from '../../../../services/lifecycle/common/lifecycle.js'; +import { IWorkbenchContributionsRegistry, Extensions, IWorkbenchContribution } from '../../../../common/contributions.js'; +import { PromptLinkProvider } from './languageProviders/promptLinkProvider.js'; +import { PromptLinkDiagnosticsInstanceManager } from './languageProviders/promptLinkDiagnosticsProvider.js'; +import { PromptHeaderDiagnosticsInstanceManager } from './languageProviders/promptHeaderDiagnosticsProvider.js'; +import { isWindows } from '../../../../../base/common/platform.js'; +import { PromptPathAutocompletion } from './languageProviders/promptPathAutocompletion.js'; + + +/** + * Function that registers all prompt-file related contributions. + */ +export const registerPromptFileContributions = (): void => { + + // all language constributions + + registerContribution(PromptLinkProvider); + registerContribution(PromptLinkDiagnosticsInstanceManager); + registerContribution(PromptHeaderDiagnosticsInstanceManager); + /** + * PromptDecorationsProviderInstanceManager is currently disabled because the only currently + * available decoration is the Front Matter header, which we decided to disable for now. + * Add it back when more decorations are needed. + */ + // registerContribution(PromptDecorationsProviderInstanceManager); , + + + /** + * We restrict this provider to `Unix` machines for now because of + * the filesystem paths differences on `Windows` operating system. + * + * Notes on `Windows` support: + * - we add the `./` for the first path component, which may not work on `Windows` + * - the first path component of the absolute paths must be a drive letter + */ + if (!isWindows) { + registerContribution(PromptPathAutocompletion); + } + + registerContribution(ConfigMigration); +}; + +/** + * Type for a generic workbench contribution. + */ +export type TContribution = new (...args: any[]) => IWorkbenchContribution; + +/** + * Register a specific workbench contribution. + */ +function registerContribution(contribution: TContribution): void { + Registry.as(Extensions.Workbench).registerWorkbenchContribution(contribution, LifecyclePhase.Eventually); +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/constants.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts similarity index 85% rename from src/vs/workbench/contrib/chat/common/promptSyntax/constants.ts rename to src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts index 5a5c5e8cbc6..3bfee9a5261 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/constants.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { LanguageSelector } from '../../../../../editor/common/languageSelector.js'; -import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; /** * Documentation link for the reusable prompts feature. @@ -47,4 +46,16 @@ export function getLanguageIdForPromptsType(type: PromptsType): string { default: throw new Error(`Unknown prompt type: ${type}`); } +}/** + * What the prompt is used for. + */ + +export enum PromptsType { + instructions = 'instructions', + prompt = 'prompt', + mode = 'mode' } +export function isValidPromptType(type: string): type is PromptsType { + return Object.values(PromptsType).includes(type as PromptsType); +} + diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 165bb3e9aa1..fe706645583 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -3,380 +3,222 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { flatten } from '../utils/treeUtils.js'; -import { localize } from '../../../../../../nls.js'; -import { PROMPT_LANGUAGE_ID } from '../constants.js'; -import { PromptParser } from '../parsers/promptParser.js'; -import { match, splitGlobAware } from '../../../../../../base/common/glob.js'; -import { type URI } from '../../../../../../base/common/uri.js'; -import { type IPromptFileReference } from '../parsers/types.js'; -import { assert } from '../../../../../../base/common/assert.js'; -import { basename } from '../../../../../../base/common/path.js'; -import { ResourceSet } from '../../../../../../base/common/map.js'; -import { PromptFilesLocator } from '../utils/promptFilesLocator.js'; -import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { TTree } from '../utils/treeUtils.js'; +import { ChatMode } from '../../constants.js'; +import { URI } from '../../../../../../base/common/uri.js'; import { Event } from '../../../../../../base/common/event.js'; -import { type ITextModel } from '../../../../../../editor/common/model.js'; -import { ObjectCache } from '../utils/objectCache.js'; -import { ILogService } from '../../../../../../platform/log/common/log.js'; +import { TMetadata } from '../parsers/promptHeader/headerBase.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { IDisposable } from '../../../../../../base/common/lifecycle.js'; import { TextModelPromptParser } from '../parsers/textModelPromptParser.js'; -import { ILabelService } from '../../../../../../platform/label/common/label.js'; -import { IModelService } from '../../../../../../editor/common/services/model.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; -import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { IUserDataProfileService } from '../../../../../services/userDataProfile/common/userDataProfile.js'; -import type { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptPath, IPromptsService, TPromptsStorage } from './types.js'; -import { getCleanPromptName, isValidPromptType, PROMPT_FILE_EXTENSION, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../promptTypes.js'; +import { createDecorator } from '../../../../../../platform/instantiation/common/instantiation.js'; /** * Provides prompt services. */ -export class PromptsService extends Disposable implements IPromptsService { - public declare readonly _serviceBrand: undefined; +export const IPromptsService = createDecorator('IPromptsService'); + +/** + * Where the prompt is stored. + */ +export type TPromptsStorage = 'local' | 'user'; + +/** + * Represents a prompt path with its type. + * This is used for both prompt files and prompt source folders. + */ +export interface IPromptPath { + /** + * URI of the prompt. + */ + readonly uri: URI; /** - * Cache of text model content prompt parsers. + * Storage of the prompt. */ - private readonly cache: ObjectCache; + readonly storage: TPromptsStorage; /** - * Prompt files locator utility. + * Type of the prompt (e.g. 'prompt' or 'instructions'). */ - private readonly fileLocator: PromptFilesLocator; + readonly type: PromptsType; +} +/** + * Type for a shared prompt parser instance returned by the {@link IPromptsService}. + * Because the parser is shared, we omit the `dispose` method from + * the original type so the caller cannot dispose it prematurely + */ +export type TSharedPrompt = Omit; + +/** + * Metadata node object in a hierarchical tree of prompt references. + */ +export interface IMetadata { + /** + * URI of a prompt file. + */ + readonly uri: URI; /** - * Lazily created event that is fired when the custom chat modes change. + * Metadata of the prompt file. */ - private onDidChangeCustomChatModesEvent: Event | undefined; - - constructor( - @ILogService public readonly logger: ILogService, - @ILabelService private readonly labelService: ILabelService, - @IModelService private readonly modelService: IModelService, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IUserDataProfileService private readonly userDataService: IUserDataProfileService, - ) { - super(); - - this.fileLocator = this._register(this.instantiationService.createInstance(PromptFilesLocator)); - - // the factory function below creates a new prompt parser object - // for the provided model, if no active non-disposed parser exists - this.cache = this._register( - new ObjectCache((model) => { - assert( - model.isDisposed() === false, - 'Text model must not be disposed.', - ); - - /** - * Note! When/if shared with "file" prompts, the `seenReferences` array below must be taken into account. - * Otherwise consumers will either see incorrect failing or incorrect successful results, based on their - * use case, timing of their calls to the {@link getSyntaxParserFor} function, and state of this service. - */ - const parser: TextModelPromptParser = instantiationService.createInstance( - TextModelPromptParser, - model, - { seenReferences: [] }, - ).start(); - - // this is a sanity check and the contract of the object cache, - // we must return a non-disposed object from this factory function - parser.assertNotDisposed( - 'Created prompt parser must not be disposed.', - ); - - return parser; - }) - ); - } + readonly metadata: TMetadata | null; /** - * Emitter for the custom chat modes change event. + * List of metadata for each valid child prompt reference. */ - public get onDidChangeCustomChatModes(): Event { - if (!this.onDidChangeCustomChatModesEvent) { - this.onDidChangeCustomChatModesEvent = this._register(this.fileLocator.createFilesUpdatedEvent(PromptsType.mode)).event; - } - return this.onDidChangeCustomChatModesEvent; - } + readonly children?: readonly TTree[]; +} +export interface ICustomChatMode { + /** + * URI of a custom chat mode file. + */ + readonly uri: URI; /** - * @throws {Error} if: - * - the provided model is disposed - * - newly created parser is disposed immediately on initialization. - * See factory function in the {@link constructor} for more info. + * Name of the custom chat mode. */ - public getSyntaxParserFor( + readonly name: string; + + /** + * Description of the mode + */ + readonly description?: string; + + /** + * Tools metadata in the prompt header. + */ + readonly tools?: readonly string[]; + + /** + * Contents of the custom chat mode file body. + */ + readonly body: string; +} + +/** + * Type of combined tools metadata for the case + * when the prompt is in the agent mode. + */ +interface ICombinedAgentToolsMetadata { + /** + * List of combined tools metadata for + * the entire tree of prompt references. + */ + readonly tools: readonly string[] | undefined; + + /** + * Resulting chat mode of a prompt, based on modes + * used in the entire tree of prompt references. + */ + readonly mode: ChatMode.Agent; +} + +/** + * Type of combined tools metadata for the case + * when the prompt is in non-agent mode. + */ +interface ICombinedNonAgentToolsMetadata { + /** + * List of combined tools metadata is empty + * when the prompt is in non-agent mode. + */ + readonly tools: undefined; + + /** + * Resulting chat mode of a prompt, based on modes + * used in the entire tree of prompt references. + */ + readonly mode?: ChatMode.Ask | ChatMode.Edit; +} + +/** + * General type of the combined tools metadata. + */ +export type TCombinedToolsMetadata = ICombinedAgentToolsMetadata | ICombinedNonAgentToolsMetadata; + +/** + * Provides prompt services. + */ +export interface IPromptsService extends IDisposable { + readonly _serviceBrand: undefined; + + /** + * Get a prompt syntax parser for the provided text model. + * See {@link TextModelPromptParser} for more info on the parser API. + */ + getSyntaxParserFor( model: ITextModel, - ): TextModelPromptParser & { isDisposed: false } { - assert( - model.isDisposed() === false, - 'Cannot create a prompt syntax parser for a disposed model.', - ); + ): TSharedPrompt & { isDisposed: false }; - return this.cache.get(model); - } + /** + * List all available prompt files. + */ + listPromptFiles(type: PromptsType, token: CancellationToken): Promise; - public async listPromptFiles(type: PromptsType, token: CancellationToken): Promise { - const prompts = await Promise.all([ - this.fileLocator.listFiles(type, 'user', token) - .then(withType('user', type)), - this.fileLocator.listFiles(type, 'local', token) - .then(withType('local', type)), - ]); + /** + * Get a list of prompt source folders based on the provided prompt type. + */ + getSourceFolders(type: PromptsType): readonly IPromptPath[]; - return prompts.flat(); - } + /** + * Returns a prompt command if the command name. + * Undefined is returned if the name does not look like a file name of a prompt file. + */ + asPromptSlashCommand(name: string): IChatPromptSlashCommand | undefined; - public getSourceFolders(type: PromptsType): readonly IPromptPath[] { - // sanity check to make sure we don't miss a new - // prompt type that could be added in the future - assert(isValidPromptType(type), `Unknown prompt type '${type}'.`); + /** + * Gets the prompt file for a slash command. + */ + resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise; - const result: IPromptPath[] = []; + /** + * Returns a prompt command if the command name is valid. + */ + findPromptSlashCommands(): Promise; - for (const uri of this.fileLocator.getConfigBasedSourceFolders(type)) { - result.push({ uri, storage: 'local', type }); - } - const userHome = this.userDataService.currentProfile.promptsHome; - result.push({ uri: userHome, storage: 'user', type }); + /** + * Find all instruction files which have a glob pattern in their + * 'applyTo' metadata record that match the provided list of files. + */ + findInstructionFilesFor( + fileUris: readonly URI[], + ): Promise; - return result; - } + /** + * Event that is triggered when the list of custom chat modes changes. + */ + readonly onDidChangeCustomChatModes: Event; - public asPromptSlashCommand(command: string): IChatPromptSlashCommand | undefined { - if (command.match(/^[\w_\-\.]+$/)) { - return { command, detail: localize('prompt.file.detail', 'Prompt file: {0}', command) }; - } - return undefined; - } + /** + * Finds all available custom chat modes + */ + getCustomChatModes(): Promise; - public async resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise { - const promptUri = await this.getPromptPath(data); - if (!promptUri) { - return undefined; - } - return await this.getMetadata(promptUri); - } + /** + * Gets the metadata for the given prompt file uri. + */ + getMetadata(promptFileUri: URI): Promise; - private async getPromptPath(data: IChatPromptSlashCommand): Promise { - if (data.promptPath) { - return data.promptPath.uri; - } - - const files = await this.listPromptFiles(PromptsType.prompt, CancellationToken.None); - const command = data.command; - const result = files.find(file => getPromptCommandName(file.uri.path) === command); - if (result) { - return result.uri; - } - const textModel = this.modelService.getModels().find(model => model.getLanguageId() === PROMPT_LANGUAGE_ID && getPromptCommandName(model.uri.path) === command); - if (textModel) { - return textModel.uri; - } - return undefined; - } - - public async findPromptSlashCommands(): Promise { - const promptFiles = await this.listPromptFiles(PromptsType.prompt, CancellationToken.None); - return promptFiles.map(promptPath => { - const command = getPromptCommandName(promptPath.uri.path); - return { - command, - detail: localize('prompt.file.detail', 'Prompt file: {0}', this.labelService.getUriLabel(promptPath.uri, { relative: true })), - promptPath - }; - }); - } - - public async getCustomChatModes(): Promise { - const modeFiles = (await this.listPromptFiles(PromptsType.mode, CancellationToken.None)) - .map(modeFile => modeFile.uri); - - const metadataList = await Promise.all( - modeFiles.map(async (uri): Promise => { - let parser: PromptParser | undefined; - try { - // Note! this can be (and should be) improved by using shared parser instances - // that the `getSyntaxParserFor` method provides for opened documents. - parser = this.instantiationService.createInstance( - PromptParser, - uri, - { allowNonPromptFiles: true }, - ).start(); - - await parser.settled(); - - const { metadata } = parser; - const tools = (metadata && ('tools' in metadata)) - ? metadata.tools - : undefined; - - const body = await parser.getBody(); - return { - uri: uri, - name: getCleanPromptName(uri), - description: metadata?.description, - tools, - body, - }; - } finally { - parser?.dispose(); - } - }), - ); - - return metadataList; - } - - public async findInstructionFilesFor( - files: readonly URI[], - ): Promise { - const instructionFiles = await this.listPromptFiles(PromptsType.instructions, CancellationToken.None); - if (instructionFiles.length === 0) { - return []; - } - - const instructions = await this.getAllMetadata( - instructionFiles.map(file => file.uri), - ); - - const foundFiles = new ResourceSet(); - for (const instruction of instructions.flatMap(flatten)) { - const { metadata, uri } = instruction; - - if (metadata?.promptType !== PromptsType.instructions) { - continue; - } - - const { applyTo } = metadata; - if (applyTo === undefined) { - continue; - } - - const patterns = splitGlobAware(applyTo, ','); - const patterMatches = (pattern: string) => { - pattern = pattern.trim(); - if (pattern.length === 0) { - // if glob pattern is empty, skip it - return false; - } - if (pattern === '**' || pattern === '**/*' || pattern === '*') { - // if glob pattern is one of the special wildcard values, - // add the instructions file event if no files are attached - return true; - } - if (!pattern.startsWith('/') && !pattern.startsWith('**/')) { - // support relative glob patterns, e.g. `src/**/*.js` - pattern = '**/' + pattern; - } - - // match each attached file with each glob pattern and - // add the instructions file if its rule matches the file - for (const file of files) { - // if the file is not a valid URI, skip it - if (match(pattern, file.path)) { - return true; - } - } - return false; - }; - - if (patterns.some(patterMatches)) { - foundFiles.add(uri); - } - } - return [...foundFiles]; - } - - public async getMetadata(promptFileUri: URI): Promise { - const metaDatas = await this.getAllMetadata([promptFileUri]); - return metaDatas[0]; - } - - public async getAllMetadata( + /** + * Get all metadata for entire prompt references tree + * that spans out of each of the provided files. + * + * In other words, the metadata tree is built starting from + * each of the provided files, therefore the result is a number + * of metadata trees, one for each file. + */ + getAllMetadata( promptUris: readonly URI[], - ): Promise { - const metadata = await Promise.all( - promptUris.map(async (uri) => { - let parser: PromptParser | undefined; - try { - parser = this.instantiationService.createInstance( - PromptParser, - uri, - { allowNonPromptFiles: true }, - ).start(); - - await parser.allSettled(); - - return collectMetadata(parser); - } finally { - parser?.dispose(); - } - }), - ); - - return metadata; - } + ): Promise; } -/** - * Collect all metadata from prompt file references - * into a single hierarchical tree structure. - */ -const collectMetadata = ( - reference: Pick, -): IMetadata => { - const childMetadata = []; - for (const child of reference.references) { - if (child.errorCondition !== undefined) { - continue; - } - - childMetadata.push(collectMetadata(child)); - } - - const children = (childMetadata.length > 0) - ? childMetadata - : undefined; - - return { - uri: reference.uri, - metadata: reference.metadata, - children, - }; -}; - -export function getPromptCommandName(path: string): string { - const name = basename(path, PROMPT_FILE_EXTENSION); - return name; +export interface IChatPromptSlashCommand { + readonly command: string; + readonly detail: string; + readonly promptPath?: IPromptPath; } - -/** - * Utility to add a provided prompt `storage` and - * `type` attributes to a prompt URI. - */ -const addType = ( - storage: TPromptsStorage, - type: PromptsType, -): (uri: URI) => IPromptPath => { - return (uri) => { - return { uri, storage, type }; - }; -}; - -/** - * Utility to add a provided prompt `type` to a list of prompt URIs. - */ -const withType = ( - storage: TPromptsStorage, - type: PromptsType, -): (uris: readonly URI[]) => (readonly IPromptPath[]) => { - return (uris) => { - return uris - .map(addType(storage, type)); - }; -}; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts new file mode 100644 index 00000000000..22fe4bb7daa --- /dev/null +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts @@ -0,0 +1,382 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { flatten } from '../utils/treeUtils.js'; +import { localize } from '../../../../../../nls.js'; +import { isValidPromptType, PROMPT_LANGUAGE_ID, PromptsType } from '../promptTypes.js'; +import { PromptParser } from '../parsers/promptParser.js'; +import { match, splitGlobAware } from '../../../../../../base/common/glob.js'; +import { type URI } from '../../../../../../base/common/uri.js'; +import { type IPromptFileReference } from '../parsers/types.js'; +import { assert } from '../../../../../../base/common/assert.js'; +import { basename } from '../../../../../../base/common/path.js'; +import { ResourceSet } from '../../../../../../base/common/map.js'; +import { PromptFilesLocator } from '../utils/promptFilesLocator.js'; +import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { Event } from '../../../../../../base/common/event.js'; +import { type ITextModel } from '../../../../../../editor/common/model.js'; +import { ObjectCache } from '../utils/objectCache.js'; +import { ILogService } from '../../../../../../platform/log/common/log.js'; +import { TextModelPromptParser } from '../parsers/textModelPromptParser.js'; +import { ILabelService } from '../../../../../../platform/label/common/label.js'; +import { IModelService } from '../../../../../../editor/common/services/model.js'; +import { CancellationToken } from '../../../../../../base/common/cancellation.js'; +import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; +import { IUserDataProfileService } from '../../../../../services/userDataProfile/common/userDataProfile.js'; +import type { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptPath, IPromptsService, TPromptsStorage } from './promptsService.js'; +import { getCleanPromptName, PROMPT_FILE_EXTENSION } from '../config/promptFileLocations.js'; + +/** + * Provides prompt services. + */ +export class PromptsService extends Disposable implements IPromptsService { + public declare readonly _serviceBrand: undefined; + + /** + * Cache of text model content prompt parsers. + */ + private readonly cache: ObjectCache; + + /** + * Prompt files locator utility. + */ + private readonly fileLocator: PromptFilesLocator; + + + /** + * Lazily created event that is fired when the custom chat modes change. + */ + private onDidChangeCustomChatModesEvent: Event | undefined; + + constructor( + @ILogService public readonly logger: ILogService, + @ILabelService private readonly labelService: ILabelService, + @IModelService private readonly modelService: IModelService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IUserDataProfileService private readonly userDataService: IUserDataProfileService, + ) { + super(); + + this.fileLocator = this._register(this.instantiationService.createInstance(PromptFilesLocator)); + + // the factory function below creates a new prompt parser object + // for the provided model, if no active non-disposed parser exists + this.cache = this._register( + new ObjectCache((model) => { + assert( + model.isDisposed() === false, + 'Text model must not be disposed.', + ); + + /** + * Note! When/if shared with "file" prompts, the `seenReferences` array below must be taken into account. + * Otherwise consumers will either see incorrect failing or incorrect successful results, based on their + * use case, timing of their calls to the {@link getSyntaxParserFor} function, and state of this service. + */ + const parser: TextModelPromptParser = instantiationService.createInstance( + TextModelPromptParser, + model, + { seenReferences: [] }, + ).start(); + + // this is a sanity check and the contract of the object cache, + // we must return a non-disposed object from this factory function + parser.assertNotDisposed( + 'Created prompt parser must not be disposed.', + ); + + return parser; + }) + ); + } + + /** + * Emitter for the custom chat modes change event. + */ + public get onDidChangeCustomChatModes(): Event { + if (!this.onDidChangeCustomChatModesEvent) { + this.onDidChangeCustomChatModesEvent = this._register(this.fileLocator.createFilesUpdatedEvent(PromptsType.mode)).event; + } + return this.onDidChangeCustomChatModesEvent; + } + + + /** + * @throws {Error} if: + * - the provided model is disposed + * - newly created parser is disposed immediately on initialization. + * See factory function in the {@link constructor} for more info. + */ + public getSyntaxParserFor( + model: ITextModel, + ): TextModelPromptParser & { isDisposed: false } { + assert( + model.isDisposed() === false, + 'Cannot create a prompt syntax parser for a disposed model.', + ); + + return this.cache.get(model); + } + + public async listPromptFiles(type: PromptsType, token: CancellationToken): Promise { + const prompts = await Promise.all([ + this.fileLocator.listFiles(type, 'user', token) + .then(withType('user', type)), + this.fileLocator.listFiles(type, 'local', token) + .then(withType('local', type)), + ]); + + return prompts.flat(); + } + + public getSourceFolders(type: PromptsType): readonly IPromptPath[] { + // sanity check to make sure we don't miss a new + // prompt type that could be added in the future + assert(isValidPromptType(type), `Unknown prompt type '${type}'.`); + + const result: IPromptPath[] = []; + + for (const uri of this.fileLocator.getConfigBasedSourceFolders(type)) { + result.push({ uri, storage: 'local', type }); + } + const userHome = this.userDataService.currentProfile.promptsHome; + result.push({ uri: userHome, storage: 'user', type }); + + return result; + } + + public asPromptSlashCommand(command: string): IChatPromptSlashCommand | undefined { + if (command.match(/^[\w_\-\.]+$/)) { + return { command, detail: localize('prompt.file.detail', 'Prompt file: {0}', command) }; + } + return undefined; + } + + public async resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise { + const promptUri = await this.getPromptPath(data); + if (!promptUri) { + return undefined; + } + return await this.getMetadata(promptUri); + } + + private async getPromptPath(data: IChatPromptSlashCommand): Promise { + if (data.promptPath) { + return data.promptPath.uri; + } + + const files = await this.listPromptFiles(PromptsType.prompt, CancellationToken.None); + const command = data.command; + const result = files.find(file => getPromptCommandName(file.uri.path) === command); + if (result) { + return result.uri; + } + const textModel = this.modelService.getModels().find(model => model.getLanguageId() === PROMPT_LANGUAGE_ID && getPromptCommandName(model.uri.path) === command); + if (textModel) { + return textModel.uri; + } + return undefined; + } + + public async findPromptSlashCommands(): Promise { + const promptFiles = await this.listPromptFiles(PromptsType.prompt, CancellationToken.None); + return promptFiles.map(promptPath => { + const command = getPromptCommandName(promptPath.uri.path); + return { + command, + detail: localize('prompt.file.detail', 'Prompt file: {0}', this.labelService.getUriLabel(promptPath.uri, { relative: true })), + promptPath + }; + }); + } + + public async getCustomChatModes(): Promise { + const modeFiles = (await this.listPromptFiles(PromptsType.mode, CancellationToken.None)) + .map(modeFile => modeFile.uri); + + const metadataList = await Promise.all( + modeFiles.map(async (uri): Promise => { + let parser: PromptParser | undefined; + try { + // Note! this can be (and should be) improved by using shared parser instances + // that the `getSyntaxParserFor` method provides for opened documents. + parser = this.instantiationService.createInstance( + PromptParser, + uri, + { allowNonPromptFiles: true }, + ).start(); + + await parser.settled(); + + const { metadata } = parser; + const tools = (metadata && ('tools' in metadata)) + ? metadata.tools + : undefined; + + const body = await parser.getBody(); + return { + uri: uri, + name: getCleanPromptName(uri), + description: metadata?.description, + tools, + body, + }; + } finally { + parser?.dispose(); + } + }), + ); + + return metadataList; + } + + public async findInstructionFilesFor( + files: readonly URI[], + ): Promise { + const instructionFiles = await this.listPromptFiles(PromptsType.instructions, CancellationToken.None); + if (instructionFiles.length === 0) { + return []; + } + + const instructions = await this.getAllMetadata( + instructionFiles.map(file => file.uri), + ); + + const foundFiles = new ResourceSet(); + for (const instruction of instructions.flatMap(flatten)) { + const { metadata, uri } = instruction; + + if (metadata?.promptType !== PromptsType.instructions) { + continue; + } + + const { applyTo } = metadata; + if (applyTo === undefined) { + continue; + } + + const patterns = splitGlobAware(applyTo, ','); + const patterMatches = (pattern: string) => { + pattern = pattern.trim(); + if (pattern.length === 0) { + // if glob pattern is empty, skip it + return false; + } + if (pattern === '**' || pattern === '**/*' || pattern === '*') { + // if glob pattern is one of the special wildcard values, + // add the instructions file event if no files are attached + return true; + } + if (!pattern.startsWith('/') && !pattern.startsWith('**/')) { + // support relative glob patterns, e.g. `src/**/*.js` + pattern = '**/' + pattern; + } + + // match each attached file with each glob pattern and + // add the instructions file if its rule matches the file + for (const file of files) { + // if the file is not a valid URI, skip it + if (match(pattern, file.path)) { + return true; + } + } + return false; + }; + + if (patterns.some(patterMatches)) { + foundFiles.add(uri); + } + } + return [...foundFiles]; + } + + public async getMetadata(promptFileUri: URI): Promise { + const metaDatas = await this.getAllMetadata([promptFileUri]); + return metaDatas[0]; + } + + public async getAllMetadata( + promptUris: readonly URI[], + ): Promise { + const metadata = await Promise.all( + promptUris.map(async (uri) => { + let parser: PromptParser | undefined; + try { + parser = this.instantiationService.createInstance( + PromptParser, + uri, + { allowNonPromptFiles: true }, + ).start(); + + await parser.allSettled(); + + return collectMetadata(parser); + } finally { + parser?.dispose(); + } + }), + ); + + return metadata; + } +} + +/** + * Collect all metadata from prompt file references + * into a single hierarchical tree structure. + */ +const collectMetadata = ( + reference: Pick, +): IMetadata => { + const childMetadata = []; + for (const child of reference.references) { + if (child.errorCondition !== undefined) { + continue; + } + + childMetadata.push(collectMetadata(child)); + } + + const children = (childMetadata.length > 0) + ? childMetadata + : undefined; + + return { + uri: reference.uri, + metadata: reference.metadata, + children, + }; +}; + +export function getPromptCommandName(path: string): string { + const name = basename(path, PROMPT_FILE_EXTENSION); + return name; +} + +/** + * Utility to add a provided prompt `storage` and + * `type` attributes to a prompt URI. + */ +const addType = ( + storage: TPromptsStorage, + type: PromptsType, +): (uri: URI) => IPromptPath => { + return (uri) => { + return { uri, storage, type }; + }; +}; + +/** + * Utility to add a provided prompt `type` to a list of prompt URIs. + */ +const withType = ( + storage: TPromptsStorage, + type: PromptsType, +): (uris: readonly URI[]) => (readonly IPromptPath[]) => { + return (uris) => { + return uris + .map(addType(storage, type)); + }; +}; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts deleted file mode 100644 index ce41e74a705..00000000000 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/types.ts +++ /dev/null @@ -1,224 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TTree } from '../utils/treeUtils.js'; -import { ChatMode } from '../../constants.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import { Event } from '../../../../../../base/common/event.js'; -import { TMetadata } from '../parsers/promptHeader/headerBase.js'; -import { ITextModel } from '../../../../../../editor/common/model.js'; -import { IDisposable } from '../../../../../../base/common/lifecycle.js'; -import { TextModelPromptParser } from '../parsers/textModelPromptParser.js'; -import { CancellationToken } from '../../../../../../base/common/cancellation.js'; -import { PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; -import { createDecorator } from '../../../../../../platform/instantiation/common/instantiation.js'; - -/** - * Provides prompt services. - */ -export const IPromptsService = createDecorator('IPromptsService'); - -/** - * Where the prompt is stored. - */ -export type TPromptsStorage = 'local' | 'user'; - -/** - * Represents a prompt path with its type. - * This is used for both prompt files and prompt source folders. - */ -export interface IPromptPath { - /** - * URI of the prompt. - */ - readonly uri: URI; - - /** - * Storage of the prompt. - */ - readonly storage: TPromptsStorage; - - /** - * Type of the prompt (e.g. 'prompt' or 'instructions'). - */ - readonly type: PromptsType; -} - -/** - * Type for a shared prompt parser instance returned by the {@link IPromptsService}. - * Because the parser is shared, we omit the `dispose` method from - * the original type so the caller cannot dispose it prematurely - */ -export type TSharedPrompt = Omit; - -/** - * Metadata node object in a hierarchical tree of prompt references. - */ -export interface IMetadata { - /** - * URI of a prompt file. - */ - readonly uri: URI; - - /** - * Metadata of the prompt file. - */ - readonly metadata: TMetadata | null; - - /** - * List of metadata for each valid child prompt reference. - */ - readonly children?: readonly TTree[]; -} - -export interface ICustomChatMode { - /** - * URI of a custom chat mode file. - */ - readonly uri: URI; - - /** - * Name of the custom chat mode. - */ - readonly name: string; - - /** - * Description of the mode - */ - readonly description?: string; - - /** - * Tools metadata in the prompt header. - */ - readonly tools?: readonly string[]; - - /** - * Contents of the custom chat mode file body. - */ - readonly body: string; -} - -/** - * Type of combined tools metadata for the case - * when the prompt is in the agent mode. - */ -interface ICombinedAgentToolsMetadata { - /** - * List of combined tools metadata for - * the entire tree of prompt references. - */ - readonly tools: readonly string[] | undefined; - - /** - * Resulting chat mode of a prompt, based on modes - * used in the entire tree of prompt references. - */ - readonly mode: ChatMode.Agent; -} - -/** - * Type of combined tools metadata for the case - * when the prompt is in non-agent mode. - */ -interface ICombinedNonAgentToolsMetadata { - /** - * List of combined tools metadata is empty - * when the prompt is in non-agent mode. - */ - readonly tools: undefined; - - /** - * Resulting chat mode of a prompt, based on modes - * used in the entire tree of prompt references. - */ - readonly mode?: ChatMode.Ask | ChatMode.Edit; -} - -/** - * General type of the combined tools metadata. - */ -export type TCombinedToolsMetadata = ICombinedAgentToolsMetadata | ICombinedNonAgentToolsMetadata; - -/** - * Provides prompt services. - */ -export interface IPromptsService extends IDisposable { - readonly _serviceBrand: undefined; - - /** - * Get a prompt syntax parser for the provided text model. - * See {@link TextModelPromptParser} for more info on the parser API. - */ - getSyntaxParserFor( - model: ITextModel, - ): TSharedPrompt & { isDisposed: false }; - - /** - * List all available prompt files. - */ - listPromptFiles(type: PromptsType, token: CancellationToken): Promise; - - /** - * Get a list of prompt source folders based on the provided prompt type. - */ - getSourceFolders(type: PromptsType): readonly IPromptPath[]; - - /** - * Returns a prompt command if the command name. - * Undefined is returned if the name does not look like a file name of a prompt file. - */ - asPromptSlashCommand(name: string): IChatPromptSlashCommand | undefined; - - /** - * Gets the prompt file for a slash command. - */ - resolvePromptSlashCommand(data: IChatPromptSlashCommand): Promise; - - /** - * Returns a prompt command if the command name is valid. - */ - findPromptSlashCommands(): Promise; - - /** - * Find all instruction files which have a glob pattern in their - * 'applyTo' metadata record that match the provided list of files. - */ - findInstructionFilesFor( - fileUris: readonly URI[], - ): Promise; - - /** - * Event that is triggered when the list of custom chat modes changes. - */ - readonly onDidChangeCustomChatModes: Event; - - /** - * Finds all available custom chat modes - */ - getCustomChatModes(): Promise; - - /** - * Gets the metadata for the given prompt file uri. - */ - getMetadata(promptFileUri: URI): Promise; - - /** - * Get all metadata for entire prompt references tree - * that spans out of each of the provided files. - * - * In other words, the metadata tree is built starting from - * each of the provided files, therefore the result is a number - * of metadata trees, one for each file. - */ - getAllMetadata( - promptUris: readonly URI[], - ): Promise; -} - -export interface IChatPromptSlashCommand { - readonly command: string; - readonly detail: string; - readonly promptPath?: IPromptPath; -} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts index e319d2dce02..dc52b01653f 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts @@ -8,17 +8,18 @@ import { assert } from '../../../../../../base/common/assert.js'; import { isAbsolute } from '../../../../../../base/common/path.js'; import { ResourceSet } from '../../../../../../base/common/map.js'; import { IFileService } from '../../../../../../platform/files/common/files.js'; -import { PromptsConfig } from '../../../../../../platform/prompts/common/config.js'; +import { getPromptFileLocationsConfigKey, PromptsConfig } from '../config/config.js'; import { basename, dirname, joinPath } from '../../../../../../base/common/resources.js'; import { IWorkspaceContextService } from '../../../../../../platform/workspace/common/workspace.js'; import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; -import { getPromptFileExtension, getPromptFileLocationsConfigKey, getPromptFileType, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; +import { getPromptFileExtension, getPromptFileType } from '../config/promptFileLocations.js'; +import { PromptsType } from '../promptTypes.js'; import { IWorkbenchEnvironmentService } from '../../../../../services/environment/common/environmentService.js'; import { Schemas } from '../../../../../../base/common/network.js'; import { getExcludes, IFileQuery, ISearchConfiguration, ISearchService, QueryType } from '../../../../../services/search/common/search.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { isCancellationError } from '../../../../../../base/common/errors.js'; -import { TPromptsStorage } from '../service/types.js'; +import { TPromptsStorage } from '../service/promptsService.js'; import { IUserDataProfileService } from '../../../../../services/userDataProfile/common/userDataProfile.js'; import { Emitter, Event } from '../../../../../../base/common/event.js'; import { Disposable, DisposableStore } from '../../../../../../base/common/lifecycle.js'; diff --git a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts index 217ec965f1d..5c2da359ca5 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts @@ -20,7 +20,7 @@ import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; import { IChatVariablesService } from '../../common/chatVariables.js'; import { ChatMode, ChatAgentLocation } from '../../common/constants.js'; import { IToolData, ToolDataSource } from '../../common/languageModelToolsService.js'; -import { IPromptsService } from '../../common/promptSyntax/service/types.js'; +import { IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; import { MockChatService } from './mockChatService.js'; import { MockPromptsService } from './mockPromptsService.js'; diff --git a/src/vs/platform/prompts/test/common/config.test.ts b/src/vs/workbench/contrib/chat/test/common/config/config.test.ts similarity index 97% rename from src/vs/platform/prompts/test/common/config.test.ts rename to src/vs/workbench/contrib/chat/test/common/config/config.test.ts index 3f60a2e6a8e..bfc8eef386c 100644 --- a/src/vs/platform/prompts/test/common/config.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/config/config.test.ts @@ -4,12 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { mockService } from './utils/mock.js'; -import { PromptsConfig } from '../../common/config.js'; -import { randomInt } from '../../../../base/common/numbers.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; -import { IConfigurationOverrides, IConfigurationService } from '../../../configuration/common/configuration.js'; -import { PromptsType } from '../../common/prompts.js'; + +import { PromptsConfig } from '../../../common/promptSyntax/config/config.js'; +import { PromptsType } from '../../../common/promptSyntax/promptTypes.js'; +import { randomInt } from '../../../../../../base/common/numbers.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; +import { IConfigurationOverrides, IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; +import { mockService } from '../promptSyntax/utils/mock.js'; /** * Mocked instance of {@link IConfigurationService}. diff --git a/src/vs/platform/prompts/test/common/constants.test.ts b/src/vs/workbench/contrib/chat/test/common/config/constants.test.ts similarity index 91% rename from src/vs/platform/prompts/test/common/constants.test.ts rename to src/vs/workbench/contrib/chat/test/common/config/constants.test.ts index d1181219141..1d9cfda9da0 100644 --- a/src/vs/platform/prompts/test/common/constants.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/config/constants.test.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { URI } from '../../../../base/common/uri.js'; -import { randomInt } from '../../../../base/common/numbers.js'; -import { getCleanPromptName, isPromptOrInstructionsFile } from '../../common/prompts.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; +import { getCleanPromptName, isPromptOrInstructionsFile } from '../../../common/promptSyntax/config/promptFileLocations.js'; +import { randomInt } from '../../../../../../base/common/numbers.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; +import { URI } from '../../../../../../base/common/uri.js'; suite('Prompt Constants', () => { diff --git a/src/vs/workbench/contrib/chat/test/common/config/utils/mock.test.ts b/src/vs/workbench/contrib/chat/test/common/config/utils/mock.test.ts new file mode 100644 index 00000000000..062e2a9bbdb --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/config/utils/mock.test.ts @@ -0,0 +1,194 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; + +import { typeCheck } from '../../../../../../../base/common/types.js'; +import { randomInt } from '../../../../../../../base/common/numbers.js'; +import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; +import { mockObject, mockService } from '../../promptSyntax/utils/mock.js'; + +suite('mockService', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + + suite('mockObject', () => { + test('overrides properties and functions', () => { + interface ITestObject { + foo: string; + bar: string; + readonly baz: number; + someMethod(arg: boolean): string; + anotherMethod(arg: number): boolean; + } + + const mock = mockObject({ + bar: 'oh hi!', + baz: 42, + anotherMethod(arg: number): boolean { + return isNaN(arg); + }, + }); + + typeCheck(mock); + + assert.strictEqual( + mock.bar, + 'oh hi!', + 'bar should be overriden', + ); + + assert.strictEqual( + mock.baz, + 42, + 'baz should be overriden', + ); + + assert( + !(mock.anotherMethod(randomInt(100))), + 'Must execute overriden method correctly 1.', + ); + + assert( + mock.anotherMethod(NaN), + 'Must execute overriden method correctly 2.', + ); + + assert.throws(() => { + // property is not overriden so must throw + // eslint-disable-next-line local/code-no-unused-expressions + mock.foo; + }); + + assert.throws(() => { + // function is not overriden so must throw + mock.someMethod(randomBoolean()); + }); + }); + + test('immutability of the overrides object', () => { + interface ITestObject { + foo: string; + bar: string; + readonly baz: number; + someMethod(arg: boolean): string; + anotherMethod(arg: number): boolean; + } + + const overrides: Partial = { + baz: 4, + }; + const mock = mockObject(overrides); + typeCheck(mock); + + assert.strictEqual( + mock.baz, + 4, + 'baz should be overridden', + ); + + // overrides object must be immutable + assert.throws(() => { + overrides.foo = 'test'; + }); + + assert.throws(() => { + overrides.someMethod = (arg: boolean): string => { + return `${arg}__${arg}`; + }; + }); + }); + }); + + suite('mockService', () => { + test('overrides properties and functions', () => { + interface ITestService { + readonly _serviceBrand: undefined; + prop1: string; + id: string; + readonly counter: number; + method1(arg: boolean): string; + testMethod2(arg: number): boolean; + } + + const mock = mockService({ + id: 'ciao!', + counter: 74, + testMethod2(arg: number): boolean { + return !isNaN(arg); + }, + }); + + typeCheck(mock); + + assert.strictEqual( + mock.id, + 'ciao!', + 'id should be overridden', + ); + + assert.strictEqual( + mock.counter, + 74, + 'counter should be overridden', + ); + + assert( + mock.testMethod2(randomInt(100)), + 'Must execute overridden method correctly 1.', + ); + + assert( + !(mock.testMethod2(NaN)), + 'Must execute overridden method correctly 2.', + ); + + assert.throws(() => { + // property is not overridden so must throw + // eslint-disable-next-line local/code-no-unused-expressions + mock.prop1; + }); + + assert.throws(() => { + // function is not overridden so must throw + mock.method1(randomBoolean()); + }); + }); + + test('immutability of the overrides object', () => { + interface ITestService { + readonly _serviceBrand: undefined; + foo: string; + bar: string; + readonly baz: boolean; + someMethod(arg: boolean): string; + anotherMethod(arg: number): boolean; + } + + const overrides: Partial = { + baz: false, + }; + const mock = mockService(overrides); + typeCheck(mock); + + assert.strictEqual( + mock.baz, + false, + 'baz should be overridden', + ); + + // overrides object must be immutable + assert.throws(() => { + overrides.foo = 'test'; + }); + + assert.throws(() => { + overrides.someMethod = (arg: boolean): string => { + return `${arg}__${arg}`; + }; + }); + }); + }); +}); diff --git a/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts b/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts index ae5cdcf211a..1d7162f1154 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts @@ -6,9 +6,9 @@ import { Event } from '../../../../../base/common/event.js'; import { URI } from '../../../../../base/common/uri.js'; import { ITextModel } from '../../../../../editor/common/model.js'; -import { PromptsType } from '../../../../../platform/prompts/common/prompts.js'; +import { PromptsType } from '../../common/promptSyntax/promptTypes.js'; import { TextModelPromptParser } from '../../common/promptSyntax/parsers/textModelPromptParser.js'; -import { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptPath, IPromptsService } from '../../common/promptSyntax/service/types.js'; +import { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptPath, IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; export class MockPromptsService implements IPromptsService { diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts new file mode 100644 index 00000000000..de0d5fce8a4 --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts @@ -0,0 +1,461 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { mockService } from '../utils/mock.js'; +import { PromptsConfig } from '../../../../common/promptSyntax/config/config.js'; +import { PromptsType } from '../../../../common/promptSyntax/promptTypes.js'; +import { randomInt } from '../../../../../../../base/common/numbers.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; +import { IConfigurationOverrides, IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'; + +/** + * Mocked instance of {@link IConfigurationService}. + */ +const createMock = (value: T): IConfigurationService => { + return mockService({ + getValue(key?: string | IConfigurationOverrides) { + assert( + typeof key === 'string', + `Expected string configuration key, got '${typeof key}'.`, + ); + + assert( + [PromptsConfig.KEY, PromptsConfig.PROMPT_LOCATIONS_KEY, PromptsConfig.INSTRUCTIONS_LOCATION_KEY, PromptsConfig.MODE_LOCATION_KEY].includes(key), + `Unsupported configuration key '${key}'.`, + ); + + return value; + }, + }); +}; + +suite('PromptsConfig', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + + suite('enabled', () => { + test('true', () => { + const configService = createMock(true); + + assert.strictEqual( + PromptsConfig.enabled(configService), + true, + 'Must read correct enablement value.', + ); + }); + + test('false', () => { + const configService = createMock(false); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('null', () => { + const configService = createMock(null); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('string', () => { + const configService = createMock(''); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('true string', () => { + const configService = createMock('TRUE'); + + assert.strictEqual( + PromptsConfig.enabled(configService), + true, + 'Must read correct enablement value.', + ); + }); + + test('false string', () => { + const configService = createMock('FaLsE'); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('number', () => { + const configService = createMock(randomInt(100)); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('NaN', () => { + const configService = createMock(NaN); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('bigint', () => { + const configService = createMock(BigInt(randomInt(100))); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('symbol', () => { + const configService = createMock(Symbol('test')); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('object', () => { + const configService = createMock({ + '.github/prompts': false, + }); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + + test('array', () => { + const configService = createMock(['.github/prompts']); + + assert.strictEqual( + PromptsConfig.enabled(configService), + false, + 'Must read correct enablement value.', + ); + }); + }); + + + suite('getLocationsValue', () => { + test('undefined', () => { + const configService = createMock(undefined); + + assert.strictEqual( + PromptsConfig.getLocationsValue(configService, PromptsType.prompt), + undefined, + 'Must read correct value.', + ); + }); + + test('null', () => { + const configService = createMock(null); + + assert.strictEqual( + PromptsConfig.getLocationsValue(configService, PromptsType.prompt), + undefined, + 'Must read correct value.', + ); + }); + + suite('object', () => { + test('empty', () => { + assert.deepStrictEqual( + PromptsConfig.getLocationsValue(createMock({}), PromptsType.prompt), + {}, + 'Must read correct value.', + ); + }); + + test('only valid strings', () => { + assert.deepStrictEqual( + PromptsConfig.getLocationsValue(createMock({ + '/root/.bashrc': true, + '../../folder/.hidden-folder/config.xml': true, + '/srv/www/Public_html/.htaccess': true, + '../../another.folder/.WEIRD_FILE.log': true, + './folder.name/file.name': true, + '/media/external/backup.tar.gz': true, + '/Media/external/.secret.backup': true, + '../relative/path.to.file': true, + './folderName.with.dots/more.dots.extension': true, + 'some/folder.with.dots/another.file': true, + '/var/logs/app.01.05.error': true, + './.tempfile': true, + }), PromptsType.prompt), + { + '/root/.bashrc': true, + '../../folder/.hidden-folder/config.xml': true, + '/srv/www/Public_html/.htaccess': true, + '../../another.folder/.WEIRD_FILE.log': true, + './folder.name/file.name': true, + '/media/external/backup.tar.gz': true, + '/Media/external/.secret.backup': true, + '../relative/path.to.file': true, + './folderName.with.dots/more.dots.extension': true, + 'some/folder.with.dots/another.file': true, + '/var/logs/app.01.05.error': true, + './.tempfile': true, + }, + 'Must read correct value.', + ); + }); + + test('filters out non valid entries', () => { + assert.deepStrictEqual( + PromptsConfig.getLocationsValue(createMock({ + '/etc/hosts.backup': '\t\n\t', + './run.tests.sh': '\v', + '../assets/img/logo.v2.png': true, + '/mnt/storage/video.archive/episode.01.mkv': false, + '../.local/bin/script.sh': true, + '/usr/local/share/.fonts/CustomFont.otf': '', + '../../development/branch.name/some.test': true, + '/Home/user/.ssh/config': true, + './hidden.dir/.subhidden': '\f', + '/tmp/.temp.folder/cache.db': true, + '/opt/software/v3.2.1/build.log': ' ', + '': true, + './scripts/.old.build.sh': true, + '/var/data/datafile.2025-02-05.json': '\n', + '\n\n': true, + '\t': true, + '\v': true, + '\f': true, + '\r\n': true, + '\f\f': true, + '../lib/some_library.v1.0.1.so': '\r\n', + '/dev/shm/.shared_resource': randomInt(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER), + }), PromptsType.prompt), + { + '../assets/img/logo.v2.png': true, + '/mnt/storage/video.archive/episode.01.mkv': false, + '../.local/bin/script.sh': true, + '../../development/branch.name/some.test': true, + '/Home/user/.ssh/config': true, + '/tmp/.temp.folder/cache.db': true, + './scripts/.old.build.sh': true, + }, + 'Must read correct value.', + ); + }); + + test('only invalid or false values', () => { + assert.deepStrictEqual( + PromptsConfig.getLocationsValue(createMock({ + '/etc/hosts.backup': '\t\n\t', + './run.tests.sh': '\v', + '../assets/IMG/logo.v2.png': '', + '/mnt/storage/video.archive/episode.01.mkv': false, + '/usr/local/share/.fonts/CustomFont.otf': '', + './hidden.dir/.subhidden': '\f', + '/opt/Software/v3.2.1/build.log': ' ', + '/var/data/datafile.2025-02-05.json': '\n', + '../lib/some_library.v1.0.1.so': '\r\n', + '/dev/shm/.shared_resource': randomInt(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER), + }), PromptsType.prompt), + { + '/mnt/storage/video.archive/episode.01.mkv': false, + }, + 'Must read correct value.', + ); + }); + }); + }); + + suite('sourceLocations', () => { + test('undefined', () => { + const configService = createMock(undefined); + + assert.deepStrictEqual( + PromptsConfig.promptSourceFolders(configService, PromptsType.prompt), + [], + 'Must read correct value.', + ); + }); + + test('null', () => { + const configService = createMock(null); + + assert.deepStrictEqual( + PromptsConfig.promptSourceFolders(configService, PromptsType.prompt), + [], + 'Must read correct value.', + ); + }); + + suite('object', () => { + test('empty', () => { + assert.deepStrictEqual( + PromptsConfig.promptSourceFolders(createMock({}), PromptsType.prompt), + ['.github/prompts'], + 'Must read correct value.', + ); + }); + + test('only valid strings', () => { + assert.deepStrictEqual( + PromptsConfig.promptSourceFolders(createMock({ + '/root/.bashrc': true, + '../../folder/.hidden-folder/config.xml': true, + '/srv/www/Public_html/.htaccess': true, + '../../another.folder/.WEIRD_FILE.log': true, + './folder.name/file.name': true, + '/media/external/backup.tar.gz': true, + '/Media/external/.secret.backup': true, + '../relative/path.to.file': true, + './folderName.with.dots/more.dots.extension': true, + 'some/folder.with.dots/another.file': true, + '/var/logs/app.01.05.error': true, + '.GitHub/prompts': true, + './.tempfile': true, + }), PromptsType.prompt), + [ + '.github/prompts', + '/root/.bashrc', + '../../folder/.hidden-folder/config.xml', + '/srv/www/Public_html/.htaccess', + '../../another.folder/.WEIRD_FILE.log', + './folder.name/file.name', + '/media/external/backup.tar.gz', + '/Media/external/.secret.backup', + '../relative/path.to.file', + './folderName.with.dots/more.dots.extension', + 'some/folder.with.dots/another.file', + '/var/logs/app.01.05.error', + '.GitHub/prompts', + './.tempfile', + ], + 'Must read correct value.', + ); + }); + + test('filters out non valid entries', () => { + assert.deepStrictEqual( + PromptsConfig.promptSourceFolders(createMock({ + '/etc/hosts.backup': '\t\n\t', + './run.tests.sh': '\v', + '../assets/img/logo.v2.png': true, + '/mnt/storage/video.archive/episode.01.mkv': false, + '../.local/bin/script.sh': true, + '/usr/local/share/.fonts/CustomFont.otf': '', + '../../development/branch.name/some.test': true, + '.giThub/prompts': true, + '/Home/user/.ssh/config': true, + './hidden.dir/.subhidden': '\f', + '/tmp/.temp.folder/cache.db': true, + '.github/prompts': true, + '/opt/software/v3.2.1/build.log': ' ', + '': true, + './scripts/.old.build.sh': true, + '/var/data/datafile.2025-02-05.json': '\n', + '\n\n': true, + '\t': true, + '\v': true, + '\f': true, + '\r\n': true, + '\f\f': true, + '../lib/some_library.v1.0.1.so': '\r\n', + '/dev/shm/.shared_resource': randomInt(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER), + }), PromptsType.prompt), + [ + '.github/prompts', + '../assets/img/logo.v2.png', + '../.local/bin/script.sh', + '../../development/branch.name/some.test', + '.giThub/prompts', + '/Home/user/.ssh/config', + '/tmp/.temp.folder/cache.db', + './scripts/.old.build.sh', + ], + 'Must read correct value.', + ); + }); + + test('only invalid or false values', () => { + assert.deepStrictEqual( + PromptsConfig.promptSourceFolders(createMock({ + '/etc/hosts.backup': '\t\n\t', + './run.tests.sh': '\v', + '../assets/IMG/logo.v2.png': '', + '/mnt/storage/video.archive/episode.01.mkv': false, + '/usr/local/share/.fonts/CustomFont.otf': '', + './hidden.dir/.subhidden': '\f', + '/opt/Software/v3.2.1/build.log': ' ', + '/var/data/datafile.2025-02-05.json': '\n', + '../lib/some_library.v1.0.1.so': '\r\n', + '/dev/shm/.shared_resource': randomInt(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER), + }), PromptsType.prompt), + [ + '.github/prompts', + ], + 'Must read correct value.', + ); + }); + + test('filters out disabled default location', () => { + assert.deepStrictEqual( + PromptsConfig.promptSourceFolders(createMock({ + '/etc/hosts.backup': '\t\n\t', + './run.tests.sh': '\v', + '.github/prompts': false, + '../assets/img/logo.v2.png': true, + '/mnt/storage/video.archive/episode.01.mkv': false, + '../.local/bin/script.sh': true, + '/usr/local/share/.fonts/CustomFont.otf': '', + '../../development/branch.name/some.test': true, + '.giThub/prompts': true, + '/Home/user/.ssh/config': true, + './hidden.dir/.subhidden': '\f', + '/tmp/.temp.folder/cache.db': true, + '/opt/software/v3.2.1/build.log': ' ', + '': true, + './scripts/.old.build.sh': true, + '/var/data/datafile.2025-02-05.json': '\n', + '\n\n': true, + '\t': true, + '\v': true, + '\f': true, + '\r\n': true, + '\f\f': true, + '../lib/some_library.v1.0.1.so': '\r\n', + '/dev/shm/.shared_resource': randomInt(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER), + }), PromptsType.prompt), + [ + '../assets/img/logo.v2.png', + '../.local/bin/script.sh', + '../../development/branch.name/some.test', + '.giThub/prompts', + '/Home/user/.ssh/config', + '/tmp/.temp.folder/cache.db', + './scripts/.old.build.sh', + ], + 'Must read correct value.', + ); + }); + }); + }); +}); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/constants.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/constants.test.ts new file mode 100644 index 00000000000..cbde965cf2d --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/constants.test.ts @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { getCleanPromptName, isPromptOrInstructionsFile } from '../../../../common/promptSyntax/config/promptFileLocations.js'; +import { randomInt } from '../../../../../../../base/common/numbers.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; +import { URI } from '../../../../../../../base/common/uri.js'; + + +suite('Prompt Constants', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + + suite('getCleanPromptName', () => { + test('returns a clean prompt name', () => { + assert.strictEqual( + getCleanPromptName(URI.file('/path/to/my-prompt.prompt.md')), + 'my-prompt', + ); + + assert.strictEqual( + getCleanPromptName(URI.file('../common.prompt.md')), + 'common', + ); + + const expectedPromptName = `some-${randomInt(1000)}`; + assert.strictEqual( + getCleanPromptName(URI.file(`./${expectedPromptName}.prompt.md`)), + expectedPromptName, + ); + + assert.strictEqual( + getCleanPromptName(URI.file('.github/copilot-instructions.md')), + 'copilot-instructions', + ); + + assert.strictEqual( + getCleanPromptName(URI.file('/etc/prompts/my-prompt')), + 'my-prompt', + ); + + assert.strictEqual( + getCleanPromptName(URI.file('../some-folder/frequent.txt')), + 'frequent.txt', + ); + + assert.strictEqual( + getCleanPromptName(URI.parse('untitled:Untitled-1')), + 'Untitled-1', + ); + }); + }); + + suite('isPromptOrInstructionsFile', () => { + test('returns `true` for prompt files', () => { + assert( + isPromptOrInstructionsFile(URI.file('/path/to/my-prompt.prompt.md')), + ); + + assert( + isPromptOrInstructionsFile(URI.file('../common.prompt.md')), + ); + + assert( + isPromptOrInstructionsFile(URI.file(`./some-${randomInt(1000)}.prompt.md`)), + ); + + assert( + isPromptOrInstructionsFile(URI.file('.github/copilot-instructions.md')), + ); + }); + + test('returns `false` for non-prompt files', () => { + assert( + !isPromptOrInstructionsFile(URI.file('/path/to/my-prompt.prompt.md1')), + ); + + assert( + !isPromptOrInstructionsFile(URI.file('../common.md')), + ); + + assert( + !isPromptOrInstructionsFile(URI.file(`./some-${randomInt(1000)}.txt`)), + ); + }); + }); +}); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts index 013e8ebb23c..cd1aa4c8915 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/parsers/textModelPromptParser.test.ts @@ -15,14 +15,14 @@ import { Disposable } from '../../../../../../../base/common/lifecycle.js'; import { OpenFailed } from '../../../../common/promptFileReferenceErrors.js'; import { IFileService } from '../../../../../../../platform/files/common/files.js'; import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; -import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; +import { PROMPT_LANGUAGE_ID, INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PromptsType } from '../../../../common/promptSyntax/promptTypes.js'; import { FileService } from '../../../../../../../platform/files/common/fileService.js'; import { createTextModel } from '../../../../../../../editor/test/common/testTextModel.js'; import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; import { TextModelPromptParser } from '../../../../common/promptSyntax/parsers/textModelPromptParser.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; import { IInstantiationService } from '../../../../../../../platform/instantiation/common/instantiation.js'; -import { INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../../../../common/promptSyntax/constants.js'; + import { InMemoryFileSystemProvider } from '../../../../../../../platform/files/common/inMemoryFilesystemProvider.js'; import { ExpectedDiagnosticError, ExpectedDiagnosticWarning, TExpectedDiagnostic } from '../testUtils/expectedDiagnostic.js'; import { TestInstantiationService } from '../../../../../../../platform/instantiation/test/common/instantiationServiceMock.js'; diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts index 90676ae9cae..a8f6cc657f3 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts @@ -4,34 +4,35 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { ChatMode } from '../../../common/constants.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import { Schemas } from '../../../../../../base/common/network.js'; -import { Range } from '../../../../../../editor/common/core/range.js'; -import { assertDefined } from '../../../../../../base/common/types.js'; -import { Disposable } from '../../../../../../base/common/lifecycle.js'; -import { IMockFolder, MockFilesystem } from './testUtils/mockFilesystem.js'; -import { IFileService } from '../../../../../../platform/files/common/files.js'; -import { IModelService } from '../../../../../../editor/common/services/model.js'; -import { FileService } from '../../../../../../platform/files/common/fileService.js'; -import { type TPromptReference } from '../../../common/promptSyntax/parsers/types.js'; -import { NullPolicyService } from '../../../../../../platform/policy/common/policy.js'; -import { ILanguageService } from '../../../../../../editor/common/languages/language.js'; -import { ILogService, NullLogService } from '../../../../../../platform/log/common/log.js'; -import { FileReference } from '../../../common/promptSyntax/codecs/tokens/fileReference.js'; -import { FilePromptParser } from '../../../common/promptSyntax/parsers/filePromptParser.js'; import { timeout } from '../../../../../../base/common/async.js'; +import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { Schemas } from '../../../../../../base/common/network.js'; +import { assertDefined } from '../../../../../../base/common/types.js'; +import { URI } from '../../../../../../base/common/uri.js'; import { randomBoolean } from '../../../../../../base/test/common/testUtils.js'; -import { getPromptFileType, PromptsType } from '../../../../../../platform/prompts/common/prompts.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; +import { Range } from '../../../../../../editor/common/core/range.js'; +import { ILanguageService } from '../../../../../../editor/common/languages/language.js'; +import { IModelService } from '../../../../../../editor/common/services/model.js'; import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; -import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { MarkdownLink } from '../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.js'; import { ConfigurationService } from '../../../../../../platform/configuration/common/configurationService.js'; +import { IFileService } from '../../../../../../platform/files/common/files.js'; +import { FileService } from '../../../../../../platform/files/common/fileService.js'; import { InMemoryFileSystemProvider } from '../../../../../../platform/files/common/inMemoryFilesystemProvider.js'; -import { IPromptParserOptions, type TErrorCondition } from '../../../common/promptSyntax/parsers/basePromptParser.js'; +import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { TestInstantiationService } from '../../../../../../platform/instantiation/test/common/instantiationServiceMock.js'; -import { NotPromptFile, RecursiveReference, OpenFailed, FolderReference } from '../../../common/promptFileReferenceErrors.js'; +import { ILogService, NullLogService } from '../../../../../../platform/log/common/log.js'; +import { NullPolicyService } from '../../../../../../platform/policy/common/policy.js'; +import { ChatMode } from '../../../common/constants.js'; +import { FolderReference, NotPromptFile, OpenFailed, RecursiveReference } from '../../../common/promptFileReferenceErrors.js'; +import { MarkdownLink } from '../../../common/promptSyntax/codecs/base/markdownCodec/tokens/markdownLink.js'; +import { FileReference } from '../../../common/promptSyntax/codecs/tokens/fileReference.js'; +import { getPromptFileType } from '../../../common/promptSyntax/config/promptFileLocations.js'; +import { PromptsType } from '../../../common/promptSyntax/promptTypes.js'; +import { IPromptParserOptions, type TErrorCondition } from '../../../common/promptSyntax/parsers/basePromptParser.js'; +import { FilePromptParser } from '../../../common/promptSyntax/parsers/filePromptParser.js'; +import { type TPromptReference } from '../../../common/promptSyntax/parsers/types.js'; +import { IMockFolder, MockFilesystem } from './testUtils/mockFilesystem.js'; /** * Represents a file reference with an expected diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts index 1b169671e33..8620c1e43b5 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts @@ -5,31 +5,31 @@ import assert from 'assert'; import * as sinon from 'sinon'; -import { URI } from '../../../../../../../base/common/uri.js'; -import { MockFilesystem } from '../testUtils/mockFilesystem.js'; -import { Schemas } from '../../../../../../../base/common/network.js'; -import { Range } from '../../../../../../../editor/common/core/range.js'; -import { assertDefined } from '../../../../../../../base/common/types.js'; -import { IPromptsService } from '../../../../common/promptSyntax/service/types.js'; -import { IFileService } from '../../../../../../../platform/files/common/files.js'; -import { IModelService } from '../../../../../../../editor/common/services/model.js'; -import { IPromptFileReference } from '../../../../common/promptSyntax/parsers/types.js'; -import { FileService } from '../../../../../../../platform/files/common/fileService.js'; -import { createTextModel } from '../../../../../../../editor/test/common/testTextModel.js'; -import { PromptsService } from '../../../../common/promptSyntax/service/promptsService.js'; -import { ILanguageService } from '../../../../../../../editor/common/languages/language.js'; -import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; -import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; import { timeout } from '../../../../../../../base/common/async.js'; -import { TextModelPromptParser } from '../../../../common/promptSyntax/parsers/textModelPromptParser.js'; +import { Schemas } from '../../../../../../../base/common/network.js'; +import { assertDefined } from '../../../../../../../base/common/types.js'; +import { URI } from '../../../../../../../base/common/uri.js'; +import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; +import { Range } from '../../../../../../../editor/common/core/range.js'; +import { ILanguageService } from '../../../../../../../editor/common/languages/language.js'; +import { IModelService } from '../../../../../../../editor/common/services/model.js'; +import { createTextModel } from '../../../../../../../editor/test/common/testTextModel.js'; import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'; -import { INSTRUCTIONS_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../../../../common/promptSyntax/constants.js'; +import { TestConfigurationService } from '../../../../../../../platform/configuration/test/common/testConfigurationService.js'; +import { IFileService } from '../../../../../../../platform/files/common/files.js'; +import { FileService } from '../../../../../../../platform/files/common/fileService.js'; import { InMemoryFileSystemProvider } from '../../../../../../../platform/files/common/inMemoryFilesystemProvider.js'; import { TestInstantiationService } from '../../../../../../../platform/instantiation/test/common/instantiationServiceMock.js'; -import { TestConfigurationService } from '../../../../../../../platform/configuration/test/common/testConfigurationService.js'; -import { INSTRUCTION_FILE_EXTENSION, PROMPT_FILE_EXTENSION, PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; +import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; import { IWorkspacesService } from '../../../../../../../platform/workspaces/common/workspaces.js'; +import { INSTRUCTION_FILE_EXTENSION, PROMPT_FILE_EXTENSION } from '../../../../common/promptSyntax/config/promptFileLocations.js'; +import { INSTRUCTIONS_LANGUAGE_ID, PROMPT_LANGUAGE_ID, PromptsType } from '../../../../common/promptSyntax/promptTypes.js'; +import { TextModelPromptParser } from '../../../../common/promptSyntax/parsers/textModelPromptParser.js'; +import { IPromptFileReference } from '../../../../common/promptSyntax/parsers/types.js'; +import { PromptsService } from '../../../../common/promptSyntax/service/promptsServiceImpl.js'; +import { IPromptsService } from '../../../../common/promptSyntax/service/promptsService.js'; +import { MockFilesystem } from '../testUtils/mockFilesystem.js'; /** * Helper class to assert the properties of a link. diff --git a/src/vs/platform/prompts/test/common/utils/mock.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/mock.test.ts similarity index 94% rename from src/vs/platform/prompts/test/common/utils/mock.test.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/mock.test.ts index 6d50dd24493..460e96e892e 100644 --- a/src/vs/platform/prompts/test/common/utils/mock.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/mock.test.ts @@ -5,10 +5,10 @@ import assert from 'assert'; import { mockObject, mockService } from './mock.js'; -import { typeCheck } from '../../../../../base/common/types.js'; -import { randomInt } from '../../../../../base/common/numbers.js'; -import { randomBoolean } from '../../../../../base/test/common/testUtils.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; +import { typeCheck } from '../../../../../../../base/common/types.js'; +import { randomInt } from '../../../../../../../base/common/numbers.js'; +import { randomBoolean } from '../../../../../../../base/test/common/testUtils.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; suite('mockService', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/platform/prompts/test/common/utils/mock.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/mock.ts similarity index 93% rename from src/vs/platform/prompts/test/common/utils/mock.ts rename to src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/mock.ts index 26b870312b2..6e480a1f43c 100644 --- a/src/vs/platform/prompts/test/common/utils/mock.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/mock.ts @@ -3,8 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { assert } from '../../../../../base/common/assert.js'; -import { isOneOf } from '../../../../../base/common/types.js'; +import { assert } from '../../../../../../../base/common/assert.js'; +import { isOneOf } from '../../../../../../../base/common/types.js'; + + /** * Mocks an `TObject` with the provided `overrides`. diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts index 9c4f0a3165c..849a8b5b34f 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts @@ -4,28 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; +import { CancellationToken } from '../../../../../../../base/common/cancellation.js'; +import { match } from '../../../../../../../base/common/glob.js'; import { Schemas } from '../../../../../../../base/common/network.js'; import { basename, relativePath } from '../../../../../../../base/common/resources.js'; -import { IMockFolder, MockFilesystem } from '../testUtils/mockFilesystem.js'; -import { IFileService } from '../../../../../../../platform/files/common/files.js'; -import { PromptsConfig } from '../../../../../../../platform/prompts/common/config.js'; -import { FileService } from '../../../../../../../platform/files/common/fileService.js'; -import { mockService } from '../../../../../../../platform/prompts/test/common/utils/mock.js'; -import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; +import { URI } from '../../../../../../../base/common/uri.js'; +import { mock } from '../../../../../../../base/test/common/mock.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js'; -import { isValidGlob, PromptFilesLocator } from '../../../../common/promptSyntax/utils/promptFilesLocator.js'; +import { IConfigurationOverrides, IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'; +import { IFileService } from '../../../../../../../platform/files/common/files.js'; +import { FileService } from '../../../../../../../platform/files/common/fileService.js'; import { InMemoryFileSystemProvider } from '../../../../../../../platform/files/common/inMemoryFilesystemProvider.js'; import { TestInstantiationService } from '../../../../../../../platform/instantiation/test/common/instantiationServiceMock.js'; -import { IConfigurationOverrides, IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'; +import { ILogService, NullLogService } from '../../../../../../../platform/log/common/log.js'; import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder } from '../../../../../../../platform/workspace/common/workspace.js'; -import { PromptsType } from '../../../../../../../platform/prompts/common/prompts.js'; -import { CancellationToken } from '../../../../../../../base/common/cancellation.js'; import { IWorkbenchEnvironmentService } from '../../../../../../services/environment/common/environmentService.js'; +import { IFileMatch, IFileQuery, ISearchService } from '../../../../../../services/search/common/search.js'; import { IUserDataProfileService } from '../../../../../../services/userDataProfile/common/userDataProfile.js'; -import { ISearchService, IFileQuery, IFileMatch } from '../../../../../../services/search/common/search.js'; -import { URI } from '../../../../../../../base/common/uri.js'; -import { match } from '../../../../../../../base/common/glob.js'; -import { mock } from '../../../../../../../base/test/common/mock.js'; +import { PromptsConfig } from '../../../../common/promptSyntax/config/config.js'; +import { PromptsType } from '../../../../common/promptSyntax/promptTypes.js'; +import { isValidGlob, PromptFilesLocator } from '../../../../common/promptSyntax/utils/promptFilesLocator.js'; +import { IMockFolder, MockFilesystem } from '../testUtils/mockFilesystem.js'; +import { mockService } from './mock.js'; /** * Mocked instance of {@link IConfigurationService}. diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts index 6342f587a42..f68cf896d94 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts @@ -39,8 +39,8 @@ import { createStyleSheet2 } from '../../../../base/browser/domStylesheets.js'; import { stringValue } from '../../../../base/browser/cssValue.js'; import { observableConfigValue } from '../../../../platform/observable/common/platformObservableUtils.js'; import { ChatAgentLocation } from '../../chat/common/constants.js'; -import { INSTRUCTIONS_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../../chat/common/promptSyntax/constants.js'; -import { MODE_FILE_EXTENSION } from '../../../../platform/prompts/common/prompts.js'; +import { INSTRUCTIONS_LANGUAGE_ID, PROMPT_LANGUAGE_ID } from '../../chat/common/promptSyntax/promptTypes.js'; +import { MODE_FILE_EXTENSION } from '../../chat/common/promptSyntax/config/promptFileLocations.js'; /** * Set of language IDs where inline chat hints should not be shown. diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts index 13eaefd9ace..1605df163d4 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts @@ -67,7 +67,7 @@ import { ChatWidgetHistoryService, IChatWidgetHistoryService } from '../../../ch import { ChatAgentLocation, ChatMode } from '../../../chat/common/constants.js'; import { ILanguageModelsService, LanguageModelsService } from '../../../chat/common/languageModels.js'; import { ILanguageModelToolsService } from '../../../chat/common/languageModelToolsService.js'; -import { IPromptsService } from '../../../chat/common/promptSyntax/service/types.js'; +import { IPromptsService } from '../../../chat/common/promptSyntax/service/promptsService.js'; import { MockChatModeService } from '../../../chat/test/common/mockChatModeService.js'; import { MockLanguageModelToolsService } from '../../../chat/test/common/mockLanguageModelToolsService.js'; import { INotebookEditorService } from '../../../notebook/browser/services/notebookEditorService.js'; diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 21d1c9b2065..8fbd8a59075 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -53,8 +53,6 @@ import { IWorkbenchIssueService } from '../../issue/common/issue.js'; import { IUserDataProfileService } from '../../../services/userDataProfile/common/userDataProfile.js'; import { ILocalizedString } from '../../../../platform/action/common/action.js'; import { isWeb } from '../../../../base/common/platform.js'; -import { PromptsConfig } from '../../../../platform/prompts/common/config.js'; -import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; type ConfigureSyncQuickPickItem = { id: SyncResource; label: string; description?: string }; @@ -116,8 +114,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo @IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService, @IHostService private readonly hostService: IHostService, @ICommandService private readonly commandService: ICommandService, - @IWorkbenchIssueService private readonly workbenchIssueService: IWorkbenchIssueService, - @IConfigurationService private readonly configService: IConfigurationService, + @IWorkbenchIssueService private readonly workbenchIssueService: IWorkbenchIssueService ) { super(); @@ -615,16 +612,11 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo }, { id: SyncResource.Profiles, label: getSyncAreaLabel(SyncResource.Profiles), + }, { + id: SyncResource.Prompts, + label: getSyncAreaLabel(SyncResource.Prompts) }]; - // if the `reusable prompt` feature is enabled and in vscode - // insiders, add the `Prompts` resource item to the list - if (PromptsConfig.enabled(this.configService) === true) { - result.push({ - id: SyncResource.Prompts, - label: getSyncAreaLabel(SyncResource.Prompts) - }); - } return result; } From bbfac3582276c2aa715197eff0ef6d0d2edf391a Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 6 Jun 2025 15:02:50 -0700 Subject: [PATCH 105/236] mcp: support system message is sampling (#250900) Ref https://github.com/microsoft/vscode/issues/244162\#issuecomment-2946034316 --- src/vs/workbench/contrib/mcp/common/mcpSamplingService.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/mcp/common/mcpSamplingService.ts b/src/vs/workbench/contrib/mcp/common/mcpSamplingService.ts index 36151a9565d..caed5bff99d 100644 --- a/src/vs/workbench/contrib/mcp/common/mcpSamplingService.ts +++ b/src/vs/workbench/contrib/mcp/common/mcpSamplingService.ts @@ -68,6 +68,10 @@ export class McpSamplingService extends Disposable implements IMcpSamplingServic }; }).filter(isDefined); + if (opts.params.systemPrompt) { + messages.unshift({ role: ChatMessageRole.System, content: [{ type: 'text', value: opts.params.systemPrompt }] }); + } + const model = await this._getMatchingModel(opts); // todo@connor4312: nullExtensionDescription.identifier -> undefined with API update const response = await this._languageModelsService.sendChatRequest(model, new ExtensionIdentifier('Github.copilot-chat'), messages, {}, token); From 00e555f620750362f5b7caca843f699f0a48c72d Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 6 Jun 2025 15:04:44 -0700 Subject: [PATCH 106/236] testing: preserve path on failed cases (#250757) Ref https://github.com/Dart-Code/Dart-Code/issues/5534 --- .../contrib/testing/browser/testResultsView/testResultsTree.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts index 1895434ddba..93d3a8d56cf 100644 --- a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts +++ b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts @@ -745,6 +745,9 @@ class TestRunElementRenderer implements ICompressibleTreeRenderer Date: Fri, 6 Jun 2025 16:44:40 -0700 Subject: [PATCH 107/236] cover the constructor as well (#250675) --- .../workbench/api/common/extHostNotebookEditor.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebookEditor.ts b/src/vs/workbench/api/common/extHostNotebookEditor.ts index 7ef4dc5f5ae..a007ca50e2d 100644 --- a/src/vs/workbench/api/common/extHostNotebookEditor.ts +++ b/src/vs/workbench/api/common/extHostNotebookEditor.ts @@ -18,16 +18,19 @@ export class ExtHostNotebookEditor { private _visible: boolean = false; private _editor?: vscode.NotebookEditor; + private _selections: vscode.NotebookRange[] = [new NotebookRange(0, 0)]; constructor( readonly id: string, private readonly _proxy: MainThreadNotebookEditorsShape, readonly notebookData: ExtHostNotebookDocument, private _visibleRanges: vscode.NotebookRange[], - private _selections: vscode.NotebookRange[], + selections: vscode.NotebookRange[], private _viewColumn: vscode.ViewColumn | undefined, private readonly viewType: string - ) { } + ) { + this._selections = this._validSelections(selections); + } get apiEditor(): vscode.NotebookEditor { if (!this._editor) { @@ -49,7 +52,7 @@ export class ExtHostNotebookEditor { if (!Array.isArray(value) || !value.every(extHostTypes.NotebookRange.isNotebookRange)) { throw illegalArgument('selections'); } - that._selections = value.length === 0 ? [new NotebookRange(0, 0)] : value; + that._selections = that._validSelections(value); that._trySetSelections(that._selections); }, get visibleRanges() { @@ -94,7 +97,7 @@ export class ExtHostNotebookEditor { } _acceptSelections(selections: vscode.NotebookRange[]): void { - this._selections = selections.length === 0 ? [new NotebookRange(0, 0)] : selections; + this._selections = this._validSelections(selections); } private _trySetSelections(value: vscode.NotebookRange[]): void { @@ -104,4 +107,8 @@ export class ExtHostNotebookEditor { _acceptViewColumn(value: vscode.ViewColumn | undefined) { this._viewColumn = value; } + + private _validSelections(selections: vscode.NotebookRange[]) { + return selections.length === 0 ? [new NotebookRange(0, 0)] : selections; + } } From af218df4934b96077e7b1437396eb9dcacce67f7 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 6 Jun 2025 18:47:38 -0700 Subject: [PATCH 108/236] mcp: fix authority-less MCP resources cannot be read by VS Code (#250908) Fixes #250905 --- .../workbench/contrib/mcp/common/mcpTypes.ts | 10 ++++--- .../contrib/mcp/test/common/mcpTypes.test.ts | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 src/vs/workbench/contrib/mcp/test/common/mcpTypes.test.ts diff --git a/src/vs/workbench/contrib/mcp/common/mcpTypes.ts b/src/vs/workbench/contrib/mcp/common/mcpTypes.ts index 5363b76ee00..768d58bc2cf 100644 --- a/src/vs/workbench/contrib/mcp/common/mcpTypes.ts +++ b/src/vs/workbench/contrib/mcp/common/mcpTypes.ts @@ -609,6 +609,10 @@ export const mcpServerIcon = registerIcon('mcp-server', Codicon.mcp, localize('m export namespace McpResourceURI { export const scheme = 'mcp-resource'; + // Random placeholder for empty authorities, otherwise they're represente as + // `scheme//path/here` in the URI which would get normalized to `scheme/path/here`. + const emptyAuthorityPlaceholder = 'dylo78gyp'; // chosen by a fair dice roll. Guaranteed to be random. + export function fromServer(def: McpDefinitionReference, resourceURI: URI | string): URI { if (typeof resourceURI === 'string') { resourceURI = URI.parse(resourceURI); @@ -616,7 +620,7 @@ export namespace McpResourceURI { return resourceURI.with({ scheme, authority: encodeHex(VSBuffer.fromString(def.id)), - path: ['', resourceURI.scheme, resourceURI.authority].join('/') + resourceURI.path, + path: ['', resourceURI.scheme, resourceURI.authority || emptyAuthorityPlaceholder].join('/') + resourceURI.path, }); } @@ -636,8 +640,8 @@ export namespace McpResourceURI { definitionId: decodeHex(uri.authority).toString(), resourceURI: uri.with({ scheme: serverScheme, - authority, - path: '/' + path.join('/'), + authority: authority.toLowerCase() === emptyAuthorityPlaceholder ? '' : authority, + path: path.length ? ('/' + path.join('/')) : '', }), }; } diff --git a/src/vs/workbench/contrib/mcp/test/common/mcpTypes.test.ts b/src/vs/workbench/contrib/mcp/test/common/mcpTypes.test.ts new file mode 100644 index 00000000000..ca832e81c44 --- /dev/null +++ b/src/vs/workbench/contrib/mcp/test/common/mcpTypes.test.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; +import { McpResourceURI } from '../../common/mcpTypes.js'; +import * as assert from 'assert'; + +suite('MCP Types', () => { + ensureNoDisposablesAreLeakedInTestSuite(); + + test('McpResourceURI - round trips', () => { + const roundTrip = (uri: string) => { + const from = McpResourceURI.fromServer({ label: '', id: 'my-id' }, uri); + const to = McpResourceURI.toServer(from); + assert.strictEqual(to.definitionId, 'my-id'); + assert.strictEqual(to.resourceURI.toString(true), uri, `expected to round trip ${uri}`); + }; + + roundTrip('file:///path/to/file.txt'); + roundTrip('custom-scheme://my-path/to/resource.txt'); + roundTrip('custom-scheme://my-path'); + roundTrip('custom-scheme://my-path/'); + roundTrip('custom-scheme://my-path/?with=query¶ms=here'); + }); +}); From 0bbc5c88b6e7d04ece538e6dfbe0e3f667510b02 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 6 Jun 2025 22:28:41 -0700 Subject: [PATCH 109/236] mcp: adopt finalized completions API, support resolved args for prompts too (#250909) Refs https://github.com/microsoft/vscode/issues/248418 --- .../mcp/browser/mcpPromptArgumentPick.ts | 17 +++++++++----- .../workbench/contrib/mcp/common/mcpServer.ts | 9 +++++--- .../mcp/common/mcpServerRequestHandler.ts | 4 ++-- .../workbench/contrib/mcp/common/mcpTypes.ts | 2 +- .../mcp/common/modelContextProtocol.ts | 22 ++++++++++--------- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/contrib/mcp/browser/mcpPromptArgumentPick.ts b/src/vs/workbench/contrib/mcp/browser/mcpPromptArgumentPick.ts index de7a0805a19..8d57bf010a0 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpPromptArgumentPick.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpPromptArgumentPick.ts @@ -82,7 +82,7 @@ export class McpPromptArgumentPick extends Disposable { quickPick.activeItems = restore?.activeItems ?? []; quickPick.buttons = i > 0 ? [this._quickInputService.backButton] : []; - const value = await this._getArg(arg, !!restore, token); + const value = await this._getArg(arg, !!restore, args, token); if (value.type === 'back') { i -= 2; } else if (value.type === 'cancel') { @@ -102,7 +102,7 @@ export class McpPromptArgumentPick extends Disposable { return args; } - private async _getArg(arg: MCP.PromptArgument, didRestoreState: boolean, token?: CancellationToken): Promise { + private async _getArg(arg: MCP.PromptArgument, didRestoreState: boolean, argsSoFar: Record, token?: CancellationToken): Promise { const { quickPick } = this; const store = new DisposableStore(); @@ -110,7 +110,7 @@ export class McpPromptArgumentPick extends Disposable { const asyncPicks = [ { name: localize('mcp.arg.suggestions', 'Suggestions'), - observer: this._promptCompletions(arg, input$), + observer: this._promptCompletions(arg, input$, argsSoFar), }, { name: localize('mcp.arg.files', 'Files'), @@ -218,9 +218,16 @@ export class McpPromptArgumentPick extends Disposable { } } - private _promptCompletions(arg: MCP.PromptArgument, input: IObservable) { + private _promptCompletions(arg: MCP.PromptArgument, input: IObservable, argsSoFar: Record) { + const alreadyResolved: Record = {}; + for (const [key, value] of Object.entries(argsSoFar)) { + if (value) { + alreadyResolved[key] = value; + } + } + return this._asyncCompletions(input, async (i, t) => { - const items = await this.prompt.complete(arg.name, i, t); + const items = await this.prompt.complete(arg.name, i, alreadyResolved, t); return items.map((i): PickItem => ({ id: `suggest:${i}`, label: i, action: 'suggest' })); }); } diff --git a/src/vs/workbench/contrib/mcp/common/mcpServer.ts b/src/vs/workbench/contrib/mcp/common/mcpServer.ts index 291c9e8fcf9..43660f303fa 100644 --- a/src/vs/workbench/contrib/mcp/common/mcpServer.ts +++ b/src/vs/workbench/contrib/mcp/common/mcpServer.ts @@ -668,10 +668,11 @@ class McpPrompt implements IMcpPrompt { return result.messages; } - async complete(argument: string, prefix: string, token?: CancellationToken): Promise { + async complete(argument: string, prefix: string, alreadyResolved: Record, token?: CancellationToken): Promise { const result = await McpServer.callOn(this._server, h => h.complete({ ref: { type: 'ref/prompt', name: this._definition.name }, - argument: { name: argument, value: prefix, } + argument: { name: argument, value: prefix }, + context: { arguments: alreadyResolved }, }, token), token); return result.completion.values; } @@ -849,7 +850,9 @@ class McpResourceTemplate implements IMcpResourceTemplate { const result = await McpServer.callOn(this._server, h => h.complete({ ref: { type: 'ref/resource', uri: this._definition.uriTemplate }, argument: { name: templatePart, value: prefix }, - resolved: mapValues(alreadyResolved, v => Array.isArray(v) ? v.join('/') : v), + context: { + arguments: mapValues(alreadyResolved, v => Array.isArray(v) ? v.join('/') : v), + }, }, token), token); return result.completion.values; } diff --git a/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts b/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts index aea97239ad0..8ac57508ac9 100644 --- a/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts +++ b/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts @@ -521,7 +521,7 @@ export class McpServerRequestHandler extends Disposable { /** * Find completions for an argument */ - complete(params: MCP.CompleteRequest2['params'], token?: CancellationToken): Promise { - return this.sendRequest({ method: 'completion/complete', params }, token); + complete(params: MCP.CompleteRequest['params'], token?: CancellationToken): Promise { + return this.sendRequest({ method: 'completion/complete', params }, token); } } diff --git a/src/vs/workbench/contrib/mcp/common/mcpTypes.ts b/src/vs/workbench/contrib/mcp/common/mcpTypes.ts index 768d58bc2cf..69c2a62680d 100644 --- a/src/vs/workbench/contrib/mcp/common/mcpTypes.ts +++ b/src/vs/workbench/contrib/mcp/common/mcpTypes.ts @@ -330,7 +330,7 @@ export interface IMcpPrompt { readonly arguments: readonly MCP.PromptArgument[]; /** Gets string completions for the given prompt part. */ - complete(argument: string, prefix: string, token: CancellationToken): Promise; + complete(argument: string, prefix: string, alreadyResolved: Record, token: CancellationToken): Promise; resolve(args: Record, token?: CancellationToken): Promise; } diff --git a/src/vs/workbench/contrib/mcp/common/modelContextProtocol.ts b/src/vs/workbench/contrib/mcp/common/modelContextProtocol.ts index 03e6a47b8c6..2e4a4974794 100644 --- a/src/vs/workbench/contrib/mcp/common/modelContextProtocol.ts +++ b/src/vs/workbench/contrib/mcp/common/modelContextProtocol.ts @@ -14,16 +14,8 @@ */ export namespace MCP { - // https://github.com/modelcontextprotocol/modelcontextprotocol/pull/598 - export interface CompleteRequest2 extends MCP.CompleteRequest { - params: MCP.CompleteRequest['params'] & { - /** - * Previously-resolved variables in a URI template. The keys of the object - * are be the template's variable expressions including surrounding braces. - */ - resolved?: { [key: string]: string }; - }; - } + // Nothing, yet + } //#endregion @@ -1144,6 +1136,16 @@ export namespace MCP { */ value: string; }; + + /** + * Additional, optional context for completions + */ + context?: { + /** + * Previously-resolved variables in a URI template or prompt. + */ + arguments?: { [key: string]: string }; + }; }; } From 73f8b07e4ec89824cad8f103b4aab794a12a1213 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 6 Jun 2025 22:29:57 -0700 Subject: [PATCH 110/236] Add setting to skip word counting/render smoothing (#250912) --- src/vs/base/common/event.ts | 2 +- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 7 +++++-- src/vs/workbench/contrib/chat/browser/chatWidget.ts | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index bd0fc90ee3d..5ec4c00022b 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -325,7 +325,7 @@ export namespace Event { * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. */ - export function accumulate(event: Event, delay: number = 0, disposable?: DisposableStore): Event { + export function accumulate(event: Event, delay: number | typeof MicrotaskDelay = 0, disposable?: DisposableStore): Event { return Event.debounce(event, (last, e) => { if (!last) { return [e]; diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index f7e8a3d7012..68378263466 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -168,7 +168,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer('chat.experimental.renderMarkdownImmediately') === true; + const renderableResponse = annotateSpecialMarkdownContent(element.response.value); this.traceLayout('getNextProgressiveRenderContent', `Want to render ${data.numWordsToRender} at ${data.rate} words/s, counting...`); @@ -811,7 +814,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { + const renderImmediately = this.configurationService.getValue('chat.experimental.renderMarkdownImmediately') === true; + const delay = renderImmediately ? MicrotaskDelay : 0; + this.viewModelDisposables.add(Event.runAndSubscribe(Event.accumulate(this.viewModel.onDidChange, delay), (events => { if (!this.viewModel) { return; } From 8cff3fed9becee07b0da0a491aef4a44aeaa75af Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Sat, 7 Jun 2025 14:52:15 +0200 Subject: [PATCH 111/236] use export function x(...) instead of export const x (#250927) --- .../promptSyntax/attachInstructionsAction.ts | 8 ++-- .../browser/promptSyntax/chatModeActions.ts | 8 ++-- .../promptSyntax/saveToPromptAction.ts | 48 +++++++------------ .../frontMatterRecord/frontMatterRecord.ts | 6 +-- .../codecs/base/utils/objectStream.ts | 4 +- .../base/utils/objectStreamFromTextModel.ts | 6 +-- .../promptHeaderDiagnosticsProvider.ts | 6 +-- .../promptLinkDiagnosticsProvider.ts | 6 +-- .../promptPathAutocompletion.ts | 7 +-- .../providerInstanceManagerBase.ts | 12 ++--- .../promptSyntax/parsers/promptParser.ts | 8 ++-- .../promptSyntax/promptFileContributions.ts | 4 +- .../service/promptsServiceImpl.ts | 32 ++++--------- .../promptSyntax/utils/promptFilesLocator.ts | 21 +++----- .../common/promptSyntax/utils/treeUtils.ts | 32 +++++-------- .../codecs/base/testUtils/randomRange.ts | 13 ++--- .../codecs/base/testUtils/randomTokens.ts | 14 ++---- .../codecs/base/tokens/baseToken.test.ts | 4 +- .../codecs/base/utils/objectStream.test.ts | 10 ++-- .../common/promptSyntax/config/config.test.ts | 4 +- .../promptSyntax/promptFileReference.test.ts | 6 +-- .../service/promptsService.test.ts | 6 +-- .../testUtils/mockFilesystem.test.ts | 12 ++--- .../utils/promptFilesLocator.test.ts | 8 ++-- 24 files changed, 107 insertions(+), 178 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts index 48d57addab3..17839752416 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts @@ -197,22 +197,22 @@ function getFocusedChatWidget(accessor: ServicesAccessor): IChatWidget | undefin /** * Gets `URI` of a instructions file open in an active editor instance, if any. */ -const getActiveInstructionsFileUri = (accessor: ServicesAccessor): URI | undefined => { +function getActiveInstructionsFileUri(accessor: ServicesAccessor): URI | undefined { const codeEditorService = accessor.get(ICodeEditorService); const model = codeEditorService.getActiveCodeEditor()?.getModel(); if (model?.getLanguageId() === INSTRUCTIONS_LANGUAGE_ID) { return model.uri; } return undefined; -}; +} /** * Helper to register the `Attach Prompt` action. */ -export const registerAttachPromptActions = () => { +export function registerAttachPromptActions(): void { registerAction2(AttachInstructionsAction); registerAction2(ManageInstructionsFilesAction); -}; +} export class ChatInstructionsPickerPick implements IChatContextPickerItem { diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts index 20a976612c3..45668199fe3 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts @@ -46,9 +46,7 @@ class ManageModeAction extends Action2 { }); } - public override async run( - accessor: ServicesAccessor, - ): Promise { + public override async run(accessor: ServicesAccessor): Promise { const openerService = accessor.get(IOpenerService); const instaService = accessor.get(IInstantiationService); @@ -69,6 +67,6 @@ class ManageModeAction extends Action2 { /** * Helper to register all the `Run Current Prompt` actions. */ -export const registerChatModeActions = () => { +export function registerChatModeActions(): void { registerAction2(ManageModeAction); -}; +} diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts index 39c7c0c21b6..d6d84c1f750 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/saveToPromptAction.ts @@ -139,9 +139,7 @@ class SaveToPromptAction extends Action2 { * Check if provided message belongs to the `save to prompt` slash * command itself that was run in the chat to invoke this action. */ -const isSaveToPromptSlashCommand = ( - message: IParsedChatRequest, -): boolean => { +function isSaveToPromptSlashCommand(message: IParsedChatRequest): boolean { const { parts } = message; if (parts.length < 1) { return false; @@ -157,14 +155,12 @@ const isSaveToPromptSlashCommand = ( } return true; -}; +} /** * Render the response part of a `request`/`response` turn pair. */ -const renderResponse = ( - response: string, -): string => { +function renderResponse(response: string): string { // if response starts with a code block, add an extra new line // before it, to prevent full blockquote from being be broken const delimiter = (response.startsWith('```')) @@ -176,25 +172,21 @@ const renderResponse = ( const quotedResponse = response.replaceAll('\n', '\n> '); return `> Copilot:${delimiter}${quotedResponse}`; -}; +} /** * Render a single `request`/`response` turn of the chat session. */ -const renderTurn = ( - turn: ITurn, -): string => { +function renderTurn(turn: ITurn): string { const { request, response } = turn; return `\n${request}\n\n${renderResponse(response)}`; -}; +} /** * Render the entire chat session as a markdown prompt. */ -const renderPrompt = ( - turns: readonly ITurn[], -): string => { +function renderPrompt(turns: readonly ITurn[]): string { const content: string[] = []; const allTools = new Set(); @@ -225,28 +217,24 @@ const renderPrompt = ( result.push(''); return result.join('\n'); -}; +} /** * Render the `tools` metadata inside prompt header. */ -const renderTools = ( - tools: Set, -): string => { +function renderTools(tools: Set): string { const toolStrings = [...tools].map((tool) => { return `'${tool}'`; }); return `tools: [${toolStrings.join(', ')}]`; -}; +} /** * Render prompt header. */ -const renderHeader = ( - tools: Set, -): string => { +function renderHeader(tools: Set): string { // skip rendering the header if no tools provided if (tools.size === 0) { return ''; @@ -257,7 +245,7 @@ const renderHeader = ( renderTools(tools), '---', ].join('\n'); -}; +} /** * Interface for a single `request`/`response` turn @@ -274,19 +262,19 @@ interface ITurn { * function instead of {@link SAVE_TO_PROMPT_ACTION_ID} directly to * encapsulate/enforce the correct options to be passed to the action. */ -export const runSaveToPromptAction = async ( +export function runSaveToPromptAction( options: ISaveToPromptActionOptions, commandService: ICommandService, -) => { - return await commandService.executeCommand( +) { + return commandService.executeCommand( SAVE_TO_PROMPT_ACTION_ID, options, ); -}; +} /** * Helper to register all the `Save Prompt` actions. */ -export const registerSaveToPromptActions = () => { +export function registerSaveToPromptActions(): void { registerAction2(SaveToPromptAction); -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts index 0db69a34c0e..5ea54b01045 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts @@ -199,12 +199,10 @@ export class PartialFrontMatterRecord extends ParserBase { +function shouldEndTokenSequence(token: BaseToken): token is (NewLine | CarriageReturn | FormFeed) { return ( (token instanceof NewLine) || (token instanceof CarriageReturn) || (token instanceof FormFeed) ); -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStream.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStream.ts index 97d4460b67c..3c8476c2d56 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStream.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStream.ts @@ -215,10 +215,10 @@ export class ObjectStream extends ObservableDisposable impleme /** * Create a generator out of a provided array. */ -export const arrayToGenerator = >(array: T[]): Generator => { +export function arrayToGenerator>(array: T[]): Generator { return (function* (): Generator { for (const item of array) { yield item; } })(); -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.ts index d6083071c5f..2a9b2173b5d 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/utils/objectStreamFromTextModel.ts @@ -21,9 +21,7 @@ export function objectStreamFromTextModel( /** * Create a generator out of a provided text model. */ -const modelToGenerator = ( - model: ITextModel, -): Generator => { +function modelToGenerator(model: ITextModel): Generator { return (function* (): Generator { const totalLines = model.getLineCount(); let currentLine = 1; @@ -45,4 +43,4 @@ const modelToGenerator = ( currentLine++; } })(); -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderDiagnosticsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderDiagnosticsProvider.ts index 6743bf70277..8ff0daf07b4 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderDiagnosticsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderDiagnosticsProvider.ts @@ -80,9 +80,7 @@ class PromptHeaderDiagnosticsProvider extends ProviderInstanceBase { /** * Convert a provided diagnostic object into a marker data object. */ -const toMarker = ( - diagnostic: TDiagnostic, -): IMarkerData => { +function toMarker(diagnostic: TDiagnostic): IMarkerData { if (diagnostic instanceof PromptMetadataWarning) { return { message: diagnostic.message, @@ -103,7 +101,7 @@ const toMarker = ( diagnostic, `Unknown prompt metadata diagnostic type '${diagnostic}'.`, ); -}; +} /** * The class that manages creation and disposal of {@link PromptHeaderDiagnosticsProvider} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkDiagnosticsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkDiagnosticsProvider.ts index 2d8f8902aae..0c7dab432bd 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkDiagnosticsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkDiagnosticsProvider.ts @@ -83,9 +83,7 @@ class PromptLinkDiagnosticsProvider extends ProviderInstanceBase { * - if the original error is of `NotPromptFile` type - we don't want to * show diagnostic markers for non-prompt file links in the prompts */ -const toMarker = ( - link: IPromptFileReference, -): IMarkerData => { +function toMarker(link: IPromptFileReference): IMarkerData { const { topError, linkRange } = link; // a sanity check because this function must be @@ -115,7 +113,7 @@ const toMarker = ( severity, ...linkRange, }; -}; +} /** * The class that manages creation and disposal of {@link PromptLinkDiagnosticsProvider} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts index 4a7f7c4be51..956cd5a6888 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts @@ -51,10 +51,7 @@ type TTriggerCharacter = ':' | '.' | '/'; /** * Finds a file reference that suites the provided `position`. */ -const findFileReference = ( - references: readonly TPromptReference[], - position: Position, -): IPromptFileReference | undefined => { +function findFileReference(references: readonly TPromptReference[], position: Position): IPromptFileReference | undefined { for (const reference of references) { const { range } = reference; @@ -78,7 +75,7 @@ const findFileReference = ( } return undefined; -}; +} /** * Provides reference paths autocompletion for the `#file:` variables inside prompts. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceManagerBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceManagerBase.ts index 51a50e801d1..36ff2339b49 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceManagerBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/providerInstanceManagerBase.ts @@ -147,22 +147,18 @@ export abstract class ProviderInstanceManagerBase { +function isPromptFile(languageId: string): boolean { return [ PROMPT_LANGUAGE_ID, INSTRUCTIONS_LANGUAGE_ID, MODE_LANGUAGE_ID, ].includes(languageId); -}; +} /** * Check if a provided model is used for prompt files. */ -const isPromptFileModel = ( - model: IEditorModel, -): model is ITextModel => { +function isPromptFileModel(model: IEditorModel): model is ITextModel { // we support only `text editors` for now so filter out `diff` ones if ('modified' in model || 'model' in model) { return false; @@ -177,4 +173,4 @@ const isPromptFileModel = ( } return true; -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts index 0d336cb5609..3e7aad075df 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptParser.ts @@ -18,12 +18,12 @@ import { Schemas } from '../../../../../../base/common/network.js'; /** * Get prompt contents provider object based on the prompt type. */ -const getContentsProvider = ( +function getContentsProvider( uri: URI, options: Partial, modelService: IModelService, - instaService: IInstantiationService, -): IPromptContentsProvider => { + instaService: IInstantiationService +): IPromptContentsProvider { // use text model contents provider for `untitled` documents if (uri.scheme === Schemas.untitled) { const model = modelService.getModel(uri); @@ -39,7 +39,7 @@ const getContentsProvider = ( return instaService .createInstance(FilePromptContentProvider, uri, options); -}; +} /** * General prompt parser class that automatically infers a prompt diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts index 5521717d439..9e277049e46 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.ts @@ -17,7 +17,7 @@ import { PromptPathAutocompletion } from './languageProviders/promptPathAutocomp /** * Function that registers all prompt-file related contributions. */ -export const registerPromptFileContributions = (): void => { +export function registerPromptFileContributions(): void { // all language constributions @@ -45,7 +45,7 @@ export const registerPromptFileContributions = (): void => { } registerContribution(ConfigMigration); -}; +} /** * Type for a generic workbench contribution. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts index 22fe4bb7daa..2c7dd5e5030 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts @@ -109,9 +109,7 @@ export class PromptsService extends Disposable implements IPromptsService { * - newly created parser is disposed immediately on initialization. * See factory function in the {@link constructor} for more info. */ - public getSyntaxParserFor( - model: ITextModel, - ): TextModelPromptParser & { isDisposed: false } { + public getSyntaxParserFor(model: ITextModel): TextModelPromptParser & { isDisposed: false } { assert( model.isDisposed() === false, 'Cannot create a prompt syntax parser for a disposed model.', @@ -232,9 +230,7 @@ export class PromptsService extends Disposable implements IPromptsService { return metadataList; } - public async findInstructionFilesFor( - files: readonly URI[], - ): Promise { + public async findInstructionFilesFor(files: readonly URI[]): Promise { const instructionFiles = await this.listPromptFiles(PromptsType.instructions, CancellationToken.None); if (instructionFiles.length === 0) { return []; @@ -297,9 +293,7 @@ export class PromptsService extends Disposable implements IPromptsService { return metaDatas[0]; } - public async getAllMetadata( - promptUris: readonly URI[], - ): Promise { + public async getAllMetadata(promptUris: readonly URI[]): Promise { const metadata = await Promise.all( promptUris.map(async (uri) => { let parser: PromptParser | undefined; @@ -327,9 +321,7 @@ export class PromptsService extends Disposable implements IPromptsService { * Collect all metadata from prompt file references * into a single hierarchical tree structure. */ -const collectMetadata = ( - reference: Pick, -): IMetadata => { +function collectMetadata(reference: Pick): IMetadata { const childMetadata = []; for (const child of reference.references) { if (child.errorCondition !== undefined) { @@ -348,7 +340,7 @@ const collectMetadata = ( metadata: reference.metadata, children, }; -}; +} export function getPromptCommandName(path: string): string { const name = basename(path, PROMPT_FILE_EXTENSION); @@ -359,24 +351,18 @@ export function getPromptCommandName(path: string): string { * Utility to add a provided prompt `storage` and * `type` attributes to a prompt URI. */ -const addType = ( - storage: TPromptsStorage, - type: PromptsType, -): (uri: URI) => IPromptPath => { +function addType(storage: TPromptsStorage, type: PromptsType): (uri: URI) => IPromptPath { return (uri) => { return { uri, storage, type }; }; -}; +} /** * Utility to add a provided prompt `type` to a list of prompt URIs. */ -const withType = ( - storage: TPromptsStorage, - type: PromptsType, -): (uris: readonly URI[]) => (readonly IPromptPath[]) => { +function withType(storage: TPromptsStorage, type: PromptsType): (uris: readonly URI[]) => (readonly IPromptPath[]) { return (uris) => { return uris .map(addType(storage, type)); }; -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts index dc52b01653f..fc1c7ab16be 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts @@ -141,10 +141,7 @@ export class PromptFilesLocator extends Disposable { * * @returns List of prompt files found in the local source folders. */ - private async listFilesInLocal( - type: PromptsType, - token: CancellationToken - ): Promise { + private async listFilesInLocal(type: PromptsType, token: CancellationToken): Promise { // find all prompt files in the provided locations, then match // the found file paths against (possible) glob patterns const paths = new ResourceSet(); @@ -232,11 +229,7 @@ export class PromptFilesLocator extends Disposable { /** * Uses the search service to find all files at the provided location */ - private async searchFilesInLocation( - folder: URI, - filePattern: string | undefined, - token: CancellationToken | undefined - ): Promise { + private async searchFilesInLocation(folder: URI, filePattern: string | undefined, token: CancellationToken | undefined): Promise { const disregardIgnoreFiles = this.configService.getValue('explorer.excludeGitIgnore'); const workspaceRoot = this.workspaceService.getWorkspaceFolder(folder); @@ -272,7 +265,7 @@ export class PromptFilesLocator extends Disposable { /** * Checks if the provided `pattern` could be a valid glob pattern. */ -export const isValidGlob = (pattern: string): boolean => { +export function isValidGlob(pattern: string): boolean { let squareBrackets = false; let squareBracketsCount = 0; @@ -337,7 +330,7 @@ export const isValidGlob = (pattern: string): boolean => { } return false; -}; +} /** * Finds the first parent of the provided location that does not contain a `glob pattern`. @@ -354,9 +347,7 @@ export const isValidGlob = (pattern: string): boolean => { * ); * ``` */ -const firstNonGlobParentAndPattern = ( - location: URI -): { parent: URI; filePattern?: string } => { +function firstNonGlobParentAndPattern(location: URI): { parent: URI; filePattern?: string } { const segments = location.path.split('/'); let i = 0; while (i < segments.length && isValidGlob(segments[i]) === false) { @@ -377,7 +368,7 @@ const firstNonGlobParentAndPattern = ( parent, filePattern: segments.slice(i).join('/') }; -}; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/treeUtils.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/treeUtils.ts index 551ba3beda8..b050a59a387 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/treeUtils.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/treeUtils.ts @@ -13,9 +13,7 @@ export type TTree = { children?: readonly TTree[] } & TT /** * Flatter a tree structure into a single flat array. */ -export const flatten = ( - treeRoot: TTree, -): TTreeNode[] => { +export function flatten(treeRoot: TTree): TTreeNode[] { const result: TTreeNode[] = []; result.push(treeRoot); @@ -25,15 +23,12 @@ export const flatten = ( } return result; -}; +} /** * Traverse a tree structure and execute a callback for each node. */ -export const forEach = ( - callback: (node: TTreeNode) => boolean, - treeRoot: TTree, -): ReturnType => { +export function forEach(callback: (node: TTreeNode) => boolean, treeRoot: TTree): ReturnType { const shouldStop = callback(treeRoot); if (shouldStop === true) { @@ -49,7 +44,7 @@ export const forEach = ( } return false; -}; +} /** * Maps nodes of a tree to a new type preserving the original tree structure by invoking @@ -91,16 +86,16 @@ export const forEach = ( * }); * ``` */ -export const map = < +export function map< TTreeNode extends object, - TNewTreeNode extends object, + TNewTreeNode extends object >( callback: ( originalNode: Readonly>, newChildren: Readonly[] | undefined, ) => TTree, treeRoot: TTree, -): TTree => { +): TTree { // if the node does not have children, just call the callback if (treeRoot.children === undefined) { return callback(treeRoot, undefined); @@ -123,7 +118,7 @@ export const map = < newNode.children = newChildren; return newNode; -}; +} /** * Type for a generic comparable object - the one that implements @@ -188,10 +183,7 @@ type TDiffTree = TTree & { * of the same type. The result is another tree of difference * nodes that represent difference between tree node pairs. */ -export function difference>( - tree1: TTree>, - tree2: TTree>, -): TDiffTree | null { +export function difference>(tree1: TTree>, tree2: TTree>): TDiffTree | null { const tree1Children = tree1.children ?? []; const tree2Children = tree2.children ?? []; @@ -276,11 +268,11 @@ type TCurriedFunction unknown> = ((...args: TRestP /** * Curry a provided function with the first argument. */ -export const curry = ( +export function curry( callback: (arg1: T, ...args: any[]) => K, arg1: T, -): TCurriedFunction => { +): TCurriedFunction { return (...args) => { return callback(arg1, ...args); }; -}; +} diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomRange.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomRange.ts index fbc57ef73a7..db00f6920d7 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomRange.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomRange.ts @@ -14,9 +14,7 @@ import { randomBoolean } from '../../../../../../../../../base/test/common/testU * @throws if {@link maxNumber} argument is less than `2`, * is equal to `NaN` or is `infinite`. */ -export const randomRange = ( - maxNumber: number = 1_000, -): Range => { +export function randomRange(maxNumber: number = 1_000): Range { assert( maxNumber > 1, `Max number must be greater than 1, got '${maxNumber}'.`, @@ -38,16 +36,13 @@ export const randomRange = ( endLineNumber, endColumnNumber, ); -}; +} /** * Generates a random {@link Range} object that is different * from the provided one. */ -export const randomRangeNotEqualTo = ( - differentFrom: Range, - maxTries: number = 10, -): Range => { +export function randomRangeNotEqualTo(differentFrom: Range, maxTries: number = 10): Range { let retriesLeft = maxTries; while (retriesLeft-- > 0) { @@ -60,4 +55,4 @@ export const randomRangeNotEqualTo = ( throw new Error( `Failed to generate a random range different from '${differentFrom}' in ${maxTries} tries.`, ); -}; +} diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomTokens.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomTokens.ts index 89bfd64afa7..dedd2340c5e 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomTokens.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/testUtils/randomTokens.ts @@ -19,9 +19,7 @@ type TToken = NewLine | Space | Word | Text; /** * Test utility to clone a list of provided tokens. */ -export const cloneTokens = ( - tokens: TToken[], -): TToken[] => { +export function cloneTokens(tokens: TToken[]): TToken[] { const clonedTokens: TToken[] = []; for (const token of tokens) { @@ -65,16 +63,12 @@ export const cloneTokens = ( } return clonedTokens; -}; +} /** * Test utility to generate a number of random tokens. */ -export const randomTokens = ( - tokenCount: number = randomInt(20, 10), - startLine: number = randomInt(100, 1), - startColumn: number = randomInt(100, 1), -): TToken[] => { +export function randomTokens(tokenCount: number = randomInt(20, 10), startLine: number = randomInt(100, 1), startColumn: number = randomInt(100, 1)): TToken[] { const tokens = []; let tokensLeft = tokenCount; @@ -149,4 +143,4 @@ export const randomTokens = ( } return tokens; -}; +} diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/baseToken.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/baseToken.test.ts index 448cd3d439a..9d5975579e0 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/baseToken.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/tokens/baseToken.test.ts @@ -30,7 +30,7 @@ const TOKENS: readonly ISimpleTokenClass[] = Object.freeze([ /** * Generates a random {@link SimpleToken} instance. */ -const randomSimpleToken = (): TSimpleToken => { +function randomSimpleToken(): TSimpleToken { const index = randomInt(TOKENS.length - 1); const Constructor = TOKENS[index]; @@ -40,7 +40,7 @@ const randomSimpleToken = (): TSimpleToken => { ); return new Constructor(randomRange()); -}; +} suite('BaseToken', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/objectStream.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/objectStream.test.ts index bcbd12424e6..8ae36566247 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/objectStream.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/codecs/base/utils/objectStream.test.ts @@ -141,10 +141,10 @@ suite('ObjectStream', () => { /** * Asserts that two tokens lists are equal. */ -const assertTokensEqual = ( +function assertTokensEqual( receivedTokens: BaseToken[], expectedTokens: BaseToken[], -): void => { +): void { for (let i = 0; i < expectedTokens.length; i++) { const receivedToken = receivedTokens[i]; @@ -158,12 +158,12 @@ const assertTokensEqual = ( `Expected token #${i} to be '${expectedTokens[i]}', got '${receivedToken}'.`, ); } -}; +} /** * Consume a provided stream and return a list of received data objects. */ -const consume = (stream: ObjectStream): Promise => { +function consume(stream: ObjectStream): Promise { return new Promise((resolve, reject) => { const receivedData: T[] = []; stream.on('data', (token) => { @@ -177,4 +177,4 @@ const consume = (stream: ObjectStream): Promise => { reject(error); }); }); -}; +} diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts index de0d5fce8a4..2ac76531de2 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/config/config.test.ts @@ -14,7 +14,7 @@ import { IConfigurationOverrides, IConfigurationService } from '../../../../../. /** * Mocked instance of {@link IConfigurationService}. */ -const createMock = (value: T): IConfigurationService => { +function createMock(value: T): IConfigurationService { return mockService({ getValue(key?: string | IConfigurationOverrides) { assert( @@ -30,7 +30,7 @@ const createMock = (value: T): IConfigurationService => { return value; }, }); -}; +} suite('PromptsConfig', () => { ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts index a8f6cc657f3..6c32ad7c098 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/promptFileReference.test.ts @@ -201,11 +201,11 @@ class TestPromptFileReference extends Disposable { * @param lineNumber The expected line number of the file reference. * @param startColumnNumber The expected start column number of the file reference. */ -const createTestFileReference = ( +function createTestFileReference( filePath: string, lineNumber: number, startColumnNumber: number, -): FileReference => { +): FileReference { const range = new Range( lineNumber, startColumnNumber, @@ -214,7 +214,7 @@ const createTestFileReference = ( ); return new FileReference(range, filePath); -}; +} suite('PromptFileReference', function () { const testDisposables = ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts index 8620c1e43b5..a3d8385568a 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts @@ -79,10 +79,10 @@ class ExpectedLink { * @param links Links to assert. * @param expectedLinks Expected links to compare against. */ -const assertLinks = ( +function assertLinks( links: readonly IPromptFileReference[], expectedLinks: readonly ExpectedLink[], -) => { +) { for (let i = 0; i < links.length; i++) { try { expectedLinks[i].assertEqual(links[i]); @@ -96,7 +96,7 @@ const assertLinks = ( expectedLinks.length, `Links count must be correct.`, ); -}; +} suite('PromptsService', () => { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts index 4d1fb9178fd..097af623225 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts @@ -46,11 +46,11 @@ interface IExpectedFolder extends IExpectedFilesystemNode { /** * Validates that file at {@link filePath} has expected attributes. */ -const validateFile = async ( +async function validateFile( filePath: string, expectedFile: IExpectedFile, fileService: IFileService, -) => { +) { let readFile: IFileStat | undefined; try { readFile = await fileService.resolve(URI.file(filePath)); @@ -100,16 +100,16 @@ const validateFile = async ( expectedFile.contents, `File '${expectedFile.resource.fsPath}' must have correct contents.`, ); -}; +} /** * Validates that folder at {@link folderPath} has expected attributes. */ -const validateFolder = async ( +async function validateFolder( folderPath: string, expectedFolder: IExpectedFolder, fileService: IFileService, -) => { +): Promise { let readFolder: IFileStat | undefined; try { readFolder = await fileService.resolve(URI.file(folderPath)); @@ -177,7 +177,7 @@ const validateFolder = async ( fileService, ); } -}; +} suite('MockFilesystem', () => { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts index 849a8b5b34f..61643956c62 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/utils/promptFilesLocator.test.ts @@ -30,7 +30,7 @@ import { mockService } from './mock.js'; /** * Mocked instance of {@link IConfigurationService}. */ -const mockConfigService = (value: T): IConfigurationService => { +function mockConfigService(value: T): IConfigurationService { return mockService({ getValue(key?: string | IConfigurationOverrides) { assert( @@ -49,12 +49,12 @@ const mockConfigService = (value: T): IConfigurationService => { return value; }, }); -}; +} /** * Mocked instance of {@link IWorkspaceContextService}. */ -const mockWorkspaceService = (folders: IWorkspaceFolder[]): IWorkspaceContextService => { +function mockWorkspaceService(folders: IWorkspaceFolder[]): IWorkspaceContextService { return mockService({ getWorkspace(): IWorkspace { return new class extends mock() { @@ -66,7 +66,7 @@ const mockWorkspaceService = (folders: IWorkspaceFolder[]): IWorkspaceContextSer } }); -}; +} suite('PromptFilesLocator', () => { const disposables = ensureNoDisposablesAreLeakedInTestSuite(); From c91a39755394a86d27bebad9948732a0ed2a3ade Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 7 Jun 2025 18:54:36 +0200 Subject: [PATCH 112/236] debt - improve type and layer checking (#250926) --- build/checker/layersChecker.js | 195 +--------------- build/checker/layersChecker.ts | 213 +----------------- ...sconfig.web.json => tsconfig.browser.json} | 0 build/checker/tsconfig.electron-main.json | 13 ++ ...op.json => tsconfig.electron-sandbox.json} | 2 +- ...sconfig.server.json => tsconfig.node.json} | 0 package.json | 2 +- src/vs/amdX.ts | 27 ++- src/vs/base/common/async.ts | 5 +- src/vs/base/common/buffer.ts | 17 +- src/vs/base/common/performance.ts | 23 +- src/vs/base/common/stopwatch.ts | 2 - src/vs/base/parts/ipc/common/ipc.ts | 5 +- src/vs/nls.ts | 1 + .../node/sharedWebContentExtractorService.ts | 2 +- .../webviewView/browser/webviewViewPane.ts | 2 - 16 files changed, 79 insertions(+), 430 deletions(-) rename build/checker/{tsconfig.web.json => tsconfig.browser.json} (100%) create mode 100644 build/checker/tsconfig.electron-main.json rename build/checker/{tsconfig.desktop.json => tsconfig.electron-sandbox.json} (95%) rename build/checker/{tsconfig.server.json => tsconfig.node.json} (100%) diff --git a/build/checker/layersChecker.js b/build/checker/layersChecker.js index 3825d3b4308..0c30e64baa0 100644 --- a/build/checker/layersChecker.js +++ b/build/checker/layersChecker.js @@ -15,88 +15,14 @@ const minimatch_1 = require("minimatch"); // ############################################################################################# // // A custom typescript checker for the specific task of detecting the use of certain types in a -// layer that does not allow such use. For example: -// - using DOM globals in common/node/electron-main layer (e.g. HTMLElement) -// - using node.js globals in common/browser layer (e.g. process) +// layer that does not allow such use. // // Make changes to below RULES to lift certain files from these checks only if absolutely needed // +// NOTE: Most layer checks are done via tsconfig..json files. +// // ############################################################################################# // -// Types we assume are present in all implementations of JS VMs (node.js, browsers) -// Feel free to add more core types as you see needed if present in node.js and browsers -const CORE_TYPES = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'console', - 'Console', - 'Error', - 'ErrorConstructor', - 'String', - 'TextDecoder', - 'TextEncoder', - 'self', - 'queueMicrotask', - 'Array', - 'Uint8Array', - 'Uint16Array', - 'Uint32Array', - 'Int8Array', - 'Int16Array', - 'Int32Array', - 'Float32Array', - 'Float64Array', - 'Uint8ClampedArray', - 'BigUint64Array', - 'BigInt64Array', - 'btoa', - 'atob', - 'AbortController', - 'AbortSignal', - 'MessageChannel', - 'MessagePort', - 'URL', - 'URLSearchParams', - 'ReadonlyArray', - 'Event', - 'EventTarget', - 'BroadcastChannel', - 'performance', - 'Blob', - 'crypto', - 'File', - 'fetch', - 'RequestInit', - 'Headers', - 'Request', - 'Response', - 'Body', - 'any', - 'timeout', - 'Performance', - 'PerformanceMark', - 'PerformanceObserver', - 'ImportMeta', - 'structuredClone', - 'stackTraceLimit', - 'captureStackTrace', - // webcrypto has been available since Node.js 19, but still live in dom.d.ts - 'Crypto', - 'SubtleCrypto', - 'JsonWebKey', - 'MessageEvent', - // node web types - 'ReadableStream', - 'ReadableStreamReadResult', - 'ReadableStreamGenericReader', - 'ReadableStreamDefaultReader', - 'value', - 'done', - 'DOMException', - 'WebSocket', -]; // Types that are defined in a common layer but are known to be only // available in native environments should not be allowed in browser const NATIVE_TYPES = [ @@ -115,37 +41,6 @@ const RULES = [ target: '**/vs/**/test/**', skip: true // -> skip all test files }, - // Common: vs/base/common/async.ts - { - target: '**/vs/base/common/async.ts', - allowedTypes: [ - ...CORE_TYPES, - // Safe access to requestIdleCallback & cancelIdleCallback - 'requestIdleCallback', - 'cancelIdleCallback' - ], - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] - }, - // Common: vs/base/common/performance.ts - { - target: '**/vs/base/common/performance.ts', - allowedTypes: [ - ...CORE_TYPES, - // Safe access to Performance - 'Performance', - 'PerformanceEntry', - 'PerformanceTiming' - ], - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] - }, // Common: vs/platform services that can access native types { target: `**/vs/platform/{${[ @@ -156,75 +51,28 @@ const RULES = [ 'browserElements/common/browserElements.ts', 'browserElements/common/nativeBrowserElementsService.ts' ].join(',')}}`, - allowedTypes: CORE_TYPES, disallowedTypes: [ /* Ignore native types that are defined from here */], - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] }, // Common: vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts { target: '**/vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts', - allowedTypes: [ - ...CORE_TYPES, - // Safe access to a very small subset of node.js - 'process', - 'NodeJS', - '__global' - ], disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] }, // Common { target: '**/vs/**/common/**', - allowedTypes: CORE_TYPES, disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] }, // Browser { target: '**/vs/**/browser/**', - allowedTypes: [ - ...CORE_TYPES, - 'localStorage' - ], disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] - }, - // node.js - { - target: '**/vs/**/node/**', - allowedTypes: CORE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts' // no DOM - ] - }, - // Electron (sandbox) - { - target: '**/vs/**/electron-sandbox/**', - allowedTypes: CORE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] }, // Electron (main, utility) { target: '**/vs/**/{electron-main,electron-utility}/**', - allowedTypes: CORE_TYPES, disallowedTypes: [ 'ipcMain' // not allowed, use validatedIpcMain instead - ], - disallowedDefinitions: [ - 'lib.dom.d.ts' // no DOM ] } ]; @@ -242,55 +90,18 @@ function checkFile(program, sourceFile, rule) { return; } let text = symbol.getName(); - if (rule.allowedTypes?.some(allowed => allowed === text)) { - return; // override - } let _parentSymbol = symbol; while (_parentSymbol.parent) { _parentSymbol = _parentSymbol.parent; } const parentSymbol = _parentSymbol; text = parentSymbol.getName(); - if (rule.allowedTypes?.some(allowed => allowed === text)) { - return; // override - } if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); console.log(`[build/checker/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); hasErrors = true; return; } - const declarations = symbol.declarations; - if (Array.isArray(declarations)) { - DeclarationLoop: for (const declaration of declarations) { - if (declaration) { - const parent = declaration.parent; - if (parent) { - const parentSourceFile = parent.getSourceFile(); - if (parentSourceFile) { - const definitionFileName = parentSourceFile.fileName; - if (rule.allowedDefinitions) { - for (const allowedDefinition of rule.allowedDefinitions) { - if (definitionFileName.indexOf(allowedDefinition) >= 0) { - continue DeclarationLoop; - } - } - } - if (rule.disallowedDefinitions) { - for (const disallowedDefinition of rule.disallowedDefinitions) { - if (definitionFileName.indexOf(disallowedDefinition) >= 0) { - const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/checker/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); - hasErrors = true; - return; - } - } - } - } - } - } - } - } } } function createProgram(tsconfigPath) { diff --git a/build/checker/layersChecker.ts b/build/checker/layersChecker.ts index 02d5860066a..6337967b248 100644 --- a/build/checker/layersChecker.ts +++ b/build/checker/layersChecker.ts @@ -12,92 +12,15 @@ import { match } from 'minimatch'; // ############################################################################################# // // A custom typescript checker for the specific task of detecting the use of certain types in a -// layer that does not allow such use. For example: -// - using DOM globals in common/node/electron-main layer (e.g. HTMLElement) -// - using node.js globals in common/browser layer (e.g. process) +// layer that does not allow such use. // // Make changes to below RULES to lift certain files from these checks only if absolutely needed // +// NOTE: Most layer checks are done via tsconfig..json files. +// // ############################################################################################# // -// Types we assume are present in all implementations of JS VMs (node.js, browsers) -// Feel free to add more core types as you see needed if present in node.js and browsers -const CORE_TYPES = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'console', - 'Console', - 'Error', - 'ErrorConstructor', - 'String', - 'TextDecoder', - 'TextEncoder', - 'self', - 'queueMicrotask', - 'Array', - 'Uint8Array', - 'Uint16Array', - 'Uint32Array', - 'Int8Array', - 'Int16Array', - 'Int32Array', - 'Float32Array', - 'Float64Array', - 'Uint8ClampedArray', - 'BigUint64Array', - 'BigInt64Array', - 'btoa', - 'atob', - 'AbortController', - 'AbortSignal', - 'MessageChannel', - 'MessagePort', - 'URL', - 'URLSearchParams', - 'ReadonlyArray', - 'Event', - 'EventTarget', - 'BroadcastChannel', - 'performance', - 'Blob', - 'crypto', - 'File', - 'fetch', - 'RequestInit', - 'Headers', - 'Request', - 'Response', - 'Body', - 'any', - 'timeout', - 'Performance', - 'PerformanceMark', - 'PerformanceObserver', - 'ImportMeta', - 'structuredClone', - 'stackTraceLimit', - 'captureStackTrace', - - // webcrypto has been available since Node.js 19, but still live in dom.d.ts - 'Crypto', - 'SubtleCrypto', - 'JsonWebKey', - 'MessageEvent', - - // node web types - 'ReadableStream', - 'ReadableStreamReadResult', - 'ReadableStreamGenericReader', - 'ReadableStreamDefaultReader', - 'value', - 'done', - 'DOMException', - 'WebSocket', -]; - // Types that are defined in a common layer but are known to be only // available in native environments should not be allowed in browser const NATIVE_TYPES = [ @@ -119,41 +42,6 @@ const RULES: IRule[] = [ skip: true // -> skip all test files }, - // Common: vs/base/common/async.ts - { - target: '**/vs/base/common/async.ts', - allowedTypes: [ - ...CORE_TYPES, - - // Safe access to requestIdleCallback & cancelIdleCallback - 'requestIdleCallback', - 'cancelIdleCallback' - ], - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] - }, - - // Common: vs/base/common/performance.ts - { - target: '**/vs/base/common/performance.ts', - allowedTypes: [ - ...CORE_TYPES, - - // Safe access to Performance - 'Performance', - 'PerformanceEntry', - 'PerformanceTiming' - ], - disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] - }, - // Common: vs/platform services that can access native types { target: `**/vs/platform/{${[ @@ -164,82 +52,32 @@ const RULES: IRule[] = [ 'browserElements/common/browserElements.ts', 'browserElements/common/nativeBrowserElementsService.ts' ].join(',')}}`, - allowedTypes: CORE_TYPES, disallowedTypes: [/* Ignore native types that are defined from here */], - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] }, // Common: vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts { target: '**/vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts', - allowedTypes: [ - ...CORE_TYPES, - - // Safe access to a very small subset of node.js - 'process', - 'NodeJS', - '__global' - ], disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] }, // Common { target: '**/vs/**/common/**', - allowedTypes: CORE_TYPES, disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts', // no DOM - '@types/node' // no node.js - ] }, // Browser { target: '**/vs/**/browser/**', - allowedTypes: [ - ...CORE_TYPES, - 'localStorage' - ], disallowedTypes: NATIVE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] - }, - - // node.js - { - target: '**/vs/**/node/**', - allowedTypes: CORE_TYPES, - disallowedDefinitions: [ - 'lib.dom.d.ts' // no DOM - ] - }, - - // Electron (sandbox) - { - target: '**/vs/**/electron-sandbox/**', - allowedTypes: CORE_TYPES, - disallowedDefinitions: [ - '@types/node' // no node.js - ] }, // Electron (main, utility) { target: '**/vs/**/{electron-main,electron-utility}/**', - allowedTypes: CORE_TYPES, disallowedTypes: [ 'ipcMain' // not allowed, use validatedIpcMain instead - ], - disallowedDefinitions: [ - 'lib.dom.d.ts' // no DOM ] } ]; @@ -249,9 +87,6 @@ const TS_CONFIG_PATH = join(__dirname, '../../', 'src', 'tsconfig.json'); interface IRule { target: string; skip?: boolean; - allowedTypes?: string[]; - allowedDefinitions?: string[]; - disallowedDefinitions?: string[]; disallowedTypes?: string[]; } @@ -273,10 +108,6 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) } let text = symbol.getName(); - if (rule.allowedTypes?.some(allowed => allowed === text)) { - return; // override - } - let _parentSymbol: any = symbol; while (_parentSymbol.parent) { @@ -286,10 +117,6 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) const parentSymbol = _parentSymbol as ts.Symbol; text = parentSymbol.getName(); - if (rule.allowedTypes?.some(allowed => allowed === text)) { - return; // override - } - if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); console.log(`[build/checker/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); @@ -297,40 +124,6 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) hasErrors = true; return; } - - const declarations = symbol.declarations; - if (Array.isArray(declarations)) { - DeclarationLoop: for (const declaration of declarations) { - if (declaration) { - const parent = declaration.parent; - if (parent) { - const parentSourceFile = parent.getSourceFile(); - if (parentSourceFile) { - const definitionFileName = parentSourceFile.fileName; - if (rule.allowedDefinitions) { - for (const allowedDefinition of rule.allowedDefinitions) { - if (definitionFileName.indexOf(allowedDefinition) >= 0) { - continue DeclarationLoop; - } - } - } - if (rule.disallowedDefinitions) { - for (const disallowedDefinition of rule.disallowedDefinitions) { - if (definitionFileName.indexOf(disallowedDefinition) >= 0) { - const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - - console.log(`[build/checker/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1}) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization.`); - - hasErrors = true; - return; - } - } - } - } - } - } - } - } } } diff --git a/build/checker/tsconfig.web.json b/build/checker/tsconfig.browser.json similarity index 100% rename from build/checker/tsconfig.web.json rename to build/checker/tsconfig.browser.json diff --git a/build/checker/tsconfig.electron-main.json b/build/checker/tsconfig.electron-main.json new file mode 100644 index 00000000000..3cb4450c701 --- /dev/null +++ b/build/checker/tsconfig.electron-main.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.node.json", + "include": [ + "../../src/**/electron-main/**/*.ts", + "../../src/**/electron-utility/**/*.ts", + "../../src/typings/*.d.ts", + "../../node_modules/@types/trusted-types/index.d.ts", + ], + "exclude": [ + "../../src/**/test/**", + "../../src/**/fixtures/**", + ] +} diff --git a/build/checker/tsconfig.desktop.json b/build/checker/tsconfig.electron-sandbox.json similarity index 95% rename from build/checker/tsconfig.desktop.json rename to build/checker/tsconfig.electron-sandbox.json index 8135902d99e..88c04da1c2d 100644 --- a/build/checker/tsconfig.desktop.json +++ b/build/checker/tsconfig.electron-sandbox.json @@ -1,5 +1,5 @@ { - "extends": "./tsconfig.web.json", + "extends": "./tsconfig.browser.json", "include": [ "../../src/**/common/**/*.ts", "../../src/**/browser/**/*.ts", diff --git a/build/checker/tsconfig.server.json b/build/checker/tsconfig.node.json similarity index 100% rename from build/checker/tsconfig.server.json rename to build/checker/tsconfig.node.json diff --git a/package.json b/package.json index b195779ddd0..759a348a876 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", "tsec-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.tsec.json", "vscode-dts-compile-check": "tsc -p src/tsconfig.vscode-dts.json && tsc -p src/tsconfig.vscode-proposed-dts.json", - "valid-layers-check": "node build/checker/layersChecker.js && tsc -p build/checker/tsconfig.web.json && tsc -p build/checker/tsconfig.desktop.json && tsc -p build/checker/tsconfig.server.json", + "valid-layers-check": "node build/checker/layersChecker.js && tsc -p build/checker/tsconfig.browser.json && tsc -p build/checker/tsconfig.node.json && tsc -p build/checker/tsconfig.electron-sandbox.json && tsc -p build/checker/tsconfig.electron-main.json", "define-class-fields-check": "node build/lib/propertyInitOrderChecker.js && tsc -p src/tsconfig.defineClassFields.json", "update-distro": "node build/npm/update-distro.mjs", "web": "echo 'npm run web' is replaced by './scripts/code-server' or './scripts/code-web'", diff --git a/src/vs/amdX.ts b/src/vs/amdX.ts index 9fd519fd130..b2f9fd3fa91 100644 --- a/src/vs/amdX.ts +++ b/src/vs/amdX.ts @@ -11,6 +11,11 @@ import { generateUuid } from './base/common/uuid.js'; export const canASAR = false; // TODO@esm: ASAR disabled in ESM +declare const window: any; +declare const document: any; +declare const self: any; +declare const globalThis: any; + class DefineCall { constructor( public readonly id: string | null | undefined, @@ -41,7 +46,7 @@ class AMDModuleImporter { private _initialize(): void { if (this._state === AMDModuleImporterState.Uninitialized) { - if ((globalThis as any).define) { + if (globalThis.define) { this._state = AMDModuleImporterState.InitializedExternal; return; } @@ -51,7 +56,7 @@ class AMDModuleImporter { this._state = AMDModuleImporterState.InitializedInternal; - (globalThis as any).define = (id: any, dependencies: any, callback: any) => { + globalThis.define = (id: any, dependencies: any, callback: any) => { if (typeof id !== 'string') { callback = dependencies; dependencies = id; @@ -67,11 +72,11 @@ class AMDModuleImporter { this._defineCalls.push(new DefineCall(id, dependencies, callback)); }; - (globalThis as any).define.amd = true; + globalThis.define.amd = true; if (this._isRenderer) { - this._amdPolicy = (globalThis as any)._VSCODE_WEB_PACKAGE_TTP ?? window.trustedTypes?.createPolicy('amdLoader', { - createScriptURL(value) { + this._amdPolicy = globalThis._VSCODE_WEB_PACKAGE_TTP ?? window.trustedTypes?.createPolicy('amdLoader', { + createScriptURL(value: any) { if (value.startsWith(window.location.origin)) { return value; } @@ -82,7 +87,7 @@ class AMDModuleImporter { } }); } else if (this._isWebWorker) { - this._amdPolicy = (globalThis as any)._VSCODE_WEB_PACKAGE_TTP ?? (globalThis as any).trustedTypes?.createPolicy('amdLoader', { + this._amdPolicy = globalThis._VSCODE_WEB_PACKAGE_TTP ?? globalThis.trustedTypes?.createPolicy('amdLoader', { createScriptURL(value: string) { return value; } @@ -96,7 +101,7 @@ class AMDModuleImporter { if (this._state === AMDModuleImporterState.InitializedExternal) { return new Promise(resolve => { const tmpModuleId = generateUuid(); - (globalThis as any).define(tmpModuleId, [scriptSrc], function (moduleResult: T) { + globalThis.define(tmpModuleId, [scriptSrc], function (moduleResult: T) { resolve(moduleResult); }); }); @@ -157,7 +162,7 @@ class AMDModuleImporter { scriptElement.addEventListener('load', loadEventListener); scriptElement.addEventListener('error', errorEventListener); if (this._amdPolicy) { - scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as any as string; + scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as unknown as string; } scriptElement.setAttribute('src', scriptSrc); window.document.getElementsByTagName('head')[0].appendChild(scriptElement); @@ -166,7 +171,7 @@ class AMDModuleImporter { private async _workerLoadScript(scriptSrc: string): Promise { if (this._amdPolicy) { - scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as any as string; + scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as unknown as string; } await import(scriptSrc); return this._defineCalls.pop(); @@ -202,7 +207,7 @@ const cache = new Map>(); export async function importAMDNodeModule(nodeModuleName: string, pathInsideNodeModule: string, isBuilt?: boolean): Promise { if (isBuilt === undefined) { const product = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration; - isBuilt = Boolean((product ?? (globalThis as any).vscode?.context?.configuration()?.product)?.commit); + isBuilt = Boolean((product ?? globalThis.vscode?.context?.configuration()?.product)?.commit); } const nodeModulePath = pathInsideNodeModule ? `${nodeModuleName}/${pathInsideNodeModule}` : nodeModuleName; @@ -227,7 +232,7 @@ export async function importAMDNodeModule(nodeModuleName: string, pathInsideN export function resolveAmdNodeModulePath(nodeModuleName: string, pathInsideNodeModule: string): string { const product = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration; - const isBuilt = Boolean((product ?? (globalThis as any).vscode?.context?.configuration()?.product)?.commit); + const isBuilt = Boolean((product ?? globalThis.vscode?.context?.configuration()?.product)?.commit); const useASAR = (canASAR && isBuilt && !platform.isWeb); const nodeModulePath = `${nodeModuleName}/${pathInsideNodeModule}`; diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 81f556b1364..ca964301327 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -1459,7 +1459,8 @@ export let runWhenGlobalIdle: (callback: (idle: IdleDeadline) => void, timeout?: export let _runWhenIdle: (targetWindow: IdleApi, callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable; (function () { - if (typeof globalThis.requestIdleCallback !== 'function' || typeof globalThis.cancelIdleCallback !== 'function') { + const safeGlobal: any = globalThis; + if (typeof safeGlobal.requestIdleCallback !== 'function' || typeof safeGlobal.cancelIdleCallback !== 'function') { _runWhenIdle = (_targetWindow, runner, timeout?) => { setTimeout0(() => { if (disposed) { @@ -1485,7 +1486,7 @@ export let _runWhenIdle: (targetWindow: IdleApi, callback: (idle: IdleDeadline) }; }; } else { - _runWhenIdle = (targetWindow: IdleApi, runner, timeout?) => { + _runWhenIdle = (targetWindow: typeof safeGlobal, runner, timeout?) => { const handle: number = targetWindow.requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined); let disposed = false; return { diff --git a/src/vs/base/common/buffer.ts b/src/vs/base/common/buffer.ts index 39c2f623fbf..831357fec08 100644 --- a/src/vs/base/common/buffer.ts +++ b/src/vs/base/common/buffer.ts @@ -6,13 +6,20 @@ import { Lazy } from './lazy.js'; import * as streams from './stream.js'; -declare const Buffer: any; +interface NodeBuffer { + allocUnsafe(size: number): Uint8Array; + isBuffer(obj: any): obj is NodeBuffer; + from(arrayBuffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8Array; + from(data: string): Uint8Array; +} + +declare const Buffer: NodeBuffer; const hasBuffer = (typeof Buffer !== 'undefined'); const indexOfTable = new Lazy(() => new Uint8Array(256)); -let textEncoder: TextEncoder | null; -let textDecoder: TextDecoder | null; +let textEncoder: { encode: (input: string) => Uint8Array } | null; +let textDecoder: { decode: (input: Uint8Array) => string } | null; export class VSBuffer { @@ -93,6 +100,10 @@ export class VSBuffer { return ret; } + static isNativeBuffer(buffer: unknown): boolean { + return hasBuffer && Buffer.isBuffer(buffer); + } + readonly buffer: Uint8Array; readonly byteLength: number; diff --git a/src/vs/base/common/performance.ts b/src/vs/base/common/performance.ts index 26cd624136b..ab97b75fb7e 100644 --- a/src/vs/base/common/performance.ts +++ b/src/vs/base/common/performance.ts @@ -29,6 +29,27 @@ function _definePolyfillMarks(timeOrigin?: number) { declare const process: INodeProcess; +interface IPerformanceEntry { + readonly name: string; + readonly startTime: number; +} + +interface IPerformanceTiming { + readonly navigationStart?: number; + readonly redirectStart?: number; + readonly fetchStart?: number; +} + +interface IPerformance { + mark(name: string, markOptions?: { startTime?: number }): void; + getEntriesByType(type: string): IPerformanceEntry[]; + readonly timeOrigin: number; + readonly timing: IPerformanceTiming; + readonly nodeTiming?: any; +} + +declare const performance: IPerformance; + function _define() { // Identify browser environment when following property is not present @@ -53,7 +74,7 @@ function _define() { if (typeof timeOrigin !== 'number') { // safari: there is no timerOrigin but in renderers there is the timing-property // see https://bugs.webkit.org/show_bug.cgi?id=174862 - timeOrigin = performance.timing.navigationStart || performance.timing.redirectStart || performance.timing.fetchStart; + timeOrigin = (performance.timing.navigationStart || performance.timing.redirectStart || performance.timing.fetchStart) ?? 0; } const result = [{ name: 'code/timeOrigin', startTime: Math.round(timeOrigin) }]; for (const entry of performance.getEntriesByType('mark')) { diff --git a/src/vs/base/common/stopwatch.ts b/src/vs/base/common/stopwatch.ts index ca3cb6388bc..6b62b72aea9 100644 --- a/src/vs/base/common/stopwatch.ts +++ b/src/vs/base/common/stopwatch.ts @@ -3,9 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -// fake definition so that the valid layers check won't trip on this declare const globalThis: { performance: { now(): number } }; - const performanceNow = globalThis.performance.now.bind(globalThis.performance); export class StopWatch { diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 7ab922e8b82..5e0764d9849 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -260,9 +260,6 @@ const BufferPresets = { Uint: createOneByteBuffer(DataType.Int), }; -declare const Buffer: any; -const hasBuffer = (typeof Buffer !== 'undefined'); - export function serialize(writer: IWriter, data: any): void { if (typeof data === 'undefined') { writer.write(BufferPresets.Undefined); @@ -271,7 +268,7 @@ export function serialize(writer: IWriter, data: any): void { writer.write(BufferPresets.String); writeInt32VQL(writer, buffer.byteLength); writer.write(buffer); - } else if (hasBuffer && Buffer.isBuffer(data)) { + } else if (VSBuffer.isNativeBuffer(data)) { const buffer = VSBuffer.wrap(data); writer.write(BufferPresets.Buffer); writeInt32VQL(writer, buffer.byteLength); diff --git a/src/vs/nls.ts b/src/vs/nls.ts index e730d0a761e..e9183ad7d32 100644 --- a/src/vs/nls.ts +++ b/src/vs/nls.ts @@ -8,6 +8,7 @@ import { getNLSLanguage, getNLSMessages } from './nls.messages.js'; // eslint-disable-next-line local/code-import-patterns export { getNLSLanguage, getNLSMessages } from './nls.messages.js'; +declare const document: { location?: { hash?: string } } | undefined; const isPseudo = getNLSLanguage() === 'pseudo' || (typeof document !== 'undefined' && document.location && typeof document.location.hash === 'string' && document.location.hash.indexOf('pseudo=true') >= 0); export interface ILocalizeInfo { diff --git a/src/vs/platform/webContentExtractor/node/sharedWebContentExtractorService.ts b/src/vs/platform/webContentExtractor/node/sharedWebContentExtractorService.ts index 61ae28d1e9b..ae70e341c0c 100644 --- a/src/vs/platform/webContentExtractor/node/sharedWebContentExtractorService.ts +++ b/src/vs/platform/webContentExtractor/node/sharedWebContentExtractorService.ts @@ -28,7 +28,7 @@ export class SharedWebContentExtractorService implements ISharedWebContentExtrac return undefined; } - const content = VSBuffer.wrap(await response.bytes()); + const content = VSBuffer.wrap(await (response as unknown as { bytes: () => Promise> } /* workaround https://github.com/microsoft/TypeScript/issues/61826 */).bytes()); return content; } catch (err) { console.log(err); diff --git a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts index 68f17c615b3..5ec6e750839 100644 --- a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts +++ b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts @@ -30,8 +30,6 @@ import { IActivityService, NumberBadge } from '../../../services/activity/common import { IExtensionService } from '../../../services/extensions/common/extensions.js'; import { IHoverService } from '../../../../platform/hover/browser/hover.js'; -declare const ResizeObserver: any; - const storageKeys = { webviewState: 'webviewState', } as const; From c5ccd47affd5f5a2350aa7154e0a7d497f984f6c Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Sat, 7 Jun 2025 10:05:06 -0700 Subject: [PATCH 113/236] mcp: add request trace-level logging (#250898) * mcp: add request trace-level logging Refs https://github.com/microsoft/vscode/issues/250537 * fix * update headers for layers --- src/vs/workbench/api/common/extHostMcp.ts | 63 +++++++++++++++------ src/vs/workbench/api/node/extHostMcpNode.ts | 5 +- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/api/common/extHostMcp.ts b/src/vs/workbench/api/common/extHostMcp.ts index db96d1e2124..d81edad5172 100644 --- a/src/vs/workbench/api/common/extHostMcp.ts +++ b/src/vs/workbench/api/common/extHostMcp.ts @@ -10,7 +10,7 @@ import { Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } import { SSEParser } from '../../../base/common/sseParser.js'; import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js'; import { createDecorator } from '../../../platform/instantiation/common/instantiation.js'; -import { LogLevel } from '../../../platform/log/common/log.js'; +import { canLog, ILogService, LogLevel } from '../../../platform/log/common/log.js'; import { StorageScope } from '../../../platform/storage/common/storage.js'; import { extensionPrefixedIdentifier, McpCollectionDefinition, McpConnectionState, McpServerDefinition, McpServerLaunch, McpServerTransportHTTP, McpServerTransportType } from '../../contrib/mcp/common/mcpTypes.js'; import { ExtHostMcpShape, MainContext, MainThreadMcpShape } from './extHost.protocol.js'; @@ -40,6 +40,7 @@ export class ExtHostMcpService extends Disposable implements IExtHostMpcService constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, + @ILogService private readonly _logService: ILogService, @IExtHostInitDataService private readonly _extHostInitData: IExtHostInitDataService ) { super(); @@ -52,7 +53,7 @@ export class ExtHostMcpService extends Disposable implements IExtHostMpcService protected _startMcp(id: number, launch: McpServerLaunch): void { if (launch.type === McpServerTransportType.HTTP) { - this._sseEventSources.set(id, new McpHTTPHandle(id, launch, this._proxy)); + this._sseEventSources.set(id, new McpHTTPHandle(id, launch, this._proxy, this._logService)); return; } @@ -197,7 +198,8 @@ class McpHTTPHandle extends Disposable { constructor( private readonly _id: number, private readonly _launch: McpServerTransportHTTP, - private readonly _proxy: MainThreadMcpShape + private readonly _proxy: MainThreadMcpShape, + private readonly _logService: ILogService, ) { super(); @@ -246,7 +248,6 @@ class McpHTTPHandle extends Disposable { this._launch.uri.toString(true), { method: 'POST', - signal: this._abortCtrl.signal, headers, body: asBytes, }, @@ -280,7 +281,7 @@ class McpHTTPHandle extends Disposable { this._proxy.$onDidChangeState(this._id, { state: McpConnectionState.Kind.Error, - message: `${res.status} status sending message to ${this._launch.uri}: ${await this._getErrText(res)}` + retryWithSessionId ? `; will retry with new session ID` : '', + message: `${res.status} status sending message to ${this._launch.uri}: ${await this._getErrText(res)}` + (retryWithSessionId ? `; will retry with new session ID` : ''), shouldRetry: retryWithSessionId, }); return; @@ -374,9 +375,8 @@ class McpHTTPHandle extends Disposable { ...Object.fromEntries(this._launch.headers) }; } - const resourceMetadataResponse = await fetch(resourceMetadata, { + const resourceMetadataResponse = await this._fetch(resourceMetadata, { method: 'GET', - signal: this._abortCtrl.signal, headers: { ...additionalHeaders, 'Accept': 'application/json', @@ -401,9 +401,8 @@ class McpHTTPHandle extends Disposable { const authorizationServerUrl = new URL(authorizationServer); const extraPath = authorizationServerUrl.pathname === '/' ? '' : authorizationServerUrl.pathname; const pathToFetch = new URL(AUTH_SERVER_METADATA_DISCOVERY_PATH, authorizationServer).toString() + extraPath; - let authServerMetadataResponse = await fetch(pathToFetch, { + let authServerMetadataResponse = await this._fetch(pathToFetch, { method: 'GET', - signal: this._abortCtrl.signal, headers: { ...addtionalHeaders, 'Accept': 'application/json', @@ -414,11 +413,10 @@ class McpHTTPHandle extends Disposable { // Try fetching the other discovery URL. For the openid metadata discovery // path, we _ADD_ the well known path after the existing path. // https://datatracker.ietf.org/doc/html/rfc8414#section-3 - authServerMetadataResponse = await fetch( + authServerMetadataResponse = await this._fetch( URI.joinPath(URI.parse(authorizationServer), '.well-known', 'openid-configuration').toString(true), { method: 'GET', - signal: this._abortCtrl.signal, headers: { ...addtionalHeaders, 'Accept': 'application/json', @@ -505,7 +503,6 @@ class McpHTTPHandle extends Disposable { this._launch.uri.toString(true), { method: 'GET', - signal: this._abortCtrl.signal, headers, }, headers @@ -557,7 +554,6 @@ class McpHTTPHandle extends Disposable { this._launch.uri.toString(true), { method: 'GET', - signal: this._abortCtrl.signal, headers, }, headers @@ -599,9 +595,8 @@ class McpHTTPHandle extends Disposable { 'Content-Length': String(asBytes.length), }; await this._addAuthHeader(headers); - const res = await fetch(url, { + const res = await this._fetch(url, { method: 'POST', - signal: this._abortCtrl.signal, headers, body: asBytes, }); @@ -670,8 +665,8 @@ class McpHTTPHandle extends Disposable { * If the initial request returns 401 and we don't have auth metadata, * it will populate the auth metadata and retry once. */ - private async _fetchWithAuthRetry(url: string, init: RequestInit, headers: Record): Promise { - const doFetch = () => fetch(url, init); + private async _fetchWithAuthRetry(url: string, init: MinimalRequestInit, headers: Record): Promise { + const doFetch = () => this._fetch(url, init); let res = await doFetch(); if (res.status === 401) { @@ -687,6 +682,40 @@ class McpHTTPHandle extends Disposable { } return res; } + + private async _fetch(url: string, init: MinimalRequestInit): Promise { + if (canLog(this._logService.getLevel(), LogLevel.Trace)) { + const traceObj: any = { ...init, headers: { ...init.headers } }; + if (traceObj.body) { + traceObj.body = new TextDecoder().decode(traceObj.body); + } + if (traceObj.headers?.Authorization) { + traceObj.headers.Authorization = '***'; // don't log the auth header + } + this._log(LogLevel.Trace, `Fetching ${url} with options: ${JSON.stringify(traceObj)}`); + } + const res = await fetch(url, { + ...init, + signal: this._abortCtrl.signal, + }); + + if (canLog(this._logService.getLevel(), LogLevel.Trace)) { + const headers: Record = {}; + res.headers.forEach((value, key) => { headers[key] = value; }); + this._log(LogLevel.Trace, `Fetched ${url}: ${JSON.stringify({ + status: res.status, + headers: headers, + })}`); + } + + return res; + } +} + +interface MinimalRequestInit { + method: string; + headers: Record; + body?: Uint8Array; } function isJSON(str: string): boolean { diff --git a/src/vs/workbench/api/node/extHostMcpNode.ts b/src/vs/workbench/api/node/extHostMcpNode.ts index 49550059ceb..0e65834ab19 100644 --- a/src/vs/workbench/api/node/extHostMcpNode.ts +++ b/src/vs/workbench/api/node/extHostMcpNode.ts @@ -10,7 +10,7 @@ import { parseEnvFile } from '../../../base/common/envfile.js'; import { untildify } from '../../../base/common/labels.js'; import { StreamSplitter } from '../../../base/node/nodeStreams.js'; import { findExecutable } from '../../../base/node/processes.js'; -import { LogLevel } from '../../../platform/log/common/log.js'; +import { ILogService, LogLevel } from '../../../platform/log/common/log.js'; import { McpConnectionState, McpServerLaunch, McpServerTransportStdio, McpServerTransportType } from '../../contrib/mcp/common/mcpTypes.js'; import { ExtHostMcpService } from '../common/extHostMcp.js'; import { IExtHostRpcService } from '../common/extHostRpcService.js'; @@ -21,8 +21,9 @@ export class NodeExtHostMpcService extends ExtHostMcpService { constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, @IExtHostInitDataService initDataService: IExtHostInitDataService, + @ILogService logService: ILogService, ) { - super(extHostRpc, initDataService); + super(extHostRpc, logService, initDataService); } private nodeServers = new Map Date: Mon, 9 Jun 2025 07:50:40 +0200 Subject: [PATCH 114/236] :up: `open@^10.1.2` (#250980) --- package-lock.json | 126 +++++++++++++++--- package.json | 2 +- scripts/code-server.js | 2 +- scripts/code-web.js | 2 +- .../node/nativeModules.integrationTest.ts | 5 - .../electron-main/nativeHostMainService.ts | 4 +- 6 files changed, 110 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index a98acf27573..3bb7fc3d2e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", "node-pty": "^1.1.0-beta33", - "open": "^8.4.2", + "open": "^10.1.2", "tas-client-umd": "0.2.0", "v8-inspect-profiler": "^0.1.1", "vscode-oniguruma": "1.7.0", @@ -4323,6 +4323,21 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -5512,6 +5527,34 @@ "node": ">=4.0.0" } }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", @@ -5560,11 +5603,15 @@ } }, "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/define-properties": { @@ -10143,14 +10190,15 @@ } }, "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10229,6 +10277,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", @@ -10418,14 +10484,18 @@ } }, "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isarray": { @@ -12876,16 +12946,18 @@ "dev": true }, "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz", + "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", + "license": "MIT", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -14623,6 +14695,18 @@ "node": ">=8.0" } }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.1.10", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", diff --git a/package.json b/package.json index 759a348a876..0a4e6295ad1 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", "node-pty": "^1.1.0-beta33", - "open": "^8.4.2", + "open": "^10.1.2", "tas-client-umd": "0.2.0", "v8-inspect-profiler": "^0.1.1", "vscode-oniguruma": "1.7.0", diff --git a/scripts/code-server.js b/scripts/code-server.js index 245694c8b6d..5226015b23b 100644 --- a/scripts/code-server.js +++ b/scripts/code-server.js @@ -33,7 +33,7 @@ async function main() { const serverArgs = process.argv.slice(2).filter(v => v !== '--launch'); const addr = await startServer(serverArgs); if (args['launch']) { - open(addr); + open.default(addr); } } diff --git a/scripts/code-web.js b/scripts/code-web.js index a66dd17018f..5dc638c0c60 100644 --- a/scripts/code-web.js +++ b/scripts/code-web.js @@ -80,7 +80,7 @@ async function main() { startServer(serverArgs); if (openSystemBrowser) { - open(`http://${HOST}:${PORT}/`); + open.default(`http://${HOST}:${PORT}/`); } } diff --git a/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts b/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts index e0b99f38093..2a6acbac584 100644 --- a/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts +++ b/src/vs/platform/environment/test/node/nativeModules.integrationTest.ts @@ -70,11 +70,6 @@ flakySuite('Native Modules (all platforms)', () => { assert.ok(typeof nodePty.spawn === 'function', testErrorMessage('node-pty')); }); - test('open', async () => { - const { default: open } = await import('open'); - assert.ok(typeof open === 'function', testErrorMessage('open')); - }); - test('@vscode/spdlog', async () => { const spdlog = await import('@vscode/spdlog'); assert.ok(typeof spdlog.createRotatingLogger === 'function', testErrorMessage('@vscode/spdlog')); diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index d71c1930a3d..7e1dda7b1a4 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -584,13 +584,13 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } try { - const { default: open } = await import('open'); + const { default: open, apps } = await import('open'); const res = await open(url, { app: { // Use `open.apps` helper to allow cross-platform browser // aliases to be looked up properly. Fallback to the // configured value if not found. - name: Object.hasOwn(open.apps, configuredBrowser) ? open.apps[(configuredBrowser as keyof typeof open['apps'])] : configuredBrowser + name: Object.hasOwn(apps, configuredBrowser) ? apps[(configuredBrowser as keyof typeof apps)] : configuredBrowser } }); From cdf404ff47a2eb58f0a9b01cdfab3a5adbf8e936 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 9 Jun 2025 09:08:43 +0200 Subject: [PATCH 115/236] debt - restore old layer name (#250928) --- .eslint-plugin-local/code-import-patterns.ts | 6 +- build/buildfile.js | 4 +- build/checker/layersChecker.js | 9 +- build/checker/layersChecker.ts | 10 +- build/checker/tsconfig.browser.json | 1 + ...ox.json => tsconfig.electron-browser.json} | 6 +- build/checker/tsconfig.electron-main.json | 6 +- build/checker/tsconfig.electron-utility.json | 17 ++ build/checker/tsconfig.node.json | 1 + build/checker/tsconfig.worker.json | 28 +++ build/gulpfile.reh.js | 2 +- build/gulpfile.vscode.js | 14 +- build/gulpfile.vscode.web.js | 2 +- eslint.config.js | 16 +- package.json | 2 +- src/bootstrap-import.ts | 2 +- src/tsec.exemptions.json | 6 +- .../contextmenu.ts | 2 +- .../ipc.electron.ts | 2 +- .../ipc.mp.ts | 2 +- src/vs/base/parts/ipc/electron-main/ipc.mp.ts | 2 +- .../ipc.mp.test.ts | 0 .../electronTypes.ts | 2 +- .../globals.ts | 0 .../preload-aux.ts | 0 .../preload.ts | 0 .../globals.test.ts | 2 +- src/vs/base/test/common/labels.test.ts | 2 +- .../workbench/workbench-dev.html | 0 .../workbench/workbench.html | 0 .../workbench/workbench.ts | 8 +- .../auxiliaryWindowsMainService.ts | 2 +- .../diagnosticsService.ts | 2 +- .../extensionsProfileScannerService.ts | 0 .../externalTerminalService.ts | 2 +- .../mainProcessService.ts | 2 +- .../services.ts | 0 .../menubar.ts | 0 .../profileAnalysisWorker.ts | 0 .../profileAnalysisWorkerMain.ts | 0 .../profileAnalysisWorkerService.ts | 2 +- .../profilingService.ts | 2 +- .../electronRemoteResourceLoader.ts | 0 .../remoteAuthorityResolverService.ts | 0 .../sharedProcessTunnelService.ts | 2 +- .../remoteAuthorityResolverService.test.ts | 2 +- .../remoteTunnelService.ts | 2 +- .../customEndpointTelemetryService.ts | 2 +- .../userDataProfileStorageService.ts | 0 .../webContentExtractorService.ts | 2 +- .../window.ts | 2 +- .../windows/electron-main/windowImpl.ts | 4 +- .../actions/chatDeveloperActions.ts | 0 .../actions/media/voiceChatActions.css | 0 .../actions/voiceChatActions.ts | 0 .../chat.contribution.ts | 0 .../tools/fetchPageTool.ts | 0 .../voiceChatActions.test.ts | 2 +- .../codeEditor.contribution.ts | 0 .../displayChangeRemeasureFonts.ts | 0 .../inputClipboardActions.ts | 0 .../selectionClipboard.ts | 0 .../sleepResumeRepaintMinimap.ts | 0 .../startDebugTextMate.ts | 2 +- .../extensionHostDebugService.ts | 2 +- .../emergencyAlert.contribution.ts | 0 .../encryption.contribution.ts | 0 .../debugExtensionHostAction.ts | 0 .../extensionProfileService.ts | 2 +- .../extensions.contribution.ts | 2 +- .../extensionsActions.ts | 2 +- .../extensionsAutoProfiler.ts | 6 +- .../extensionsSlowActions.ts | 2 +- .../remoteExtensionsInit.ts | 0 .../runtimeExtensionsEditor.ts | 0 .../extension.test.ts | 0 .../extensionRecommendationsService.test.ts | 4 +- .../extensionsActions.test.ts | 8 +- .../extensionsViews.test.ts | 6 +- .../extensionsWorkbenchService.test.ts | 6 +- .../externalTerminal.contribution.ts | 2 +- .../fileActions.contribution.ts | 0 .../fileCommands.ts | 0 .../inlineChat.contribution.ts | 0 .../inlineChatActions.ts | 2 +- .../issue.contribution.ts | 0 .../issueReporterService.ts | 2 +- .../issueService.ts | 0 .../nativeIssueFormService.ts | 0 .../localHistory.contribution.ts | 0 .../localHistoryCommands.ts | 0 .../localization.contribution.ts | 2 +- .../minimalTranslations.ts | 0 .../logs.contribution.ts | 0 .../logsActions.ts | 2 +- .../mcp.contribution.ts | 0 .../mcpDevModeDebuggingNode.ts | 0 .../nativeMpcDiscovery.ts | 0 .../devCommands.ts | 0 .../mergeEditor.contribution.ts | 0 .../performance.contribution.ts | 0 .../rendererAutoProfiler.ts | 4 +- .../startupProfiler.ts | 2 +- .../startupTimings.ts | 2 +- .../processExplorer.contribution.ts | 0 .../processExplorerControl.ts | 0 .../processExplorerEditor.ts | 0 .../remote.contribution.ts | 4 +- .../remoteTunnel.contribution.ts | 0 .../splash.contribution.ts | 0 .../tags.contribution.ts | 0 .../workspaceTags.ts | 0 .../workspaceTagsService.ts | 0 .../taskService.ts | 0 .../localPty.ts | 0 .../localTerminalBackend.ts | 4 +- .../terminal.contribution.ts | 2 +- .../terminalNativeContribution.ts | 2 +- .../terminalProfileResolverService.ts | 0 .../terminalRemote.ts | 0 .../userDataSync.contribution.ts | 2 +- .../webview.contribution.ts | 0 .../webviewCommands.ts | 0 .../webviewElement.ts | 0 .../webviewService.ts | 0 .../windowIgnoreMenuShortcutsManager.ts | 0 .../actions/developerActions.ts | 2 +- .../actions/installActions.ts | 0 .../actions/media/actions.css | 0 .../actions/windowActions.ts | 2 +- .../desktop.contribution.ts | 2 +- .../desktop.main.ts | 26 +-- .../media/window.css | 0 .../parts/dialogs/dialog.contribution.ts | 0 .../parts/dialogs/dialogHandler.ts | 2 +- .../parts/titlebar/menubarControl.ts | 4 +- .../parts/titlebar/titlebarPart.ts | 2 +- .../window.ts | 12 +- .../accessibilityService.ts | 2 +- .../auxiliaryWindowService.ts | 4 +- .../browserElementsService.ts | 4 +- .../checksumService.ts | 2 +- .../clipboardService.ts | 0 .../configurationResolverService.ts | 4 +- .../configurationResolverService.test.ts | 0 .../contextmenuService.ts | 2 +- .../fileDialogService.ts | 0 .../fileDialogService.test.ts | 2 +- .../encryptionService.ts | 2 +- .../environmentService.ts | 0 .../shellEnvironmentService.ts | 2 +- .../extensionGalleryManifestService.ts | 2 +- .../extensionManagementServerService.ts | 2 +- .../extensionManagementService.ts | 2 +- .../extensionTipsService.ts | 2 +- .../nativeExtensionManagementService.ts | 2 +- .../remoteExtensionManagementService.ts | 0 .../cachedExtensionScanner.ts | 0 .../extensionHostProfiler.ts | 0 .../extensionHostStarter.ts | 2 +- .../extensionsScannerService.ts | 0 .../localProcessExtensionHost.ts | 6 +- .../nativeExtensionService.ts | 0 .../diskFileSystemProvider.ts | 2 +- .../elevatedFileService.ts | 2 +- .../watcherClient.ts | 2 +- .../nativeHostService.ts | 2 +- .../integrityService.ts | 0 .../nativeKeyboardLayout.ts | 0 .../nativeKeyboardLayoutService.ts | 0 .../lifecycleService.ts | 2 +- .../lifecycleService.test.ts | 4 +- .../languagePackService.ts | 2 +- .../localeService.ts | 0 .../logService.ts | 2 +- .../menubarService.ts | 4 +- .../pathService.ts | 2 +- .../processService.ts | 2 +- .../remoteAgentService.ts | 0 .../requestService.ts | 0 .../searchService.ts | 0 .../secretStorageService.ts | 0 .../sharedProcessService.ts | 4 +- .../storageService.ts | 0 .../telemetryService.ts | 6 +- .../nativeTextFileService.ts | 2 +- .../nativeTextFileService.io.test.ts | 2 +- .../nativeTextFileService.test.ts | 2 +- .../nativeHostColorSchemeService.ts | 2 +- .../themes.contribution.ts | 0 .../timerService.ts | 4 +- .../titleService.ts | 2 +- .../tunnelService.ts | 2 +- .../updateService.ts | 2 +- .../urlService.ts | 0 .../userDataAutoSyncService.ts | 2 +- .../userDataSyncService.ts | 2 +- .../utilityProcessWorkerWorkbenchService.ts | 2 +- .../workingCopyBackupService.ts | 2 +- .../workingCopyBackupTracker.ts | 0 .../workingCopyHistoryService.ts | 0 .../workingCopyBackupService.test.ts | 4 +- .../workingCopyBackupTracker.test.ts | 4 +- .../workingCopyHistoryService.test.ts | 0 .../workingCopyHistoryTracker.test.ts | 0 .../workspaceEditingService.ts | 2 +- .../workspacesService.ts | 0 .../resolveExternal.test.ts | 2 +- .../workbenchTestServices.ts | 6 +- src/vs/workbench/workbench.desktop.main.ts | 166 +++++++++--------- test/unit/browser/index.js | 2 +- test/unit/node/index.js | 2 +- 212 files changed, 332 insertions(+), 270 deletions(-) rename build/checker/{tsconfig.electron-sandbox.json => tsconfig.electron-browser.json} (78%) create mode 100644 build/checker/tsconfig.electron-utility.json create mode 100644 build/checker/tsconfig.worker.json rename src/vs/base/parts/contextmenu/{electron-sandbox => electron-browser}/contextmenu.ts (97%) rename src/vs/base/parts/ipc/{electron-sandbox => electron-browser}/ipc.electron.ts (95%) rename src/vs/base/parts/ipc/{electron-sandbox => electron-browser}/ipc.mp.ts (98%) rename src/vs/base/parts/ipc/test/{electron-sandbox => electron-browser}/ipc.mp.test.ts (100%) rename src/vs/base/parts/sandbox/{electron-sandbox => electron-browser}/electronTypes.ts (99%) rename src/vs/base/parts/sandbox/{electron-sandbox => electron-browser}/globals.ts (100%) rename src/vs/base/parts/sandbox/{electron-sandbox => electron-browser}/preload-aux.ts (100%) rename src/vs/base/parts/sandbox/{electron-sandbox => electron-browser}/preload.ts (100%) rename src/vs/base/parts/sandbox/test/{electron-sandbox => electron-browser}/globals.test.ts (96%) rename src/vs/code/{electron-sandbox => electron-browser}/workbench/workbench-dev.html (100%) rename src/vs/code/{electron-sandbox => electron-browser}/workbench/workbench.html (100%) rename src/vs/code/{electron-sandbox => electron-browser}/workbench/workbench.ts (98%) rename src/vs/platform/diagnostics/{electron-sandbox => electron-browser}/diagnosticsService.ts (95%) rename src/vs/platform/extensionManagement/{electron-sandbox => electron-browser}/extensionsProfileScannerService.ts (100%) rename src/vs/platform/externalTerminal/{electron-sandbox => electron-browser}/externalTerminalService.ts (97%) rename src/vs/platform/ipc/{electron-sandbox => electron-browser}/mainProcessService.ts (97%) rename src/vs/platform/ipc/{electron-sandbox => electron-browser}/services.ts (100%) rename src/vs/platform/menubar/{electron-sandbox => electron-browser}/menubar.ts (100%) rename src/vs/platform/profiling/{electron-sandbox => electron-browser}/profileAnalysisWorker.ts (100%) rename src/vs/platform/profiling/{electron-sandbox => electron-browser}/profileAnalysisWorkerMain.ts (100%) rename src/vs/platform/profiling/{electron-sandbox => electron-browser}/profileAnalysisWorkerService.ts (97%) rename src/vs/platform/profiling/{electron-sandbox => electron-browser}/profilingService.ts (95%) rename src/vs/platform/remote/{electron-sandbox => electron-browser}/electronRemoteResourceLoader.ts (100%) rename src/vs/platform/remote/{electron-sandbox => electron-browser}/remoteAuthorityResolverService.ts (100%) rename src/vs/platform/remote/{electron-sandbox => electron-browser}/sharedProcessTunnelService.ts (95%) rename src/vs/platform/remote/test/{electron-sandbox => electron-browser}/remoteAuthorityResolverService.test.ts (93%) rename src/vs/platform/remoteTunnel/{electron-sandbox => electron-browser}/remoteTunnelService.ts (95%) rename src/vs/platform/telemetry/{electron-sandbox => electron-browser}/customEndpointTelemetryService.ts (95%) rename src/vs/platform/userDataProfile/{electron-sandbox => electron-browser}/userDataProfileStorageService.ts (100%) rename src/vs/platform/webContentExtractor/{electron-sandbox => electron-browser}/webContentExtractorService.ts (91%) rename src/vs/platform/window/{electron-sandbox => electron-browser}/window.ts (98%) rename src/vs/workbench/contrib/chat/{electron-sandbox => electron-browser}/actions/chatDeveloperActions.ts (100%) rename src/vs/workbench/contrib/chat/{electron-sandbox => electron-browser}/actions/media/voiceChatActions.css (100%) rename src/vs/workbench/contrib/chat/{electron-sandbox => electron-browser}/actions/voiceChatActions.ts (100%) rename src/vs/workbench/contrib/chat/{electron-sandbox => electron-browser}/chat.contribution.ts (100%) rename src/vs/workbench/contrib/chat/{electron-sandbox => electron-browser}/tools/fetchPageTool.ts (100%) rename src/vs/workbench/contrib/chat/test/{electron-sandbox => electron-browser}/voiceChatActions.test.ts (95%) rename src/vs/workbench/contrib/codeEditor/{electron-sandbox => electron-browser}/codeEditor.contribution.ts (100%) rename src/vs/workbench/contrib/codeEditor/{electron-sandbox => electron-browser}/displayChangeRemeasureFonts.ts (100%) rename src/vs/workbench/contrib/codeEditor/{electron-sandbox => electron-browser}/inputClipboardActions.ts (100%) rename src/vs/workbench/contrib/codeEditor/{electron-sandbox => electron-browser}/selectionClipboard.ts (100%) rename src/vs/workbench/contrib/codeEditor/{electron-sandbox => electron-browser}/sleepResumeRepaintMinimap.ts (100%) rename src/vs/workbench/contrib/codeEditor/{electron-sandbox => electron-browser}/startDebugTextMate.ts (98%) rename src/vs/workbench/contrib/debug/{electron-sandbox => electron-browser}/extensionHostDebugService.ts (95%) rename src/vs/workbench/contrib/emergencyAlert/{electron-sandbox => electron-browser}/emergencyAlert.contribution.ts (100%) rename src/vs/workbench/contrib/encryption/{electron-sandbox => electron-browser}/encryption.contribution.ts (100%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/debugExtensionHostAction.ts (100%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/extensionProfileService.ts (99%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/extensions.contribution.ts (99%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/extensionsActions.ts (97%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/extensionsAutoProfiler.ts (98%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/extensionsSlowActions.ts (99%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/remoteExtensionsInit.ts (100%) rename src/vs/workbench/contrib/extensions/{electron-sandbox => electron-browser}/runtimeExtensionsEditor.ts (100%) rename src/vs/workbench/contrib/extensions/test/{electron-sandbox => electron-browser}/extension.test.ts (100%) rename src/vs/workbench/contrib/extensions/test/{electron-sandbox => electron-browser}/extensionRecommendationsService.test.ts (99%) rename src/vs/workbench/contrib/extensions/test/{electron-sandbox => electron-browser}/extensionsActions.test.ts (99%) rename src/vs/workbench/contrib/extensions/test/{electron-sandbox => electron-browser}/extensionsViews.test.ts (99%) rename src/vs/workbench/contrib/extensions/test/{electron-sandbox => electron-browser}/extensionsWorkbenchService.test.ts (99%) rename src/vs/workbench/contrib/externalTerminal/{electron-sandbox => electron-browser}/externalTerminal.contribution.ts (99%) rename src/vs/workbench/contrib/files/{electron-sandbox => electron-browser}/fileActions.contribution.ts (100%) rename src/vs/workbench/contrib/files/{electron-sandbox => electron-browser}/fileCommands.ts (100%) rename src/vs/workbench/contrib/inlineChat/{electron-sandbox => electron-browser}/inlineChat.contribution.ts (100%) rename src/vs/workbench/contrib/inlineChat/{electron-sandbox => electron-browser}/inlineChatActions.ts (98%) rename src/vs/workbench/contrib/issue/{electron-sandbox => electron-browser}/issue.contribution.ts (100%) rename src/vs/workbench/contrib/issue/{electron-sandbox => electron-browser}/issueReporterService.ts (99%) rename src/vs/workbench/contrib/issue/{electron-sandbox => electron-browser}/issueService.ts (100%) rename src/vs/workbench/contrib/issue/{electron-sandbox => electron-browser}/nativeIssueFormService.ts (100%) rename src/vs/workbench/contrib/localHistory/{electron-sandbox => electron-browser}/localHistory.contribution.ts (100%) rename src/vs/workbench/contrib/localHistory/{electron-sandbox => electron-browser}/localHistoryCommands.ts (100%) rename src/vs/workbench/contrib/localization/{electron-sandbox => electron-browser}/localization.contribution.ts (98%) rename src/vs/workbench/contrib/localization/{electron-sandbox => electron-browser}/minimalTranslations.ts (100%) rename src/vs/workbench/contrib/logs/{electron-sandbox => electron-browser}/logs.contribution.ts (100%) rename src/vs/workbench/contrib/logs/{electron-sandbox => electron-browser}/logsActions.ts (97%) rename src/vs/workbench/contrib/mcp/{electron-sandbox => electron-browser}/mcp.contribution.ts (100%) rename src/vs/workbench/contrib/mcp/{electron-sandbox => electron-browser}/mcpDevModeDebuggingNode.ts (100%) rename src/vs/workbench/contrib/mcp/{electron-sandbox => electron-browser}/nativeMpcDiscovery.ts (100%) rename src/vs/workbench/contrib/mergeEditor/{electron-sandbox => electron-browser}/devCommands.ts (100%) rename src/vs/workbench/contrib/mergeEditor/{electron-sandbox => electron-browser}/mergeEditor.contribution.ts (100%) rename src/vs/workbench/contrib/performance/{electron-sandbox => electron-browser}/performance.contribution.ts (100%) rename src/vs/workbench/contrib/performance/{electron-sandbox => electron-browser}/rendererAutoProfiler.ts (97%) rename src/vs/workbench/contrib/performance/{electron-sandbox => electron-browser}/startupProfiler.ts (99%) rename src/vs/workbench/contrib/performance/{electron-sandbox => electron-browser}/startupTimings.ts (99%) rename src/vs/workbench/contrib/processExplorer/{electron-sandbox => electron-browser}/processExplorer.contribution.ts (100%) rename src/vs/workbench/contrib/processExplorer/{electron-sandbox => electron-browser}/processExplorerControl.ts (100%) rename src/vs/workbench/contrib/processExplorer/{electron-sandbox => electron-browser}/processExplorerEditor.ts (100%) rename src/vs/workbench/contrib/remote/{electron-sandbox => electron-browser}/remote.contribution.ts (99%) rename src/vs/workbench/contrib/remoteTunnel/{electron-sandbox => electron-browser}/remoteTunnel.contribution.ts (100%) rename src/vs/workbench/contrib/splash/{electron-sandbox => electron-browser}/splash.contribution.ts (100%) rename src/vs/workbench/contrib/tags/{electron-sandbox => electron-browser}/tags.contribution.ts (100%) rename src/vs/workbench/contrib/tags/{electron-sandbox => electron-browser}/workspaceTags.ts (100%) rename src/vs/workbench/contrib/tags/{electron-sandbox => electron-browser}/workspaceTagsService.ts (100%) rename src/vs/workbench/contrib/tasks/{electron-sandbox => electron-browser}/taskService.ts (100%) rename src/vs/workbench/contrib/terminal/{electron-sandbox => electron-browser}/localPty.ts (100%) rename src/vs/workbench/contrib/terminal/{electron-sandbox => electron-browser}/localTerminalBackend.ts (99%) rename src/vs/workbench/contrib/terminal/{electron-sandbox => electron-browser}/terminal.contribution.ts (97%) rename src/vs/workbench/contrib/terminal/{electron-sandbox => electron-browser}/terminalNativeContribution.ts (99%) rename src/vs/workbench/contrib/terminal/{electron-sandbox => electron-browser}/terminalProfileResolverService.ts (100%) rename src/vs/workbench/contrib/terminal/{electron-sandbox => electron-browser}/terminalRemote.ts (100%) rename src/vs/workbench/contrib/userDataSync/{electron-sandbox => electron-browser}/userDataSync.contribution.ts (99%) rename src/vs/workbench/contrib/webview/{electron-sandbox => electron-browser}/webview.contribution.ts (100%) rename src/vs/workbench/contrib/webview/{electron-sandbox => electron-browser}/webviewCommands.ts (100%) rename src/vs/workbench/contrib/webview/{electron-sandbox => electron-browser}/webviewElement.ts (100%) rename src/vs/workbench/contrib/webview/{electron-sandbox => electron-browser}/webviewService.ts (100%) rename src/vs/workbench/contrib/webview/{electron-sandbox => electron-browser}/windowIgnoreMenuShortcutsManager.ts (100%) rename src/vs/workbench/{electron-sandbox => electron-browser}/actions/developerActions.ts (99%) rename src/vs/workbench/{electron-sandbox => electron-browser}/actions/installActions.ts (100%) rename src/vs/workbench/{electron-sandbox => electron-browser}/actions/media/actions.css (100%) rename src/vs/workbench/{electron-sandbox => electron-browser}/actions/windowActions.ts (99%) rename src/vs/workbench/{electron-sandbox => electron-browser}/desktop.contribution.ts (99%) rename src/vs/workbench/{electron-sandbox => electron-browser}/desktop.main.ts (96%) rename src/vs/workbench/{electron-sandbox => electron-browser}/media/window.css (100%) rename src/vs/workbench/{electron-sandbox => electron-browser}/parts/dialogs/dialog.contribution.ts (100%) rename src/vs/workbench/{electron-sandbox => electron-browser}/parts/dialogs/dialogHandler.ts (99%) rename src/vs/workbench/{electron-sandbox => electron-browser}/parts/titlebar/menubarControl.ts (98%) rename src/vs/workbench/{electron-sandbox => electron-browser}/parts/titlebar/titlebarPart.ts (99%) rename src/vs/workbench/{electron-sandbox => electron-browser}/window.ts (99%) rename src/vs/workbench/services/accessibility/{electron-sandbox => electron-browser}/accessibilityService.ts (99%) rename src/vs/workbench/services/auxiliaryWindow/{electron-sandbox => electron-browser}/auxiliaryWindowService.ts (99%) rename src/vs/workbench/services/browserElements/{electron-sandbox => electron-browser}/browserElementsService.ts (97%) rename src/vs/workbench/services/checksum/{electron-sandbox => electron-browser}/checksumService.ts (92%) rename src/vs/workbench/services/clipboard/{electron-sandbox => electron-browser}/clipboardService.ts (100%) rename src/vs/workbench/services/configurationResolver/{electron-sandbox => electron-browser}/configurationResolverService.ts (96%) rename src/vs/workbench/services/configurationResolver/test/{electron-sandbox => electron-browser}/configurationResolverService.test.ts (100%) rename src/vs/workbench/services/contextmenu/{electron-sandbox => electron-browser}/contextmenuService.ts (99%) rename src/vs/workbench/services/dialogs/{electron-sandbox => electron-browser}/fileDialogService.ts (100%) rename src/vs/workbench/services/dialogs/test/{electron-sandbox => electron-browser}/fileDialogService.test.ts (99%) rename src/vs/workbench/services/encryption/{electron-sandbox => electron-browser}/encryptionService.ts (93%) rename src/vs/workbench/services/environment/{electron-sandbox => electron-browser}/environmentService.ts (100%) rename src/vs/workbench/services/environment/{electron-sandbox => electron-browser}/shellEnvironmentService.ts (98%) rename src/vs/workbench/services/extensionManagement/{electron-sandbox => electron-browser}/extensionGalleryManifestService.ts (99%) rename src/vs/workbench/services/extensionManagement/{electron-sandbox => electron-browser}/extensionManagementServerService.ts (99%) rename src/vs/workbench/services/extensionManagement/{electron-sandbox => electron-browser}/extensionManagementService.ts (99%) rename src/vs/workbench/services/extensionManagement/{electron-sandbox => electron-browser}/extensionTipsService.ts (98%) rename src/vs/workbench/services/extensionManagement/{electron-sandbox => electron-browser}/nativeExtensionManagementService.ts (98%) rename src/vs/workbench/services/extensionManagement/{electron-sandbox => electron-browser}/remoteExtensionManagementService.ts (100%) rename src/vs/workbench/services/extensions/{electron-sandbox => electron-browser}/cachedExtensionScanner.ts (100%) rename src/vs/workbench/services/extensions/{electron-sandbox => electron-browser}/extensionHostProfiler.ts (100%) rename src/vs/workbench/services/extensions/{electron-sandbox => electron-browser}/extensionHostStarter.ts (93%) rename src/vs/workbench/services/extensions/{electron-sandbox => electron-browser}/extensionsScannerService.ts (100%) rename src/vs/workbench/services/extensions/{electron-sandbox => electron-browser}/localProcessExtensionHost.ts (99%) rename src/vs/workbench/services/extensions/{electron-sandbox => electron-browser}/nativeExtensionService.ts (100%) rename src/vs/workbench/services/files/{electron-sandbox => electron-browser}/diskFileSystemProvider.ts (99%) rename src/vs/workbench/services/files/{electron-sandbox => electron-browser}/elevatedFileService.ts (98%) rename src/vs/workbench/services/files/{electron-sandbox => electron-browser}/watcherClient.ts (97%) rename src/vs/workbench/services/host/{electron-sandbox => electron-browser}/nativeHostService.ts (99%) rename src/vs/workbench/services/integrity/{electron-sandbox => electron-browser}/integrityService.ts (100%) rename src/vs/workbench/services/keybinding/{electron-sandbox => electron-browser}/nativeKeyboardLayout.ts (100%) rename src/vs/workbench/services/keybinding/{electron-sandbox => electron-browser}/nativeKeyboardLayoutService.ts (100%) rename src/vs/workbench/services/lifecycle/{electron-sandbox => electron-browser}/lifecycleService.ts (99%) rename src/vs/workbench/services/lifecycle/test/{electron-sandbox => electron-browser}/lifecycleService.test.ts (98%) rename src/vs/workbench/services/localization/{electron-sandbox => electron-browser}/languagePackService.ts (93%) rename src/vs/workbench/services/localization/{electron-sandbox => electron-browser}/localeService.ts (100%) rename src/vs/workbench/services/log/{electron-sandbox => electron-browser}/logService.ts (97%) rename src/vs/workbench/services/menubar/{electron-sandbox => electron-browser}/menubarService.ts (88%) rename src/vs/workbench/services/path/{electron-sandbox => electron-browser}/pathService.ts (96%) rename src/vs/workbench/services/process/{electron-sandbox => electron-browser}/processService.ts (93%) rename src/vs/workbench/services/remote/{electron-sandbox => electron-browser}/remoteAgentService.ts (100%) rename src/vs/workbench/services/request/{electron-sandbox => electron-browser}/requestService.ts (100%) rename src/vs/workbench/services/search/{electron-sandbox => electron-browser}/searchService.ts (100%) rename src/vs/workbench/services/secrets/{electron-sandbox => electron-browser}/secretStorageService.ts (100%) rename src/vs/workbench/services/sharedProcess/{electron-sandbox => electron-browser}/sharedProcessService.ts (98%) rename src/vs/workbench/services/storage/{electron-sandbox => electron-browser}/storageService.ts (100%) rename src/vs/workbench/services/telemetry/{electron-sandbox => electron-browser}/telemetryService.ts (97%) rename src/vs/workbench/services/textfile/{electron-sandbox => electron-browser}/nativeTextFileService.ts (99%) rename src/vs/workbench/services/textfile/test/{electron-sandbox => electron-browser}/nativeTextFileService.io.test.ts (98%) rename src/vs/workbench/services/textfile/test/{electron-sandbox => electron-browser}/nativeTextFileService.test.ts (98%) rename src/vs/workbench/services/themes/{electron-sandbox => electron-browser}/nativeHostColorSchemeService.ts (98%) rename src/vs/workbench/services/themes/{electron-sandbox => electron-browser}/themes.contribution.ts (100%) rename src/vs/workbench/services/timer/{electron-sandbox => electron-browser}/timerService.ts (98%) rename src/vs/workbench/services/title/{electron-sandbox => electron-browser}/titleService.ts (90%) rename src/vs/workbench/services/tunnel/{electron-sandbox => electron-browser}/tunnelService.ts (99%) rename src/vs/workbench/services/update/{electron-sandbox => electron-browser}/updateService.ts (94%) rename src/vs/workbench/services/url/{electron-sandbox => electron-browser}/urlService.ts (100%) rename src/vs/workbench/services/userDataSync/{electron-sandbox => electron-browser}/userDataAutoSyncService.ts (98%) rename src/vs/workbench/services/userDataSync/{electron-sandbox => electron-browser}/userDataSyncService.ts (97%) rename src/vs/workbench/services/utilityProcess/{electron-sandbox => electron-browser}/utilityProcessWorkerWorkbenchService.ts (99%) rename src/vs/workbench/services/workingCopy/{electron-sandbox => electron-browser}/workingCopyBackupService.ts (98%) rename src/vs/workbench/services/workingCopy/{electron-sandbox => electron-browser}/workingCopyBackupTracker.ts (100%) rename src/vs/workbench/services/workingCopy/{electron-sandbox => electron-browser}/workingCopyHistoryService.ts (100%) rename src/vs/workbench/services/workingCopy/test/{electron-sandbox => electron-browser}/workingCopyBackupService.test.ts (99%) rename src/vs/workbench/services/workingCopy/test/{electron-sandbox => electron-browser}/workingCopyBackupTracker.test.ts (99%) rename src/vs/workbench/services/workingCopy/test/{electron-sandbox => electron-browser}/workingCopyHistoryService.test.ts (100%) rename src/vs/workbench/services/workingCopy/test/{electron-sandbox => electron-browser}/workingCopyHistoryTracker.test.ts (100%) rename src/vs/workbench/services/workspaces/{electron-sandbox => electron-browser}/workspaceEditingService.ts (99%) rename src/vs/workbench/services/workspaces/{electron-sandbox => electron-browser}/workspacesService.ts (100%) rename src/vs/workbench/test/{electron-sandbox => electron-browser}/resolveExternal.test.ts (98%) rename src/vs/workbench/test/{electron-sandbox => electron-browser}/workbenchTestServices.ts (99%) diff --git a/.eslint-plugin-local/code-import-patterns.ts b/.eslint-plugin-local/code-import-patterns.ts index ed14fa35d5a..e4beb9a4738 100644 --- a/.eslint-plugin-local/code-import-patterns.ts +++ b/.eslint-plugin-local/code-import-patterns.ts @@ -18,7 +18,7 @@ interface ConditionalPattern { interface RawImportPatternsConfig { target: string; - layer?: 'common' | 'worker' | 'browser' | 'electron-sandbox' | 'node' | 'electron-utility' | 'electron-main'; + layer?: 'common' | 'worker' | 'browser' | 'electron-browser' | 'node' | 'electron-utility' | 'electron-main'; test?: boolean; restrictions: string | (string | ConditionalPattern)[]; } @@ -80,7 +80,7 @@ export = new class implements eslint.Rule.RuleModule { return this._optionsCache.get(options)!; } - type Layer = 'common' | 'worker' | 'browser' | 'electron-sandbox' | 'node' | 'electron-utility' | 'electron-main'; + type Layer = 'common' | 'worker' | 'browser' | 'electron-browser' | 'node' | 'electron-utility' | 'electron-main'; interface ILayerRule { layer: Layer; @@ -98,7 +98,7 @@ export = new class implements eslint.Rule.RuleModule { { layer: 'common', deps: orSegment(['common']) }, { layer: 'worker', deps: orSegment(['common', 'worker']) }, { layer: 'browser', deps: orSegment(['common', 'browser']), isBrowser: true }, - { layer: 'electron-sandbox', deps: orSegment(['common', 'browser', 'electron-sandbox']), isBrowser: true }, + { layer: 'electron-browser', deps: orSegment(['common', 'browser', 'electron-browser']), isBrowser: true }, { layer: 'node', deps: orSegment(['common', 'node']), isNode: true }, { layer: 'electron-utility', deps: orSegment(['common', 'node', 'electron-utility']), isNode: true, isElectron: true }, { layer: 'electron-main', deps: orSegment(['common', 'node', 'electron-utility', 'electron-main']), isNode: true, isElectron: true }, diff --git a/build/buildfile.js b/build/buildfile.js index b1ce1186d4e..b5e8f6e7e6c 100644 --- a/build/buildfile.js +++ b/build/buildfile.js @@ -18,7 +18,7 @@ exports.workerExtensionHost = createModuleDescription('vs/workbench/api/worker/e exports.workerNotebook = createModuleDescription('vs/workbench/contrib/notebook/common/services/notebookWebWorkerMain'); exports.workerLanguageDetection = createModuleDescription('vs/workbench/services/languageDetection/browser/languageDetectionWebWorkerMain'); exports.workerLocalFileSearch = createModuleDescription('vs/workbench/services/search/worker/localFileSearchMain'); -exports.workerProfileAnalysis = createModuleDescription('vs/platform/profiling/electron-sandbox/profileAnalysisWorkerMain'); +exports.workerProfileAnalysis = createModuleDescription('vs/platform/profiling/electron-browser/profileAnalysisWorkerMain'); exports.workerOutputLinks = createModuleDescription('vs/workbench/contrib/output/common/outputLinkComputerMain'); exports.workerBackgroundTokenization = createModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.workerMain'); @@ -43,7 +43,7 @@ exports.code = [ // 'vs/code/node/cli' is not included here because it comes in via ./src/cli.js createModuleDescription('vs/code/node/cliProcessMain'), createModuleDescription('vs/code/electron-utility/sharedProcess/sharedProcessMain'), - createModuleDescription('vs/code/electron-sandbox/workbench/workbench'), + createModuleDescription('vs/code/electron-browser/workbench/workbench'), createModuleDescription('vs/workbench/contrib/webview/browser/pre/service-worker') ]; diff --git a/build/checker/layersChecker.js b/build/checker/layersChecker.js index 0c30e64baa0..b2e319b5ecb 100644 --- a/build/checker/layersChecker.js +++ b/build/checker/layersChecker.js @@ -53,9 +53,9 @@ const RULES = [ ].join(',')}}`, disallowedTypes: [ /* Ignore native types that are defined from here */], }, - // Common: vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts + // Common: vs/base/parts/sandbox/electron-browser/preload{,-aux}.ts { - target: '**/vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts', + target: '**/vs/base/parts/sandbox/electron-browser/preload{,-aux}.ts', disallowedTypes: NATIVE_TYPES, }, // Common @@ -63,6 +63,11 @@ const RULES = [ target: '**/vs/**/common/**', disallowedTypes: NATIVE_TYPES, }, + // Common + { + target: '**/vs/**/worker/**', + disallowedTypes: NATIVE_TYPES, + }, // Browser { target: '**/vs/**/browser/**', diff --git a/build/checker/layersChecker.ts b/build/checker/layersChecker.ts index 6337967b248..68e12e61c40 100644 --- a/build/checker/layersChecker.ts +++ b/build/checker/layersChecker.ts @@ -55,9 +55,9 @@ const RULES: IRule[] = [ disallowedTypes: [/* Ignore native types that are defined from here */], }, - // Common: vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts + // Common: vs/base/parts/sandbox/electron-browser/preload{,-aux}.ts { - target: '**/vs/base/parts/sandbox/electron-sandbox/preload{,-aux}.ts', + target: '**/vs/base/parts/sandbox/electron-browser/preload{,-aux}.ts', disallowedTypes: NATIVE_TYPES, }, @@ -67,6 +67,12 @@ const RULES: IRule[] = [ disallowedTypes: NATIVE_TYPES, }, + // Common + { + target: '**/vs/**/worker/**', + disallowedTypes: NATIVE_TYPES, + }, + // Browser { target: '**/vs/**/browser/**', diff --git a/build/checker/tsconfig.browser.json b/build/checker/tsconfig.browser.json index 098a4ffbb1e..67868ef7575 100644 --- a/build/checker/tsconfig.browser.json +++ b/build/checker/tsconfig.browser.json @@ -11,6 +11,7 @@ "skipLibCheck": true }, "include": [ + "../../src/*.ts", "../../src/**/common/**/*.ts", "../../src/**/browser/**/*.ts", "../../src/typings/*.d.ts", diff --git a/build/checker/tsconfig.electron-sandbox.json b/build/checker/tsconfig.electron-browser.json similarity index 78% rename from build/checker/tsconfig.electron-sandbox.json rename to build/checker/tsconfig.electron-browser.json index 88c04da1c2d..2cbe3d3bd33 100644 --- a/build/checker/tsconfig.electron-sandbox.json +++ b/build/checker/tsconfig.electron-browser.json @@ -3,7 +3,7 @@ "include": [ "../../src/**/common/**/*.ts", "../../src/**/browser/**/*.ts", - "../../src/**/electron-sandbox/**/*.ts", + "../../src/**/electron-browser/**/*.ts", "../../src/typings/*.d.ts", "../../src/vs/monaco.d.ts", "../../src/vscode-dts/vscode.proposed.*.d.ts", @@ -15,7 +15,7 @@ "exclude": [ "../../src/**/test/**", "../../src/**/fixtures/**", - "../../src/vs/base/parts/sandbox/electron-sandbox/preload.ts", // Preload scripts for Electron sandbox - "../../src/vs/base/parts/sandbox/electron-sandbox/preload-aux.ts" // have limited access to node.js APIs + "../../src/vs/base/parts/sandbox/electron-browser/preload.ts", // Preload scripts for Electron sandbox + "../../src/vs/base/parts/sandbox/electron-browser/preload-aux.ts" // have limited access to node.js APIs ] } diff --git a/build/checker/tsconfig.electron-main.json b/build/checker/tsconfig.electron-main.json index 3cb4450c701..a275f65d9e5 100644 --- a/build/checker/tsconfig.electron-main.json +++ b/build/checker/tsconfig.electron-main.json @@ -1,9 +1,13 @@ { "extends": "./tsconfig.node.json", "include": [ + "../../src/**/common/**/*.ts", + "../../src/**/node/**/*.ts", "../../src/**/electron-main/**/*.ts", - "../../src/**/electron-utility/**/*.ts", "../../src/typings/*.d.ts", + "../../src/vs/monaco.d.ts", + "../../src/vscode-dts/vscode.proposed.*.d.ts", + "../../src/vscode-dts/vscode.d.ts", "../../node_modules/@types/trusted-types/index.d.ts", ], "exclude": [ diff --git a/build/checker/tsconfig.electron-utility.json b/build/checker/tsconfig.electron-utility.json new file mode 100644 index 00000000000..25b33be427d --- /dev/null +++ b/build/checker/tsconfig.electron-utility.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.node.json", + "include": [ + "../../src/**/common/**/*.ts", + "../../src/**/node/**/*.ts", + "../../src/**/electron-utility/**/*.ts", + "../../src/typings/*.d.ts", + "../../src/vs/monaco.d.ts", + "../../src/vscode-dts/vscode.proposed.*.d.ts", + "../../src/vscode-dts/vscode.d.ts", + "../../node_modules/@types/trusted-types/index.d.ts", + ], + "exclude": [ + "../../src/**/test/**", + "../../src/**/fixtures/**", + ] +} diff --git a/build/checker/tsconfig.node.json b/build/checker/tsconfig.node.json index 0b2a09b83f6..2e483136e08 100644 --- a/build/checker/tsconfig.node.json +++ b/build/checker/tsconfig.node.json @@ -11,6 +11,7 @@ "skipLibCheck": true }, "include": [ + "../../src/*.ts", "../../src/**/common/**/*.ts", "../../src/**/node/**/*.ts", "../../src/typings/*.d.ts", diff --git a/build/checker/tsconfig.worker.json b/build/checker/tsconfig.worker.json new file mode 100644 index 00000000000..ebb919bf0f2 --- /dev/null +++ b/build/checker/tsconfig.worker.json @@ -0,0 +1,28 @@ +{ + "extends": "../../src/tsconfig.base.json", + "compilerOptions": { + "lib": [ + "ES2022", + "WebWorker", + "Webworker.Iterable", + "WebWorker.AsyncIterable" + ], + "types": [], + "noEmit": true, + "skipLibCheck": true + }, + "include": [ + "../../src/**/common/**/*.ts", + "../../src/**/worker/**/*.ts", + "../../src/typings/*.d.ts", + "../../src/vs/monaco.d.ts", + "../../src/vscode-dts/vscode.proposed.*.d.ts", + "../../src/vscode-dts/vscode.d.ts", + "../../node_modules/@types/trusted-types/index.d.ts", + "../../node_modules/@types/wicg-file-system-access/index.d.ts" + ], + "exclude": [ + "../../src/**/test/**", + "../../src/**/fixtures/**" + ] +} diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index c3db770d0a0..ba9f0e46ff0 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -80,7 +80,7 @@ const serverResourceIncludes = [ ]; const serverResourceExcludes = [ - '!out-build/vs/**/{electron-sandbox,electron-main,electron-utility}/**', + '!out-build/vs/**/{electron-browser,electron-main,electron-utility}/**', '!out-build/vs/editor/standalone/**', '!out-build/vs/workbench/**/*-tb.png', '!**/test/**' diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 610cbc389fc..f819cd6a1c2 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -57,11 +57,11 @@ const vscodeResourceIncludes = [ 'out-build/nls.keys.json', // Workbench - 'out-build/vs/code/electron-sandbox/workbench/workbench.html', + 'out-build/vs/code/electron-browser/workbench/workbench.html', // Electron Preload - 'out-build/vs/base/parts/sandbox/electron-sandbox/preload.js', - 'out-build/vs/base/parts/sandbox/electron-sandbox/preload-aux.js', + 'out-build/vs/base/parts/sandbox/electron-browser/preload.js', + 'out-build/vs/base/parts/sandbox/electron-browser/preload-aux.js', // Node Scripts 'out-build/vs/base/node/{terminateProcess.sh,cpuUsage.sh,ps.sh}', @@ -138,7 +138,7 @@ const bundleVSCodeTask = task.define('bundle-vscode', task.series( ...bootstrapEntryPoints ], resources: vscodeResources, - skipTSBoilerplateRemoval: entryPoint => entryPoint === 'vs/code/electron-sandbox/workbench/workbench' + skipTSBoilerplateRemoval: entryPoint => entryPoint === 'vs/code/electron-browser/workbench/workbench' } } ) @@ -220,12 +220,12 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const out = sourceFolderName; const checksums = computeChecksums(out, [ - 'vs/base/parts/sandbox/electron-sandbox/preload.js', + 'vs/base/parts/sandbox/electron-browser/preload.js', 'vs/workbench/workbench.desktop.main.js', 'vs/workbench/workbench.desktop.main.css', 'vs/workbench/api/node/extensionHostProcess.js', - 'vs/code/electron-sandbox/workbench/workbench.html', - 'vs/code/electron-sandbox/workbench/workbench.js' + 'vs/code/electron-browser/workbench/workbench.html', + 'vs/code/electron-browser/workbench/workbench.js' ]); const src = gulp.src(out + '/**', { base: '.' }) diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index 72423c765ea..08dfcfd0cd9 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -66,7 +66,7 @@ const vscodeWebResources = [ ...vscodeWebResourceIncludes, // Excludes - '!out-build/vs/**/{node,electron-sandbox,electron-main,electron-utility}/**', + '!out-build/vs/**/{node,electron-browser,electron-main,electron-utility}/**', '!out-build/vs/editor/standalone/**', '!out-build/vs/workbench/**/*-tb.png', '!out-build/vs/code/**/*-dev.html', diff --git a/eslint.config.js b/eslint.config.js index 7067b7ea730..dde24771a66 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -99,7 +99,7 @@ export default tseslint.config( 'browser': [ 'common' ], - 'electron-sandbox': [ + 'electron-browser': [ 'common', 'browser' ], @@ -406,10 +406,10 @@ export default tseslint.config( ] } }, - // browser/electron-sandbox layer + // browser/electron-browser layer { files: [ - 'src/**/{browser,electron-sandbox}/**/*.ts' + 'src/**/{browser,electron-browser}/**/*.ts' ], languageOptions: { parser: tseslint.parser, @@ -770,7 +770,7 @@ export default tseslint.config( { // imports that are allowed in all files of layers: // - browser - // - electron-sandbox + // - electron-browser 'when': 'hasBrowser', 'allow': [] }, @@ -866,18 +866,18 @@ export default tseslint.config( // - src/vs/base/common // - src/vs/base/worker // - src/vs/base/browser - // - src/vs/base/electron-sandbox + // - src/vs/base/electron-browser // - src/vs/base/node // - src/vs/base/electron-main // - src/vs/base/test/common // - src/vs/base/test/worker // - src/vs/base/test/browser - // - src/vs/base/test/electron-sandbox + // - src/vs/base/test/electron-browser // - src/vs/base/test/node // - src/vs/base/test/electron-main // // When /~ is used in the restrictions, it will be replaced with the correct - // layers that can be used e.g. 'src/vs/base/electron-sandbox' will be able + // layers that can be used e.g. 'src/vs/base/electron-browser' will be able // to import '{common,browser,electron-sanbox}', etc. // // It is possible to use /~ in the restrictions property even without using it in @@ -1203,7 +1203,7 @@ export default tseslint.config( }, { 'target': 'src/vs/workbench/workbench.desktop.main.ts', - 'layer': 'electron-sandbox', + 'layer': 'electron-browser', 'restrictions': [ 'vs/base/*/~', 'vs/base/parts/*/~', diff --git a/package.json b/package.json index 0a4e6295ad1..49da9b08d69 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", "tsec-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.tsec.json", "vscode-dts-compile-check": "tsc -p src/tsconfig.vscode-dts.json && tsc -p src/tsconfig.vscode-proposed-dts.json", - "valid-layers-check": "node build/checker/layersChecker.js && tsc -p build/checker/tsconfig.browser.json && tsc -p build/checker/tsconfig.node.json && tsc -p build/checker/tsconfig.electron-sandbox.json && tsc -p build/checker/tsconfig.electron-main.json", + "valid-layers-check": "node build/checker/layersChecker.js && tsc -p build/checker/tsconfig.browser.json && tsc -p build/checker/tsconfig.worker.json && tsc -p build/checker/tsconfig.node.json && tsc -p build/checker/tsconfig.electron-browser.json && tsc -p build/checker/tsconfig.electron-main.json && tsc -p build/checker/tsconfig.electron-utility.json", "define-class-fields-check": "node build/lib/propertyInitOrderChecker.js && tsc -p src/tsconfig.defineClassFields.json", "update-distro": "node build/npm/update-distro.mjs", "web": "echo 'npm run web' is replaced by './scripts/code-server' or './scripts/code-web'", diff --git a/src/bootstrap-import.ts b/src/bootstrap-import.ts index 8869058159d..9d222a003eb 100644 --- a/src/bootstrap-import.ts +++ b/src/bootstrap-import.ts @@ -6,7 +6,7 @@ // ********************************************************************* // * * // * We need this to redirect to node_modules from the remote-folder. * -// * This ONLY applies when running out of source. * +// * This ONLY applies when running out of source. * // * * // ********************************************************************* diff --git a/src/tsec.exemptions.json b/src/tsec.exemptions.json index 5bb86c7a91f..f913df5e7da 100644 --- a/src/tsec.exemptions.json +++ b/src/tsec.exemptions.json @@ -1,6 +1,6 @@ { "ban-document-execcommand": [ - "vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts", + "vs/workbench/contrib/codeEditor/electron-browser/inputClipboardActions.ts", "vs/editor/contrib/clipboard/browser/clipboard.ts" ], "ban-eval-calls": [ @@ -12,7 +12,7 @@ "vs/workbench/services/keybinding/test/node/keyboardMapperTestUtils.ts" ], "ban-trustedtypes-createpolicy": [ - "vs/code/electron-sandbox/workbench/workbench.ts", + "vs/code/electron-browser/workbench/workbench.ts", "vs/amdX.ts", "vs/base/browser/trustedTypes.ts", "vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts" @@ -37,6 +37,6 @@ "**/*.ts" ], "ban-script-content-assignments": [ - "vs/code/electron-sandbox/workbench/workbench.ts" + "vs/code/electron-browser/workbench/workbench.ts" ] } diff --git a/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts b/src/vs/base/parts/contextmenu/electron-browser/contextmenu.ts similarity index 97% rename from src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts rename to src/vs/base/parts/contextmenu/electron-browser/contextmenu.ts index 845cf33c343..3eab2e24b9d 100644 --- a/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts +++ b/src/vs/base/parts/contextmenu/electron-browser/contextmenu.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CONTEXT_MENU_CHANNEL, CONTEXT_MENU_CLOSE_CHANNEL, IContextMenuEvent, IContextMenuItem, IPopupOptions, ISerializableContextMenuItem } from '../common/contextmenu.js'; -import { ipcRenderer } from '../../sandbox/electron-sandbox/globals.js'; +import { ipcRenderer } from '../../sandbox/electron-browser/globals.js'; let contextMenuIdPool = 0; diff --git a/src/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts b/src/vs/base/parts/ipc/electron-browser/ipc.electron.ts similarity index 95% rename from src/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts rename to src/vs/base/parts/ipc/electron-browser/ipc.electron.ts index 553a310e978..4a0ae19a37d 100644 --- a/src/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts +++ b/src/vs/base/parts/ipc/electron-browser/ipc.electron.ts @@ -8,7 +8,7 @@ import { Event } from '../../../common/event.js'; import { IDisposable } from '../../../common/lifecycle.js'; import { IPCClient } from '../common/ipc.js'; import { Protocol as ElectronProtocol } from '../common/ipc.electron.js'; -import { ipcRenderer } from '../../sandbox/electron-sandbox/globals.js'; +import { ipcRenderer } from '../../sandbox/electron-browser/globals.js'; /** * An implementation of `IPCClient` on top of Electron `ipcRenderer` IPC communication diff --git a/src/vs/base/parts/ipc/electron-sandbox/ipc.mp.ts b/src/vs/base/parts/ipc/electron-browser/ipc.mp.ts similarity index 98% rename from src/vs/base/parts/ipc/electron-sandbox/ipc.mp.ts rename to src/vs/base/parts/ipc/electron-browser/ipc.mp.ts index 4a36b238817..407ff931794 100644 --- a/src/vs/base/parts/ipc/electron-sandbox/ipc.mp.ts +++ b/src/vs/base/parts/ipc/electron-browser/ipc.mp.ts @@ -6,7 +6,7 @@ import { mainWindow } from '../../../browser/window.js'; import { Event } from '../../../common/event.js'; import { generateUuid } from '../../../common/uuid.js'; -import { ipcMessagePort, ipcRenderer } from '../../sandbox/electron-sandbox/globals.js'; +import { ipcMessagePort, ipcRenderer } from '../../sandbox/electron-browser/globals.js'; interface IMessageChannelResult { nonce: string; diff --git a/src/vs/base/parts/ipc/electron-main/ipc.mp.ts b/src/vs/base/parts/ipc/electron-main/ipc.mp.ts index dacaac11a56..4f2dc1987b3 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.mp.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.mp.ts @@ -34,7 +34,7 @@ export class Client extends MessagePortClient implements IDisposable { /** * This method opens a message channel connection * in the target window. The target window needs - * to use the `Server` from `electron-sandbox/ipc.mp`. + * to use the `Server` from `electron-browser/ipc.mp`. */ export async function connect(window: BrowserWindow): Promise { diff --git a/src/vs/base/parts/ipc/test/electron-sandbox/ipc.mp.test.ts b/src/vs/base/parts/ipc/test/electron-browser/ipc.mp.test.ts similarity index 100% rename from src/vs/base/parts/ipc/test/electron-sandbox/ipc.mp.test.ts rename to src/vs/base/parts/ipc/test/electron-browser/ipc.mp.test.ts diff --git a/src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts b/src/vs/base/parts/sandbox/electron-browser/electronTypes.ts similarity index 99% rename from src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts rename to src/vs/base/parts/sandbox/electron-browser/electronTypes.ts index a132d7d6eb4..cbf98ff13c5 100644 --- a/src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts +++ b/src/vs/base/parts/sandbox/electron-browser/electronTypes.ts @@ -6,7 +6,7 @@ // ####################################################################### // ### ### -// ### electron.d.ts types we expose from electron-sandbox ### +// ### electron.d.ts types we expose from electron-browser ### // ### (copied from Electron 29.x) ### // ### ### // ####################################################################### diff --git a/src/vs/base/parts/sandbox/electron-sandbox/globals.ts b/src/vs/base/parts/sandbox/electron-browser/globals.ts similarity index 100% rename from src/vs/base/parts/sandbox/electron-sandbox/globals.ts rename to src/vs/base/parts/sandbox/electron-browser/globals.ts diff --git a/src/vs/base/parts/sandbox/electron-sandbox/preload-aux.ts b/src/vs/base/parts/sandbox/electron-browser/preload-aux.ts similarity index 100% rename from src/vs/base/parts/sandbox/electron-sandbox/preload-aux.ts rename to src/vs/base/parts/sandbox/electron-browser/preload-aux.ts diff --git a/src/vs/base/parts/sandbox/electron-sandbox/preload.ts b/src/vs/base/parts/sandbox/electron-browser/preload.ts similarity index 100% rename from src/vs/base/parts/sandbox/electron-sandbox/preload.ts rename to src/vs/base/parts/sandbox/electron-browser/preload.ts diff --git a/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts b/src/vs/base/parts/sandbox/test/electron-browser/globals.test.ts similarity index 96% rename from src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts rename to src/vs/base/parts/sandbox/test/electron-browser/globals.test.ts index d979b221111..dcc6b0abc18 100644 --- a/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts +++ b/src/vs/base/parts/sandbox/test/electron-browser/globals.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { ipcRenderer, process, webFrame, webUtils } from '../../electron-sandbox/globals.js'; +import { ipcRenderer, process, webFrame, webUtils } from '../../electron-browser/globals.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../test/common/utils.js'; suite('Sandbox', () => { diff --git a/src/vs/base/test/common/labels.test.ts b/src/vs/base/test/common/labels.test.ts index 9e3feeb4d34..dd91ac24b97 100644 --- a/src/vs/base/test/common/labels.test.ts +++ b/src/vs/base/test/common/labels.test.ts @@ -60,7 +60,7 @@ suite('Labels', () => { assert.deepStrictEqual(labels.shorten(['a', 'a\\b', 'a\\b\\c', 'd\\b\\c', 'd\\b']), ['a', 'a\\b', 'a\\b\\c', 'd\\b\\c', 'd\\b']); assert.deepStrictEqual(labels.shorten(['a', 'a\\b', 'b']), ['a', 'a\\b', 'b']); assert.deepStrictEqual(labels.shorten(['', 'a', 'b', 'b\\c', 'a\\c']), ['.\\', 'a', 'b', 'b\\c', 'a\\c']); - assert.deepStrictEqual(labels.shorten(['src\\vs\\workbench\\parts\\execution\\electron-sandbox', 'src\\vs\\workbench\\parts\\execution\\electron-sandbox\\something', 'src\\vs\\workbench\\parts\\terminal\\electron-sandbox']), ['…\\execution\\electron-sandbox', '…\\something', '…\\terminal\\…']); + assert.deepStrictEqual(labels.shorten(['src\\vs\\workbench\\parts\\execution\\electron-browser', 'src\\vs\\workbench\\parts\\execution\\electron-browser\\something', 'src\\vs\\workbench\\parts\\terminal\\electron-browser']), ['…\\execution\\electron-browser', '…\\something', '…\\terminal\\…']); }); (isWindows ? test.skip : test)('shorten - not windows', () => { diff --git a/src/vs/code/electron-sandbox/workbench/workbench-dev.html b/src/vs/code/electron-browser/workbench/workbench-dev.html similarity index 100% rename from src/vs/code/electron-sandbox/workbench/workbench-dev.html rename to src/vs/code/electron-browser/workbench/workbench-dev.html diff --git a/src/vs/code/electron-sandbox/workbench/workbench.html b/src/vs/code/electron-browser/workbench/workbench.html similarity index 100% rename from src/vs/code/electron-sandbox/workbench/workbench.html rename to src/vs/code/electron-browser/workbench/workbench.html diff --git a/src/vs/code/electron-sandbox/workbench/workbench.ts b/src/vs/code/electron-browser/workbench/workbench.ts similarity index 98% rename from src/vs/code/electron-sandbox/workbench/workbench.ts rename to src/vs/code/electron-browser/workbench/workbench.ts index 8c9ff16ec64..a49f0b2f278 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.ts +++ b/src/vs/code/electron-browser/workbench/workbench.ts @@ -11,11 +11,11 @@ performance.mark('code/didStartRenderer'); type ISandboxConfiguration = import('../../../base/parts/sandbox/common/sandboxTypes.js').ISandboxConfiguration; - type ILoadResult = import('../../../platform/window/electron-sandbox/window.js').ILoadResult; - type ILoadOptions = import('../../../platform/window/electron-sandbox/window.js').ILoadOptions; + type ILoadResult = import('../../../platform/window/electron-browser/window.js').ILoadResult; + type ILoadOptions = import('../../../platform/window/electron-browser/window.js').ILoadOptions; type INativeWindowConfiguration = import('../../../platform/window/common/window.ts').INativeWindowConfiguration; - type IMainWindowSandboxGlobals = import('../../../base/parts/sandbox/electron-sandbox/globals.js').IMainWindowSandboxGlobals; - type IDesktopMain = import('../../../workbench/electron-sandbox/desktop.main.js').IDesktopMain; + type IMainWindowSandboxGlobals = import('../../../base/parts/sandbox/electron-browser/globals.js').IMainWindowSandboxGlobals; + type IDesktopMain = import('../../../workbench/electron-browser/desktop.main.js').IDesktopMain; const preloadGlobals: IMainWindowSandboxGlobals = (window as any).vscode; // defined by preload.ts const safeProcess = preloadGlobals.process; diff --git a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts index 12754b8b00a..882dfac434c 100644 --- a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts +++ b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts @@ -93,7 +93,7 @@ export class AuxiliaryWindowsMainService extends Disposable implements IAuxiliar createWindow(details: HandlerDetails): BrowserWindowConstructorOptions { const { state, overrides } = this.computeWindowStateAndOverrides(details); return this.instantiationService.invokeFunction(defaultBrowserWindowOptions, state, overrides, { - preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-sandbox/preload-aux.js').fsPath + preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload-aux.js').fsPath }); } diff --git a/src/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts b/src/vs/platform/diagnostics/electron-browser/diagnosticsService.ts similarity index 95% rename from src/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts rename to src/vs/platform/diagnostics/electron-browser/diagnosticsService.ts index f984d59c5bc..340daeb42af 100644 --- a/src/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts +++ b/src/vs/platform/diagnostics/electron-browser/diagnosticsService.ts @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { IDiagnosticsService } from '../common/diagnostics.js'; -import { registerSharedProcessRemoteService } from '../../ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../ipc/electron-browser/services.js'; registerSharedProcessRemoteService(IDiagnosticsService, 'diagnostics'); diff --git a/src/vs/platform/extensionManagement/electron-sandbox/extensionsProfileScannerService.ts b/src/vs/platform/extensionManagement/electron-browser/extensionsProfileScannerService.ts similarity index 100% rename from src/vs/platform/extensionManagement/electron-sandbox/extensionsProfileScannerService.ts rename to src/vs/platform/extensionManagement/electron-browser/extensionsProfileScannerService.ts diff --git a/src/vs/platform/externalTerminal/electron-sandbox/externalTerminalService.ts b/src/vs/platform/externalTerminal/electron-browser/externalTerminalService.ts similarity index 97% rename from src/vs/platform/externalTerminal/electron-sandbox/externalTerminalService.ts rename to src/vs/platform/externalTerminal/electron-browser/externalTerminalService.ts index ef1fe8b73df..cdea035f7c8 100644 --- a/src/vs/platform/externalTerminal/electron-sandbox/externalTerminalService.ts +++ b/src/vs/platform/externalTerminal/electron-browser/externalTerminalService.ts @@ -5,7 +5,7 @@ import { IExternalTerminalService as ICommonExternalTerminalService } from '../common/externalTerminal.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; -import { registerMainProcessRemoteService } from '../../ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService } from '../../ipc/electron-browser/services.js'; export const IExternalTerminalService = createDecorator('externalTerminal'); diff --git a/src/vs/platform/ipc/electron-sandbox/mainProcessService.ts b/src/vs/platform/ipc/electron-browser/mainProcessService.ts similarity index 97% rename from src/vs/platform/ipc/electron-sandbox/mainProcessService.ts rename to src/vs/platform/ipc/electron-browser/mainProcessService.ts index 8707d26a237..618d8f70ef4 100644 --- a/src/vs/platform/ipc/electron-sandbox/mainProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/mainProcessService.ts @@ -5,7 +5,7 @@ import { Disposable } from '../../../base/common/lifecycle.js'; import { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js'; -import { Client as IPCElectronClient } from '../../../base/parts/ipc/electron-sandbox/ipc.electron.js'; +import { Client as IPCElectronClient } from '../../../base/parts/ipc/electron-browser/ipc.electron.js'; import { IMainProcessService } from '../common/mainProcessService.js'; /** diff --git a/src/vs/platform/ipc/electron-sandbox/services.ts b/src/vs/platform/ipc/electron-browser/services.ts similarity index 100% rename from src/vs/platform/ipc/electron-sandbox/services.ts rename to src/vs/platform/ipc/electron-browser/services.ts diff --git a/src/vs/platform/menubar/electron-sandbox/menubar.ts b/src/vs/platform/menubar/electron-browser/menubar.ts similarity index 100% rename from src/vs/platform/menubar/electron-sandbox/menubar.ts rename to src/vs/platform/menubar/electron-browser/menubar.ts diff --git a/src/vs/platform/profiling/electron-sandbox/profileAnalysisWorker.ts b/src/vs/platform/profiling/electron-browser/profileAnalysisWorker.ts similarity index 100% rename from src/vs/platform/profiling/electron-sandbox/profileAnalysisWorker.ts rename to src/vs/platform/profiling/electron-browser/profileAnalysisWorker.ts diff --git a/src/vs/platform/profiling/electron-sandbox/profileAnalysisWorkerMain.ts b/src/vs/platform/profiling/electron-browser/profileAnalysisWorkerMain.ts similarity index 100% rename from src/vs/platform/profiling/electron-sandbox/profileAnalysisWorkerMain.ts rename to src/vs/platform/profiling/electron-browser/profileAnalysisWorkerMain.ts diff --git a/src/vs/platform/profiling/electron-sandbox/profileAnalysisWorkerService.ts b/src/vs/platform/profiling/electron-browser/profileAnalysisWorkerService.ts similarity index 97% rename from src/vs/platform/profiling/electron-sandbox/profileAnalysisWorkerService.ts rename to src/vs/platform/profiling/electron-browser/profileAnalysisWorkerService.ts index b53efdadc1a..1edace6dcaf 100644 --- a/src/vs/platform/profiling/electron-sandbox/profileAnalysisWorkerService.ts +++ b/src/vs/platform/profiling/electron-browser/profileAnalysisWorkerService.ts @@ -49,7 +49,7 @@ class ProfileAnalysisWorkerService implements IProfileAnalysisWorkerService { private async _withWorker(callback: (worker: Proxied) => Promise): Promise { const worker = createWebWorker( - FileAccess.asBrowserUri('vs/platform/profiling/electron-sandbox/profileAnalysisWorkerMain.js'), + FileAccess.asBrowserUri('vs/platform/profiling/electron-browser/profileAnalysisWorkerMain.js'), 'CpuProfileAnalysisWorker' ); diff --git a/src/vs/platform/profiling/electron-sandbox/profilingService.ts b/src/vs/platform/profiling/electron-browser/profilingService.ts similarity index 95% rename from src/vs/platform/profiling/electron-sandbox/profilingService.ts rename to src/vs/platform/profiling/electron-browser/profilingService.ts index ffb1e47edf1..54936f2c001 100644 --- a/src/vs/platform/profiling/electron-sandbox/profilingService.ts +++ b/src/vs/platform/profiling/electron-browser/profilingService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSharedProcessRemoteService } from '../../ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../ipc/electron-browser/services.js'; import { IV8InspectProfilingService } from '../common/profiling.js'; registerSharedProcessRemoteService(IV8InspectProfilingService, 'v8InspectProfiling'); diff --git a/src/vs/platform/remote/electron-sandbox/electronRemoteResourceLoader.ts b/src/vs/platform/remote/electron-browser/electronRemoteResourceLoader.ts similarity index 100% rename from src/vs/platform/remote/electron-sandbox/electronRemoteResourceLoader.ts rename to src/vs/platform/remote/electron-browser/electronRemoteResourceLoader.ts diff --git a/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts similarity index 100% rename from src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts rename to src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts diff --git a/src/vs/platform/remote/electron-sandbox/sharedProcessTunnelService.ts b/src/vs/platform/remote/electron-browser/sharedProcessTunnelService.ts similarity index 95% rename from src/vs/platform/remote/electron-sandbox/sharedProcessTunnelService.ts rename to src/vs/platform/remote/electron-browser/sharedProcessTunnelService.ts index 81c04b34fcb..89e2e4034b0 100644 --- a/src/vs/platform/remote/electron-sandbox/sharedProcessTunnelService.ts +++ b/src/vs/platform/remote/electron-browser/sharedProcessTunnelService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSharedProcessRemoteService } from '../../ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../ipc/electron-browser/services.js'; import { ISharedProcessTunnelService, ipcSharedProcessTunnelChannelName } from '../common/sharedProcessTunnelService.js'; registerSharedProcessRemoteService(ISharedProcessTunnelService, ipcSharedProcessTunnelChannelName); diff --git a/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts b/src/vs/platform/remote/test/electron-browser/remoteAuthorityResolverService.test.ts similarity index 93% rename from src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts rename to src/vs/platform/remote/test/electron-browser/remoteAuthorityResolverService.test.ts index ebf023ac49c..c085559fa6a 100644 --- a/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts +++ b/src/vs/platform/remote/test/electron-browser/remoteAuthorityResolverService.test.ts @@ -8,7 +8,7 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/c import product from '../../../product/common/product.js'; import { IProductService } from '../../../product/common/productService.js'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from '../../common/remoteAuthorityResolver.js'; -import { RemoteAuthorityResolverService } from '../../electron-sandbox/remoteAuthorityResolverService.js'; +import { RemoteAuthorityResolverService } from '../../electron-browser/remoteAuthorityResolverService.js'; suite('RemoteAuthorityResolverService', () => { diff --git a/src/vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService.ts b/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts similarity index 95% rename from src/vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService.ts rename to src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts index 7aa3657e2a5..fc033ed547e 100644 --- a/src/vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService.ts +++ b/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSharedProcessRemoteService } from '../../ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../ipc/electron-browser/services.js'; import { IRemoteTunnelService } from '../common/remoteTunnel.js'; registerSharedProcessRemoteService(IRemoteTunnelService, 'remoteTunnel'); diff --git a/src/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts b/src/vs/platform/telemetry/electron-browser/customEndpointTelemetryService.ts similarity index 95% rename from src/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts rename to src/vs/platform/telemetry/electron-browser/customEndpointTelemetryService.ts index 97a41b21d5b..7b557705a69 100644 --- a/src/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts +++ b/src/vs/platform/telemetry/electron-browser/customEndpointTelemetryService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSharedProcessRemoteService } from '../../ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../ipc/electron-browser/services.js'; import { ICustomEndpointTelemetryService } from '../common/telemetry.js'; registerSharedProcessRemoteService(ICustomEndpointTelemetryService, 'customEndpointTelemetry'); diff --git a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfileStorageService.ts b/src/vs/platform/userDataProfile/electron-browser/userDataProfileStorageService.ts similarity index 100% rename from src/vs/platform/userDataProfile/electron-sandbox/userDataProfileStorageService.ts rename to src/vs/platform/userDataProfile/electron-browser/userDataProfileStorageService.ts diff --git a/src/vs/platform/webContentExtractor/electron-sandbox/webContentExtractorService.ts b/src/vs/platform/webContentExtractor/electron-browser/webContentExtractorService.ts similarity index 91% rename from src/vs/platform/webContentExtractor/electron-sandbox/webContentExtractorService.ts rename to src/vs/platform/webContentExtractor/electron-browser/webContentExtractorService.ts index 2d6ebf12b5f..9fab2c6e7e1 100644 --- a/src/vs/platform/webContentExtractor/electron-sandbox/webContentExtractorService.ts +++ b/src/vs/platform/webContentExtractor/electron-browser/webContentExtractorService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerMainProcessRemoteService, registerSharedProcessRemoteService } from '../../ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService, registerSharedProcessRemoteService } from '../../ipc/electron-browser/services.js'; import { ISharedWebContentExtractorService, IWebContentExtractorService } from '../common/webContentExtractor.js'; registerMainProcessRemoteService(IWebContentExtractorService, 'webContentExtractor'); diff --git a/src/vs/platform/window/electron-sandbox/window.ts b/src/vs/platform/window/electron-browser/window.ts similarity index 98% rename from src/vs/platform/window/electron-sandbox/window.ts rename to src/vs/platform/window/electron-browser/window.ts index c9914e2117e..cdd43a4e00c 100644 --- a/src/vs/platform/window/electron-sandbox/window.ts +++ b/src/vs/platform/window/electron-browser/window.ts @@ -7,7 +7,7 @@ import { getZoomLevel, setZoomFactor, setZoomLevel } from '../../../base/browser import { getActiveWindow, getWindows } from '../../../base/browser/dom.js'; import { mainWindow } from '../../../base/browser/window.js'; import { ISandboxConfiguration } from '../../../base/parts/sandbox/common/sandboxTypes.js'; -import { ISandboxGlobals, ipcRenderer, webFrame } from '../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { ISandboxGlobals, ipcRenderer, webFrame } from '../../../base/parts/sandbox/electron-browser/globals.js'; import { zoomLevelToZoomFactor } from '../common/window.js'; export enum ApplyZoomTarget { diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index 4eae571a75c..78587bf0b8c 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -619,7 +619,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { this.logService.trace('window#ctor: using window state', state); const options = instantiationService.invokeFunction(defaultBrowserWindowOptions, this.windowState, undefined, { - preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-sandbox/preload.js').fsPath, + preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js').fsPath, additionalArguments: [`--vscode-window-config=${this.configObjectUrl.resource.toString()}`], v8CacheOptions: this.environmentMainService.useCodeCache ? 'bypassHeatCheck' : 'none', }); @@ -1091,7 +1091,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { this.readyState = ReadyState.NAVIGATING; // Load URL - this._win.loadURL(FileAccess.asBrowserUri(`vs/code/electron-sandbox/workbench/workbench${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)); + this._win.loadURL(FileAccess.asBrowserUri(`vs/code/electron-browser/workbench/workbench${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)); // Remember that we did load const wasLoaded = this.wasLoaded; diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/chatDeveloperActions.ts b/src/vs/workbench/contrib/chat/electron-browser/actions/chatDeveloperActions.ts similarity index 100% rename from src/vs/workbench/contrib/chat/electron-sandbox/actions/chatDeveloperActions.ts rename to src/vs/workbench/contrib/chat/electron-browser/actions/chatDeveloperActions.ts diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css b/src/vs/workbench/contrib/chat/electron-browser/actions/media/voiceChatActions.css similarity index 100% rename from src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css rename to src/vs/workbench/contrib/chat/electron-browser/actions/media/voiceChatActions.css diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-browser/actions/voiceChatActions.ts similarity index 100% rename from src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts rename to src/vs/workbench/contrib/chat/electron-browser/actions/voiceChatActions.ts diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts b/src/vs/workbench/contrib/chat/electron-browser/chat.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts rename to src/vs/workbench/contrib/chat/electron-browser/chat.contribution.ts diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/tools/fetchPageTool.ts b/src/vs/workbench/contrib/chat/electron-browser/tools/fetchPageTool.ts similarity index 100% rename from src/vs/workbench/contrib/chat/electron-sandbox/tools/fetchPageTool.ts rename to src/vs/workbench/contrib/chat/electron-browser/tools/fetchPageTool.ts diff --git a/src/vs/workbench/contrib/chat/test/electron-sandbox/voiceChatActions.test.ts b/src/vs/workbench/contrib/chat/test/electron-browser/voiceChatActions.test.ts similarity index 95% rename from src/vs/workbench/contrib/chat/test/electron-sandbox/voiceChatActions.test.ts rename to src/vs/workbench/contrib/chat/test/electron-browser/voiceChatActions.test.ts index 478a0c14214..bcf00d4b79f 100644 --- a/src/vs/workbench/contrib/chat/test/electron-sandbox/voiceChatActions.test.ts +++ b/src/vs/workbench/contrib/chat/test/electron-browser/voiceChatActions.test.ts @@ -5,7 +5,7 @@ import assert from 'assert'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { parseNextChatResponseChunk } from '../../electron-sandbox/actions/voiceChatActions.js'; +import { parseNextChatResponseChunk } from '../../electron-browser/actions/voiceChatActions.js'; suite('VoiceChatActions', function () { diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution.ts rename to src/vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution.ts diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/displayChangeRemeasureFonts.ts similarity index 100% rename from src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts rename to src/vs/workbench/contrib/codeEditor/electron-browser/displayChangeRemeasureFonts.ts diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/inputClipboardActions.ts similarity index 100% rename from src/vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts rename to src/vs/workbench/contrib/codeEditor/electron-browser/inputClipboardActions.ts diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts similarity index 100% rename from src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts rename to src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/sleepResumeRepaintMinimap.ts similarity index 100% rename from src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts rename to src/vs/workbench/contrib/codeEditor/electron-browser/sleepResumeRepaintMinimap.ts diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/startDebugTextMate.ts similarity index 98% rename from src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts rename to src/vs/workbench/contrib/codeEditor/electron-browser/startDebugTextMate.ts index 645eabd6384..5a746dc17fc 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-browser/startDebugTextMate.ts @@ -16,7 +16,7 @@ import { ICodeEditorService } from '../../../../editor/browser/services/codeEdit import { ITextModel } from '../../../../editor/common/model.js'; import { Constants } from '../../../../base/common/uint.js'; import { IHostService } from '../../../services/host/browser/host.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { ILoggerService } from '../../../../platform/log/common/log.js'; import { joinPath } from '../../../../base/common/resources.js'; import { IFileService } from '../../../../platform/files/common/files.js'; diff --git a/src/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts similarity index 95% rename from src/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts rename to src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts index cf036366f08..d229afb5feb 100644 --- a/src/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IExtensionHostDebugService } from '../../../../platform/debug/common/extensionHostDebug.js'; -import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from '../../../../platform/debug/common/extensionHostDebugIpc.js'; registerMainProcessRemoteService(IExtensionHostDebugService, ExtensionHostDebugBroadcastChannel.ChannelName, { channelClientCtor: ExtensionHostDebugChannelClient }); diff --git a/src/vs/workbench/contrib/emergencyAlert/electron-sandbox/emergencyAlert.contribution.ts b/src/vs/workbench/contrib/emergencyAlert/electron-browser/emergencyAlert.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/emergencyAlert/electron-sandbox/emergencyAlert.contribution.ts rename to src/vs/workbench/contrib/emergencyAlert/electron-browser/emergencyAlert.contribution.ts diff --git a/src/vs/workbench/contrib/encryption/electron-sandbox/encryption.contribution.ts b/src/vs/workbench/contrib/encryption/electron-browser/encryption.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/encryption/electron-sandbox/encryption.contribution.ts rename to src/vs/workbench/contrib/encryption/electron-browser/encryption.contribution.ts diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts b/src/vs/workbench/contrib/extensions/electron-browser/debugExtensionHostAction.ts similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts rename to src/vs/workbench/contrib/extensions/electron-browser/debugExtensionHostAction.ts diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts similarity index 99% rename from src/vs/workbench/contrib/extensions/electron-sandbox/extensionProfileService.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index 99057a3464c..353643784cc 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -21,7 +21,7 @@ import { IExtensionHostProfileService, ProfileSessionState } from './runtimeExte import { IEditorService } from '../../../services/editor/common/editorService.js'; import { ExtensionHostKind } from '../../../services/extensions/common/extensionHostKind.js'; import { IExtensionHostProfile, IExtensionService, ProfileSession } from '../../../services/extensions/common/extensions.js'; -import { ExtensionHostProfiler } from '../../../services/extensions/electron-sandbox/extensionHostProfiler.js'; +import { ExtensionHostProfiler } from '../../../services/extensions/electron-browser/extensionHostProfiler.js'; import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from '../../../services/statusbar/browser/statusbar.js'; import { URI } from '../../../../base/common/uri.js'; diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts similarity index 99% rename from src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index e78c2df7839..0ba0fad1d18 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -11,7 +11,7 @@ import { ExtensionRecommendationNotificationServiceChannel } from '../../../../p import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from '../../../common/contributions.js'; diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts similarity index 97% rename from src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index d189fce4a3b..41978486698 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -6,7 +6,7 @@ import { localize2 } from '../../../../nls.js'; import { IFileService } from '../../../../platform/files/common/files.js'; import { URI } from '../../../../base/common/uri.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; import { Schemas } from '../../../../base/common/network.js'; import { Action2 } from '../../../../platform/actions/common/actions.js'; diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsAutoProfiler.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts similarity index 98% rename from src/vs/workbench/contrib/extensions/electron-sandbox/extensionsAutoProfiler.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts index bcab2c6a34d..b1223ae226c 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsAutoProfiler.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts @@ -20,17 +20,17 @@ import { IFileService } from '../../../../platform/files/common/files.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { INotificationService, NotificationPriority, Severity } from '../../../../platform/notification/common/notification.js'; -import { IProfileAnalysisWorkerService } from '../../../../platform/profiling/electron-sandbox/profileAnalysisWorkerService.js'; +import { IProfileAnalysisWorkerService } from '../../../../platform/profiling/electron-browser/profileAnalysisWorkerService.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { IWorkbenchContribution } from '../../../common/contributions.js'; import { RuntimeExtensionsInput } from '../common/runtimeExtensionsInput.js'; import { createSlowExtensionAction } from './extensionsSlowActions.js'; import { IExtensionHostProfileService } from './runtimeExtensionsEditor.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { ExtensionHostKind } from '../../../services/extensions/common/extensionHostKind.js'; import { IExtensionHostProfile, IExtensionService, IResponsiveStateChangeEvent, ProfileSession } from '../../../services/extensions/common/extensions.js'; -import { ExtensionHostProfiler } from '../../../services/extensions/electron-sandbox/extensionHostProfiler.js'; +import { ExtensionHostProfiler } from '../../../services/extensions/electron-browser/extensionHostProfiler.js'; import { ITimerService } from '../../../services/timer/browser/timerService.js'; export class ExtensionsAutoProfiler implements IWorkbenchContribution { diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts similarity index 99% rename from src/vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts index 447f4c9ff1f..46120a9e645 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts @@ -16,7 +16,7 @@ import { joinPath } from '../../../../base/common/resources.js'; import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { Utils } from '../../../../platform/profiling/common/profiling.js'; import { IFileService } from '../../../../platform/files/common/files.js'; import { VSBuffer } from '../../../../base/common/buffer.js'; diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/remoteExtensionsInit.ts b/src/vs/workbench/contrib/extensions/electron-browser/remoteExtensionsInit.ts similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-sandbox/remoteExtensionsInit.ts rename to src/vs/workbench/contrib/extensions/electron-browser/remoteExtensionsInit.ts diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor.ts rename to src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts diff --git a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extension.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extension.test.ts similarity index 100% rename from src/vs/workbench/contrib/extensions/test/electron-sandbox/extension.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extension.test.ts diff --git a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionRecommendationsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts similarity index 99% rename from src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionRecommendationsService.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts index a380a714200..39d0a701927 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionRecommendationsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts @@ -18,7 +18,7 @@ import { NullTelemetryService } from '../../../../../platform/telemetry/common/t import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { TestLifecycleService } from '../../../../test/browser/workbenchTestServices.js'; import { TestContextService, TestProductService, TestStorageService } from '../../../../test/common/workbenchTestServices.js'; -import { TestExtensionTipsService, TestSharedProcessService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { TestExtensionTipsService, TestSharedProcessService } from '../../../../test/electron-browser/workbenchTestServices.js'; import { TestNotificationService } from '../../../../../platform/notification/test/common/testNotificationService.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { URI } from '../../../../../base/common/uri.js'; @@ -37,7 +37,7 @@ import { INotificationService, Severity, IPromptChoice, IPromptOptions } from '. import { NativeURLService } from '../../../../../platform/url/common/urlService.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../../platform/storage/common/storage.js'; import { ExtensionType } from '../../../../../platform/extensions/common/extensions.js'; -import { ISharedProcessService } from '../../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../../platform/ipc/electron-browser/services.js'; import { FileService } from '../../../../../platform/files/common/fileService.js'; import { NullLogService, ILogService } from '../../../../../platform/log/common/log.js'; import { IFileService } from '../../../../../platform/files/common/files.js'; diff --git a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts similarity index 99% rename from src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsActions.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index bce84045b3e..b194b88322d 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -26,16 +26,16 @@ import { NullTelemetryService } from '../../../../../platform/telemetry/common/t import { IExtensionService, toExtensionDescription } from '../../../../services/extensions/common/extensions.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { TestContextService, TestWorkspaceTrustManagementService } from '../../../../test/common/workbenchTestServices.js'; -import { TestExtensionTipsService, TestSharedProcessService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { TestExtensionTipsService, TestSharedProcessService } from '../../../../test/electron-browser/workbenchTestServices.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { ILogService, NullLogService } from '../../../../../platform/log/common/log.js'; import { NativeURLService } from '../../../../../platform/url/common/urlService.js'; import { URI } from '../../../../../base/common/uri.js'; import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js'; import { IRemoteAgentService } from '../../../../services/remote/common/remoteAgentService.js'; -import { RemoteAgentService } from '../../../../services/remote/electron-sandbox/remoteAgentService.js'; +import { RemoteAgentService } from '../../../../services/remote/electron-browser/remoteAgentService.js'; import { IExtensionContributions, ExtensionType, IExtensionDescription, IExtension } from '../../../../../platform/extensions/common/extensions.js'; -import { ISharedProcessService } from '../../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../../platform/ipc/electron-browser/services.js'; import { CancellationToken } from '../../../../../base/common/cancellation.js'; import { ILabelService, IFormatterChangeEvent } from '../../../../../platform/label/common/label.js'; import { IProductService } from '../../../../../platform/product/common/productService.js'; @@ -45,7 +45,7 @@ import { ProgressService } from '../../../../services/progress/browser/progressS import { ILifecycleService } from '../../../../services/lifecycle/common/lifecycle.js'; import { TestEnvironmentService, TestLifecycleService } from '../../../../test/browser/workbenchTestServices.js'; import { DisposableStore } from '../../../../../base/common/lifecycle.js'; -import { INativeWorkbenchEnvironmentService } from '../../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../../services/environment/electron-browser/environmentService.js'; import { IWorkbenchEnvironmentService } from '../../../../services/environment/common/environmentService.js'; import { IUserDataSyncEnablementService } from '../../../../../platform/userDataSync/common/userDataSync.js'; import { UserDataSyncEnablementService } from '../../../../../platform/userDataSync/common/userDataSyncEnablementService.js'; diff --git a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts similarity index 99% rename from src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsViews.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index 3752be94aaa..4b5ebfc1d22 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -26,7 +26,7 @@ import { NullTelemetryService } from '../../../../../platform/telemetry/common/t import { IExtensionService, toExtensionDescription } from '../../../../services/extensions/common/extensions.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { TestMenuService } from '../../../../test/browser/workbenchTestServices.js'; -import { TestSharedProcessService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { TestSharedProcessService } from '../../../../test/electron-browser/workbenchTestServices.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { ILogService, NullLogService } from '../../../../../platform/log/common/log.js'; import { NativeURLService } from '../../../../../platform/url/common/urlService.js'; @@ -34,9 +34,9 @@ import { URI } from '../../../../../base/common/uri.js'; import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js'; import { SinonStub } from 'sinon'; import { IRemoteAgentService } from '../../../../services/remote/common/remoteAgentService.js'; -import { RemoteAgentService } from '../../../../services/remote/electron-sandbox/remoteAgentService.js'; +import { RemoteAgentService } from '../../../../services/remote/electron-browser/remoteAgentService.js'; import { ExtensionType, IExtension } from '../../../../../platform/extensions/common/extensions.js'; -import { ISharedProcessService } from '../../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../../platform/ipc/electron-browser/services.js'; import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { MockContextKeyService } from '../../../../../platform/keybinding/test/common/mockKeybindingService.js'; import { IMenuService } from '../../../../../platform/actions/common/actions.js'; diff --git a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts similarity index 99% rename from src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsWorkbenchService.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 6f9c1ee9667..c68caf3fbbb 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -24,7 +24,7 @@ import { IPager } from '../../../../../base/common/paging.js'; import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js'; import { NullTelemetryService } from '../../../../../platform/telemetry/common/telemetryUtils.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; -import { TestExtensionTipsService, TestSharedProcessService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { TestExtensionTipsService, TestSharedProcessService } from '../../../../test/electron-browser/workbenchTestServices.js'; import { ConfigurationTarget, IConfigurationChangeEvent, IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { ILogService, NullLogService } from '../../../../../platform/log/common/log.js'; import { IProgressService } from '../../../../../platform/progress/common/progress.js'; @@ -36,8 +36,8 @@ import { CancellationToken } from '../../../../../base/common/cancellation.js'; import { ExtensionType } from '../../../../../platform/extensions/common/extensions.js'; import { ExtensionKind } from '../../../../../platform/environment/common/environment.js'; import { IRemoteAgentService } from '../../../../services/remote/common/remoteAgentService.js'; -import { RemoteAgentService } from '../../../../services/remote/electron-sandbox/remoteAgentService.js'; -import { ISharedProcessService } from '../../../../../platform/ipc/electron-sandbox/services.js'; +import { RemoteAgentService } from '../../../../services/remote/electron-browser/remoteAgentService.js'; +import { ISharedProcessService } from '../../../../../platform/ipc/electron-browser/services.js'; import { TestContextService } from '../../../../test/common/workbenchTestServices.js'; import { IProductService } from '../../../../../platform/product/common/productService.js'; import { ILifecycleService } from '../../../../services/lifecycle/common/lifecycle.js'; diff --git a/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution.ts similarity index 99% rename from src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts rename to src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution.ts index 572445bbec5..1edaaa8ada1 100644 --- a/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution.ts @@ -14,7 +14,7 @@ import { Schemas } from '../../../../base/common/network.js'; import { IConfigurationRegistry, Extensions, ConfigurationScope, type IConfigurationPropertySchema } from '../../../../platform/configuration/common/configurationRegistry.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from '../../../common/contributions.js'; -import { IExternalTerminalService } from '../../../../platform/externalTerminal/electron-sandbox/externalTerminalService.js'; +import { IExternalTerminalService } from '../../../../platform/externalTerminal/electron-browser/externalTerminalService.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { TerminalContextKeys } from '../../terminal/common/terminalContextKey.js'; import { IRemoteAuthorityResolverService } from '../../../../platform/remote/common/remoteAuthorityResolver.js'; diff --git a/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts rename to src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts diff --git a/src/vs/workbench/contrib/files/electron-sandbox/fileCommands.ts b/src/vs/workbench/contrib/files/electron-browser/fileCommands.ts similarity index 100% rename from src/vs/workbench/contrib/files/electron-sandbox/fileCommands.ts rename to src/vs/workbench/contrib/files/electron-browser/fileCommands.ts diff --git a/src/vs/workbench/contrib/inlineChat/electron-sandbox/inlineChat.contribution.ts b/src/vs/workbench/contrib/inlineChat/electron-browser/inlineChat.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/inlineChat/electron-sandbox/inlineChat.contribution.ts rename to src/vs/workbench/contrib/inlineChat/electron-browser/inlineChat.contribution.ts diff --git a/src/vs/workbench/contrib/inlineChat/electron-sandbox/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/electron-browser/inlineChatActions.ts similarity index 98% rename from src/vs/workbench/contrib/inlineChat/electron-sandbox/inlineChatActions.ts rename to src/vs/workbench/contrib/inlineChat/electron-browser/inlineChatActions.ts index 54754b0b91d..1f0e9638235 100644 --- a/src/vs/workbench/contrib/inlineChat/electron-sandbox/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/electron-browser/inlineChatActions.ts @@ -13,7 +13,7 @@ import { disposableTimeout } from '../../../../base/common/async.js'; import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; -import { StartVoiceChatAction, StopListeningAction, VOICE_KEY_HOLD_THRESHOLD } from '../../chat/electron-sandbox/actions/voiceChatActions.js'; +import { StartVoiceChatAction, StopListeningAction, VOICE_KEY_HOLD_THRESHOLD } from '../../chat/electron-browser/actions/voiceChatActions.js'; import { IChatExecuteActionContext } from '../../chat/browser/actions/chatExecuteActions.js'; import { CTX_INLINE_CHAT_VISIBLE, InlineChatConfigKeys } from '../common/inlineChat.js'; import { HasSpeechProvider, ISpeechService } from '../../speech/common/speechService.js'; diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts rename to src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService.ts b/src/vs/workbench/contrib/issue/electron-browser/issueReporterService.ts similarity index 99% rename from src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService.ts rename to src/vs/workbench/contrib/issue/electron-browser/issueReporterService.ts index cbdf9723c31..4ad8cca1d8a 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueReporterService.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issueReporterService.ts @@ -17,7 +17,7 @@ import { INativeHostService } from '../../../../platform/native/common/native.js import { IProcessService } from '../../../../platform/process/common/process.js'; import { IThemeService } from '../../../../platform/theme/common/themeService.js'; import { IUpdateService, StateType } from '../../../../platform/update/common/update.js'; -import { applyZoom } from '../../../../platform/window/electron-sandbox/window.js'; +import { applyZoom } from '../../../../platform/window/electron-browser/window.js'; import { BaseIssueReporterService } from '../browser/baseIssueReporterService.js'; import { IssueReporterData as IssueReporterModelData } from '../browser/issueReporterModel.js'; import { IIssueFormService, IssueReporterData, IssueType } from '../common/issue.js'; diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts similarity index 100% rename from src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts rename to src/vs/workbench/contrib/issue/electron-browser/issueService.ts diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/nativeIssueFormService.ts b/src/vs/workbench/contrib/issue/electron-browser/nativeIssueFormService.ts similarity index 100% rename from src/vs/workbench/contrib/issue/electron-sandbox/nativeIssueFormService.ts rename to src/vs/workbench/contrib/issue/electron-browser/nativeIssueFormService.ts diff --git a/src/vs/workbench/contrib/localHistory/electron-sandbox/localHistory.contribution.ts b/src/vs/workbench/contrib/localHistory/electron-browser/localHistory.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/localHistory/electron-sandbox/localHistory.contribution.ts rename to src/vs/workbench/contrib/localHistory/electron-browser/localHistory.contribution.ts diff --git a/src/vs/workbench/contrib/localHistory/electron-sandbox/localHistoryCommands.ts b/src/vs/workbench/contrib/localHistory/electron-browser/localHistoryCommands.ts similarity index 100% rename from src/vs/workbench/contrib/localHistory/electron-sandbox/localHistoryCommands.ts rename to src/vs/workbench/contrib/localHistory/electron-browser/localHistoryCommands.ts diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts b/src/vs/workbench/contrib/localization/electron-browser/localization.contribution.ts similarity index 98% rename from src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts rename to src/vs/workbench/contrib/localization/electron-browser/localization.contribution.ts index 4201a6563f1..0455b7556b4 100644 --- a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts +++ b/src/vs/workbench/contrib/localization/electron-browser/localization.contribution.ts @@ -139,7 +139,7 @@ class NativeLocalizationWorkbenchContribution extends BaseLocalizationWorkbenchC const loc = manifest?.contributes?.localizations?.find(x => locale.startsWith(x.languageId.toLowerCase())); const languageName = loc ? (loc.languageName || locale) : locale; const languageDisplayName = loc ? (loc.localizedLanguageName || loc.languageName || locale) : locale; - const translationsFromPack: { [key: string]: string } = translation?.contents?.['vs/workbench/contrib/localization/electron-sandbox/minimalTranslations'] ?? {}; + const translationsFromPack: { [key: string]: string } = translation?.contents?.['vs/workbench/contrib/localization/electron-browser/minimalTranslations'] ?? {}; const promptMessageKey = extensionToInstall ? 'installAndRestartMessage' : 'showLanguagePackExtensions'; const useEnglish = !translationsFromPack[promptMessageKey]; diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/minimalTranslations.ts b/src/vs/workbench/contrib/localization/electron-browser/minimalTranslations.ts similarity index 100% rename from src/vs/workbench/contrib/localization/electron-sandbox/minimalTranslations.ts rename to src/vs/workbench/contrib/localization/electron-browser/minimalTranslations.ts diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts rename to src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts b/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts similarity index 97% rename from src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts rename to src/vs/workbench/contrib/logs/electron-browser/logsActions.ts index bc7e00198c2..2e0f77cc3d7 100644 --- a/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts +++ b/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts @@ -6,7 +6,7 @@ import { Action } from '../../../../base/common/actions.js'; import * as nls from '../../../../nls.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { IFileService } from '../../../../platform/files/common/files.js'; import { joinPath } from '../../../../base/common/resources.js'; import { Schemas } from '../../../../base/common/network.js'; diff --git a/src/vs/workbench/contrib/mcp/electron-sandbox/mcp.contribution.ts b/src/vs/workbench/contrib/mcp/electron-browser/mcp.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/mcp/electron-sandbox/mcp.contribution.ts rename to src/vs/workbench/contrib/mcp/electron-browser/mcp.contribution.ts diff --git a/src/vs/workbench/contrib/mcp/electron-sandbox/mcpDevModeDebuggingNode.ts b/src/vs/workbench/contrib/mcp/electron-browser/mcpDevModeDebuggingNode.ts similarity index 100% rename from src/vs/workbench/contrib/mcp/electron-sandbox/mcpDevModeDebuggingNode.ts rename to src/vs/workbench/contrib/mcp/electron-browser/mcpDevModeDebuggingNode.ts diff --git a/src/vs/workbench/contrib/mcp/electron-sandbox/nativeMpcDiscovery.ts b/src/vs/workbench/contrib/mcp/electron-browser/nativeMpcDiscovery.ts similarity index 100% rename from src/vs/workbench/contrib/mcp/electron-sandbox/nativeMpcDiscovery.ts rename to src/vs/workbench/contrib/mcp/electron-browser/nativeMpcDiscovery.ts diff --git a/src/vs/workbench/contrib/mergeEditor/electron-sandbox/devCommands.ts b/src/vs/workbench/contrib/mergeEditor/electron-browser/devCommands.ts similarity index 100% rename from src/vs/workbench/contrib/mergeEditor/electron-sandbox/devCommands.ts rename to src/vs/workbench/contrib/mergeEditor/electron-browser/devCommands.ts diff --git a/src/vs/workbench/contrib/mergeEditor/electron-sandbox/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/electron-browser/mergeEditor.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/mergeEditor/electron-sandbox/mergeEditor.contribution.ts rename to src/vs/workbench/contrib/mergeEditor/electron-browser/mergeEditor.contribution.ts diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts b/src/vs/workbench/contrib/performance/electron-browser/performance.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts rename to src/vs/workbench/contrib/performance/electron-browser/performance.contribution.ts diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-browser/rendererAutoProfiler.ts similarity index 97% rename from src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts rename to src/vs/workbench/contrib/performance/electron-browser/rendererAutoProfiler.ts index 5286ecc047b..52edafd6cff 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/rendererAutoProfiler.ts @@ -12,8 +12,8 @@ import { IFileService } from '../../../../platform/files/common/files.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; import { IV8Profile } from '../../../../platform/profiling/common/profiling.js'; -import { IProfileAnalysisWorkerService, ProfilingOutput } from '../../../../platform/profiling/electron-sandbox/profileAnalysisWorkerService.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { IProfileAnalysisWorkerService, ProfilingOutput } from '../../../../platform/profiling/electron-browser/profileAnalysisWorkerService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { parseExtensionDevOptions } from '../../../services/extensions/common/extensionDevOptions.js'; import { ITimerService } from '../../../services/timer/browser/timerService.js'; diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/startupProfiler.ts b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts similarity index 99% rename from src/vs/workbench/contrib/performance/electron-sandbox/startupProfiler.ts rename to src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts index 448ebcba59f..f5b6f208aa1 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/startupProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts @@ -8,7 +8,7 @@ import { localize } from '../../../../nls.js'; import { dirname, basename } from '../../../../base/common/resources.js'; import { ITextModelService } from '../../../../editor/common/services/resolverService.js'; import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { ILifecycleService, LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js'; import { PerfviewContrib } from '../browser/perfviewEditor.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts similarity index 99% rename from src/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts rename to src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts index 7753789e588..fe0d86ad970 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts @@ -6,7 +6,7 @@ import { IWorkbenchContribution } from '../../../common/contributions.js'; import { timeout } from '../../../../base/common/async.js'; import { onUnexpectedError } from '../../../../base/common/errors.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { ILifecycleService } from '../../../services/lifecycle/common/lifecycle.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; diff --git a/src/vs/workbench/contrib/processExplorer/electron-sandbox/processExplorer.contribution.ts b/src/vs/workbench/contrib/processExplorer/electron-browser/processExplorer.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/processExplorer/electron-sandbox/processExplorer.contribution.ts rename to src/vs/workbench/contrib/processExplorer/electron-browser/processExplorer.contribution.ts diff --git a/src/vs/workbench/contrib/processExplorer/electron-sandbox/processExplorerControl.ts b/src/vs/workbench/contrib/processExplorer/electron-browser/processExplorerControl.ts similarity index 100% rename from src/vs/workbench/contrib/processExplorer/electron-sandbox/processExplorerControl.ts rename to src/vs/workbench/contrib/processExplorer/electron-browser/processExplorerControl.ts diff --git a/src/vs/workbench/contrib/processExplorer/electron-sandbox/processExplorerEditor.ts b/src/vs/workbench/contrib/processExplorer/electron-browser/processExplorerEditor.ts similarity index 100% rename from src/vs/workbench/contrib/processExplorer/electron-sandbox/processExplorerEditor.ts rename to src/vs/workbench/contrib/processExplorer/electron-browser/processExplorerEditor.ts diff --git a/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts similarity index 99% rename from src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts rename to src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 7443bf9cac1..95ecd96f3fd 100644 --- a/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -16,9 +16,9 @@ import { ILabelService } from '../../../../platform/label/common/label.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { Schemas } from '../../../../base/common/network.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; -import { ipcRenderer } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { ipcRenderer } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from '../../../../platform/diagnostics/common/diagnostics.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { PersistentConnectionEventType } from '../../../../platform/remote/common/remoteAgentConnection.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from '../../../../platform/configuration/common/configurationRegistry.js'; diff --git a/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts b/src/vs/workbench/contrib/remoteTunnel/electron-browser/remoteTunnel.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts rename to src/vs/workbench/contrib/remoteTunnel/electron-browser/remoteTunnel.contribution.ts diff --git a/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/splash.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts rename to src/vs/workbench/contrib/splash/electron-browser/splash.contribution.ts diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/tags.contribution.ts b/src/vs/workbench/contrib/tags/electron-browser/tags.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/tags/electron-sandbox/tags.contribution.ts rename to src/vs/workbench/contrib/tags/electron-browser/tags.contribution.ts diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts b/src/vs/workbench/contrib/tags/electron-browser/workspaceTags.ts similarity index 100% rename from src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts rename to src/vs/workbench/contrib/tags/electron-browser/workspaceTags.ts diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts b/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts similarity index 100% rename from src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts rename to src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts diff --git a/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts b/src/vs/workbench/contrib/tasks/electron-browser/taskService.ts similarity index 100% rename from src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts rename to src/vs/workbench/contrib/tasks/electron-browser/taskService.ts diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts b/src/vs/workbench/contrib/terminal/electron-browser/localPty.ts similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts rename to src/vs/workbench/contrib/terminal/electron-browser/localPty.ts diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts b/src/vs/workbench/contrib/terminal/electron-browser/localTerminalBackend.ts similarity index 99% rename from src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts rename to src/vs/workbench/contrib/terminal/electron-browser/localTerminalBackend.ts index 2c93a4c5c8b..0be06471a89 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/localTerminalBackend.ts @@ -20,7 +20,7 @@ import { ITerminalProfileResolverService } from '../common/terminal.js'; import { TerminalStorageKeys } from '../common/terminalStorageKeys.js'; import { LocalPty } from './localPty.js'; import { IConfigurationResolverService } from '../../../services/configurationResolver/common/configurationResolver.js'; -import { IShellEnvironmentService } from '../../../services/environment/electron-sandbox/shellEnvironmentService.js'; +import { IShellEnvironmentService } from '../../../services/environment/electron-browser/shellEnvironmentService.js'; import { IHistoryService } from '../../../services/history/common/history.js'; import * as terminalEnvironment from '../common/terminalEnvironment.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; @@ -28,7 +28,7 @@ import { IEnvironmentVariableService } from '../common/environmentVariable.js'; import { BaseTerminalBackend } from '../browser/baseTerminalBackend.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; import { Client as MessagePortClient } from '../../../../base/parts/ipc/common/ipc.mp.js'; -import { acquirePort } from '../../../../base/parts/ipc/electron-sandbox/ipc.mp.js'; +import { acquirePort } from '../../../../base/parts/ipc/electron-browser/ipc.mp.js'; import { getDelayedChannel, ProxyChannel } from '../../../../base/parts/ipc/common/ipc.js'; import { mark, PerformanceMark } from '../../../../base/common/performance.js'; import { ILifecycleService, LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js'; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts similarity index 97% rename from src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts rename to src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index 381db45fa4a..b439e425bd3 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; -import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; import { ILocalPtyService, TerminalIpcChannels } from '../../../../platform/terminal/common/terminal.js'; import { IWorkbenchContributionsRegistry, WorkbenchPhase, Extensions as WorkbenchExtensions, registerWorkbenchContribution2 } from '../../../common/contributions.js'; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts similarity index 99% rename from src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts rename to src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts index c3132312b08..a076cf8cfd9 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ipcRenderer } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { ipcRenderer } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { INativeOpenFileRequest } from '../../../../platform/window/common/window.js'; import { URI } from '../../../../base/common/uri.js'; import { IFileService } from '../../../../platform/files/common/files.js'; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalProfileResolverService.ts similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-sandbox/terminalProfileResolverService.ts rename to src/vs/workbench/contrib/terminal/electron-browser/terminalProfileResolverService.ts diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts similarity index 100% rename from src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts rename to src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts diff --git a/src/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts similarity index 99% rename from src/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts rename to src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts index 6f3cd48be11..2b9a039ff3b 100644 --- a/src/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts @@ -5,7 +5,7 @@ import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js'; import { IUserDataSyncUtilService, SyncStatus } from '../../../../platform/userDataSync/common/userDataSync.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { registerAction2, Action2, MenuId } from '../../../../platform/actions/common/actions.js'; import { localize, localize2 } from '../../../../nls.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webview.contribution.ts b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/webview/electron-sandbox/webview.contribution.ts rename to src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webviewCommands.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts similarity index 100% rename from src/vs/workbench/contrib/webview/electron-sandbox/webviewCommands.ts rename to src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts similarity index 100% rename from src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts rename to src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webviewService.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts similarity index 100% rename from src/vs/workbench/contrib/webview/electron-sandbox/webviewService.ts rename to src/vs/workbench/contrib/webview/electron-browser/webviewService.ts diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/windowIgnoreMenuShortcutsManager.ts b/src/vs/workbench/contrib/webview/electron-browser/windowIgnoreMenuShortcutsManager.ts similarity index 100% rename from src/vs/workbench/contrib/webview/electron-sandbox/windowIgnoreMenuShortcutsManager.ts rename to src/vs/workbench/contrib/webview/electron-browser/windowIgnoreMenuShortcutsManager.ts diff --git a/src/vs/workbench/electron-sandbox/actions/developerActions.ts b/src/vs/workbench/electron-browser/actions/developerActions.ts similarity index 99% rename from src/vs/workbench/electron-sandbox/actions/developerActions.ts rename to src/vs/workbench/electron-browser/actions/developerActions.ts index 1bc0f68c98a..0b64a58ee06 100644 --- a/src/vs/workbench/electron-sandbox/actions/developerActions.ts +++ b/src/vs/workbench/electron-browser/actions/developerActions.ts @@ -13,7 +13,7 @@ import { IWorkbenchEnvironmentService } from '../../services/environment/common/ import { KeybindingWeight } from '../../../platform/keybinding/common/keybindingsRegistry.js'; import { IsDevelopmentContext } from '../../../platform/contextkey/common/contextkeys.js'; import { KeyCode, KeyMod } from '../../../base/common/keyCodes.js'; -import { INativeWorkbenchEnvironmentService } from '../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../services/environment/electron-browser/environmentService.js'; import { URI } from '../../../base/common/uri.js'; import { getActiveWindow } from '../../../base/browser/dom.js'; import { IDialogService } from '../../../platform/dialogs/common/dialogs.js'; diff --git a/src/vs/workbench/electron-sandbox/actions/installActions.ts b/src/vs/workbench/electron-browser/actions/installActions.ts similarity index 100% rename from src/vs/workbench/electron-sandbox/actions/installActions.ts rename to src/vs/workbench/electron-browser/actions/installActions.ts diff --git a/src/vs/workbench/electron-sandbox/actions/media/actions.css b/src/vs/workbench/electron-browser/actions/media/actions.css similarity index 100% rename from src/vs/workbench/electron-sandbox/actions/media/actions.css rename to src/vs/workbench/electron-browser/actions/media/actions.css diff --git a/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/src/vs/workbench/electron-browser/actions/windowActions.ts similarity index 99% rename from src/vs/workbench/electron-sandbox/actions/windowActions.ts rename to src/vs/workbench/electron-browser/actions/windowActions.ts index 4e31e25b81f..b542b8d7344 100644 --- a/src/vs/workbench/electron-sandbox/actions/windowActions.ts +++ b/src/vs/workbench/electron-browser/actions/windowActions.ts @@ -6,7 +6,7 @@ import './media/actions.css'; import { URI } from '../../../base/common/uri.js'; import { localize, localize2 } from '../../../nls.js'; -import { ApplyZoomTarget, MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL, applyZoom } from '../../../platform/window/electron-sandbox/window.js'; +import { ApplyZoomTarget, MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL, applyZoom } from '../../../platform/window/electron-browser/window.js'; import { IKeybindingService } from '../../../platform/keybinding/common/keybinding.js'; import { getZoomLevel } from '../../../base/browser/browser.js'; import { FileKind } from '../../../platform/files/common/files.js'; diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-browser/desktop.contribution.ts similarity index 99% rename from src/vs/workbench/electron-sandbox/desktop.contribution.ts rename to src/vs/workbench/electron-browser/desktop.contribution.ts index 008bc5ef3e1..f9d0fb87eed 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-browser/desktop.contribution.ts @@ -27,7 +27,7 @@ import { ShutdownReason } from '../services/lifecycle/common/lifecycle.js'; import { NativeWindow } from './window.js'; import { ModifierKeyEmitter } from '../../base/browser/dom.js'; import { applicationConfigurationNodeBase, securityConfigurationNodeBase } from '../common/configuration.js'; -import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../../platform/window/electron-sandbox/window.js'; +import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../../platform/window/electron-browser/window.js'; import { DefaultAccountManagementContribution } from '../services/accounts/common/defaultAccount.js'; import { registerWorkbenchContribution2, WorkbenchPhase } from '../common/contributions.js'; diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts similarity index 96% rename from src/vs/workbench/electron-sandbox/desktop.main.ts rename to src/vs/workbench/electron-browser/desktop.main.ts index 306d1c7c685..0487ad5e2b8 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -13,20 +13,20 @@ import { domContentLoaded } from '../../base/browser/dom.js'; import { onUnexpectedError } from '../../base/common/errors.js'; import { URI } from '../../base/common/uri.js'; import { WorkspaceService } from '../services/configuration/browser/configurationService.js'; -import { INativeWorkbenchEnvironmentService, NativeWorkbenchEnvironmentService } from '../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService, NativeWorkbenchEnvironmentService } from '../services/environment/electron-browser/environmentService.js'; import { ServiceCollection } from '../../platform/instantiation/common/serviceCollection.js'; import { ILoggerService, ILogService, LogLevel } from '../../platform/log/common/log.js'; -import { NativeWorkbenchStorageService } from '../services/storage/electron-sandbox/storageService.js'; +import { NativeWorkbenchStorageService } from '../services/storage/electron-browser/storageService.js'; import { IWorkspaceContextService, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IAnyWorkspaceIdentifier, reviveIdentifier, toWorkspaceIdentifier } from '../../platform/workspace/common/workspace.js'; import { IWorkbenchConfigurationService } from '../services/configuration/common/configuration.js'; import { IStorageService } from '../../platform/storage/common/storage.js'; import { Disposable } from '../../base/common/lifecycle.js'; -import { ISharedProcessService } from '../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../platform/ipc/electron-browser/services.js'; import { IMainProcessService } from '../../platform/ipc/common/mainProcessService.js'; -import { SharedProcessService } from '../services/sharedProcess/electron-sandbox/sharedProcessService.js'; -import { RemoteAuthorityResolverService } from '../../platform/remote/electron-sandbox/remoteAuthorityResolverService.js'; +import { SharedProcessService } from '../services/sharedProcess/electron-browser/sharedProcessService.js'; +import { RemoteAuthorityResolverService } from '../../platform/remote/electron-browser/remoteAuthorityResolverService.js'; import { IRemoteAuthorityResolverService, RemoteConnectionType } from '../../platform/remote/common/remoteAuthorityResolver.js'; -import { RemoteAgentService } from '../services/remote/electron-sandbox/remoteAgentService.js'; +import { RemoteAgentService } from '../services/remote/electron-browser/remoteAgentService.js'; import { IRemoteAgentService } from '../services/remote/common/remoteAgentService.js'; import { FileService } from '../../platform/files/common/fileService.js'; import { IFileService } from '../../platform/files/common/files.js'; @@ -36,18 +36,18 @@ import { ISignService } from '../../platform/sign/common/sign.js'; import { IProductService } from '../../platform/product/common/productService.js'; import { IUriIdentityService } from '../../platform/uriIdentity/common/uriIdentity.js'; import { UriIdentityService } from '../../platform/uriIdentity/common/uriIdentityService.js'; -import { INativeKeyboardLayoutService, NativeKeyboardLayoutService } from '../services/keybinding/electron-sandbox/nativeKeyboardLayoutService.js'; -import { ElectronIPCMainProcessService } from '../../platform/ipc/electron-sandbox/mainProcessService.js'; +import { INativeKeyboardLayoutService, NativeKeyboardLayoutService } from '../services/keybinding/electron-browser/nativeKeyboardLayoutService.js'; +import { ElectronIPCMainProcessService } from '../../platform/ipc/electron-browser/mainProcessService.js'; import { LoggerChannelClient } from '../../platform/log/common/logIpc.js'; import { ProxyChannel } from '../../base/parts/ipc/common/ipc.js'; -import { NativeLogService } from '../services/log/electron-sandbox/logService.js'; +import { NativeLogService } from '../services/log/electron-browser/logService.js'; import { WorkspaceTrustEnablementService, WorkspaceTrustManagementService } from '../services/workspaces/common/workspaceTrust.js'; import { IWorkspaceTrustEnablementService, IWorkspaceTrustManagementService } from '../../platform/workspace/common/workspaceTrust.js'; import { safeStringify } from '../../base/common/objects.js'; -import { IUtilityProcessWorkerWorkbenchService, UtilityProcessWorkerWorkbenchService } from '../services/utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.js'; +import { IUtilityProcessWorkerWorkbenchService, UtilityProcessWorkerWorkbenchService } from '../services/utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.js'; import { isBigSurOrNewer, isCI, isMacintosh } from '../../base/common/platform.js'; import { Schemas } from '../../base/common/network.js'; -import { DiskFileSystemProvider } from '../services/files/electron-sandbox/diskFileSystemProvider.js'; +import { DiskFileSystemProvider } from '../services/files/electron-browser/diskFileSystemProvider.js'; import { FileUserDataProvider } from '../../platform/userData/common/fileUserDataProvider.js'; import { IUserDataProfilesService, reviveProfile } from '../../platform/userDataProfile/common/userDataProfile.js'; import { UserDataProfilesService } from '../../platform/userDataProfile/common/userDataProfileIpc.js'; @@ -57,9 +57,9 @@ import { UserDataProfileService } from '../services/userDataProfile/common/userD import { IUserDataProfileService } from '../services/userDataProfile/common/userDataProfile.js'; import { BrowserSocketFactory } from '../../platform/remote/browser/browserSocketFactory.js'; import { RemoteSocketFactoryService, IRemoteSocketFactoryService } from '../../platform/remote/common/remoteSocketFactoryService.js'; -import { ElectronRemoteResourceLoader } from '../../platform/remote/electron-sandbox/electronRemoteResourceLoader.js'; +import { ElectronRemoteResourceLoader } from '../../platform/remote/electron-browser/electronRemoteResourceLoader.js'; import { IConfigurationService } from '../../platform/configuration/common/configuration.js'; -import { applyZoom } from '../../platform/window/electron-sandbox/window.js'; +import { applyZoom } from '../../platform/window/electron-browser/window.js'; import { mainWindow } from '../../base/browser/window.js'; import { DefaultAccountService, IDefaultAccountService } from '../services/accounts/common/defaultAccount.js'; import { AccountPolicyService } from '../services/policies/common/accountPolicyService.js'; diff --git a/src/vs/workbench/electron-sandbox/media/window.css b/src/vs/workbench/electron-browser/media/window.css similarity index 100% rename from src/vs/workbench/electron-sandbox/media/window.css rename to src/vs/workbench/electron-browser/media/window.css diff --git a/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts b/src/vs/workbench/electron-browser/parts/dialogs/dialog.contribution.ts similarity index 100% rename from src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts rename to src/vs/workbench/electron-browser/parts/dialogs/dialog.contribution.ts diff --git a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts b/src/vs/workbench/electron-browser/parts/dialogs/dialogHandler.ts similarity index 99% rename from src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts rename to src/vs/workbench/electron-browser/parts/dialogs/dialogHandler.ts index 6c61a590324..0806103b36a 100644 --- a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/electron-browser/parts/dialogs/dialogHandler.ts @@ -11,7 +11,7 @@ import { AbstractDialogHandler, IConfirmation, IConfirmationResult, IPrompt, IAs import { ILogService } from '../../../../platform/log/common/log.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; -import { process } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { process } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { getActiveWindow } from '../../../../base/browser/dom.js'; export class NativeDialogHandler extends AbstractDialogHandler { diff --git a/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts b/src/vs/workbench/electron-browser/parts/titlebar/menubarControl.ts similarity index 98% rename from src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts rename to src/vs/workbench/electron-browser/parts/titlebar/menubarControl.ts index 6bbdb1b7a31..716f2280413 100644 --- a/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/electron-browser/parts/titlebar/menubarControl.ts @@ -10,7 +10,7 @@ import { IWorkspacesService } from '../../../../platform/workspaces/common/works import { isMacintosh } from '../../../../base/common/platform.js'; import { INotificationService } from '../../../../platform/notification/common/notification.js'; import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { ILabelService } from '../../../../platform/label/common/label.js'; @@ -18,7 +18,7 @@ import { IUpdateService } from '../../../../platform/update/common/update.js'; import { IOpenRecentAction, MenubarControl } from '../../../browser/parts/titlebar/menubarControl.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; import { IMenubarData, IMenubarMenu, IMenubarKeybinding, IMenubarMenuItemSubmenu, IMenubarMenuItemAction, MenubarMenuItem } from '../../../../platform/menubar/common/menubar.js'; -import { IMenubarService } from '../../../../platform/menubar/electron-sandbox/menubar.js'; +import { IMenubarService } from '../../../../platform/menubar/electron-browser/menubar.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; import { IHostService } from '../../../services/host/browser/host.js'; import { IPreferencesService } from '../../../services/preferences/common/preferences.js'; diff --git a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts b/src/vs/workbench/electron-browser/parts/titlebar/titlebarPart.ts similarity index 99% rename from src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts rename to src/vs/workbench/electron-browser/parts/titlebar/titlebarPart.ts index b437af42424..cfc3572068f 100644 --- a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/electron-browser/parts/titlebar/titlebarPart.ts @@ -9,7 +9,7 @@ import { $, addDisposableListener, append, EventType, getWindow, getWindowId, hi import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { IConfigurationService, IConfigurationChangeEvent } from '../../../../platform/configuration/common/configuration.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; -import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../../services/environment/electron-browser/environmentService.js'; import { IHostService } from '../../../services/host/browser/host.js'; import { isMacintosh, isWindows, isLinux, isBigSurOrNewer } from '../../../../base/common/platform.js'; import { IMenuService, MenuId } from '../../../../platform/actions/common/actions.js'; diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-browser/window.ts similarity index 99% rename from src/vs/workbench/electron-sandbox/window.ts rename to src/vs/workbench/electron-browser/window.ts index 30805019b89..d4072f5d95c 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -16,11 +16,11 @@ import { ITelemetryService } from '../../platform/telemetry/common/telemetry.js' import { WindowMinimumSize, IOpenFileRequest, IAddRemoveFoldersRequest, INativeRunActionInWindowRequest, INativeRunKeybindingInWindowRequest, INativeOpenFileRequest, hasNativeTitlebar } from '../../platform/window/common/window.js'; import { ITitleService } from '../services/title/browser/titleService.js'; import { IWorkbenchThemeService } from '../services/themes/common/workbenchThemeService.js'; -import { ApplyZoomTarget, applyZoom } from '../../platform/window/electron-sandbox/window.js'; +import { ApplyZoomTarget, applyZoom } from '../../platform/window/electron-browser/window.js'; import { setFullscreen, getZoomLevel, onDidChangeZoomLevel, getZoomFactor } from '../../base/browser/browser.js'; import { ICommandService, CommandsRegistry } from '../../platform/commands/common/commands.js'; import { IResourceEditorInput } from '../../platform/editor/common/editor.js'; -import { ipcRenderer, process } from '../../base/parts/sandbox/electron-sandbox/globals.js'; +import { ipcRenderer, process } from '../../base/parts/sandbox/electron-browser/globals.js'; import { IWorkspaceEditingService } from '../services/workspaces/common/workspaceEditing.js'; import { IMenuService, MenuId, IMenu, MenuItemAction, MenuRegistry } from '../../platform/actions/common/actions.js'; import { ICommandAction } from '../../platform/action/common/action.js'; @@ -34,7 +34,7 @@ import { isWindows, isMacintosh } from '../../base/common/platform.js'; import { IProductService } from '../../platform/product/common/productService.js'; import { INotificationService, NotificationPriority, Severity } from '../../platform/notification/common/notification.js'; import { IKeybindingService } from '../../platform/keybinding/common/keybinding.js'; -import { INativeWorkbenchEnvironmentService } from '../services/environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../services/environment/electron-browser/environmentService.js'; import { IAccessibilityService, AccessibilitySupport } from '../../platform/accessibility/common/accessibility.js'; import { WorkbenchState, IWorkspaceContextService } from '../../platform/workspace/common/workspace.js'; import { coalesce } from '../../base/common/arrays.js'; @@ -54,11 +54,11 @@ import { IRemoteAuthorityResolverService } from '../../platform/remote/common/re import { IAddressProvider, IAddress } from '../../platform/remote/common/remoteAgentConnection.js'; import { IEditorGroupsService, IEditorPart } from '../services/editor/common/editorGroupsService.js'; import { IDialogService } from '../../platform/dialogs/common/dialogs.js'; -import { AuthInfo } from '../../base/parts/sandbox/electron-sandbox/electronTypes.js'; +import { AuthInfo } from '../../base/parts/sandbox/electron-browser/electronTypes.js'; import { ILogService } from '../../platform/log/common/log.js'; import { IInstantiationService } from '../../platform/instantiation/common/instantiation.js'; import { whenEditorClosed } from '../browser/editor.js'; -import { ISharedProcessService } from '../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../platform/ipc/electron-browser/services.js'; import { IProgressService, ProgressLocation } from '../../platform/progress/common/progress.js'; import { toErrorMessage } from '../../base/common/errorMessage.js'; import { ILabelService } from '../../platform/label/common/label.js'; @@ -67,7 +67,7 @@ import { IBannerService } from '../services/banner/browser/bannerService.js'; import { Codicon } from '../../base/common/codicons.js'; import { IUriIdentityService } from '../../platform/uriIdentity/common/uriIdentity.js'; import { IPreferencesService } from '../services/preferences/common/preferences.js'; -import { IUtilityProcessWorkerWorkbenchService } from '../services/utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.js'; +import { IUtilityProcessWorkerWorkbenchService } from '../services/utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.js'; import { registerWindowDriver } from '../services/driver/browser/driver.js'; import { mainWindow } from '../../base/browser/window.js'; import { BaseWindow } from '../browser/window.js'; diff --git a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts b/src/vs/workbench/services/accessibility/electron-browser/accessibilityService.ts similarity index 99% rename from src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts rename to src/vs/workbench/services/accessibility/electron-browser/accessibilityService.ts index 89f1c861cff..f3aab796cc1 100644 --- a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/electron-browser/accessibilityService.ts @@ -5,7 +5,7 @@ import { IAccessibilityService, AccessibilitySupport } from '../../../../platform/accessibility/common/accessibility.js'; import { isWindows, isLinux } from '../../../../base/common/platform.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { AccessibilityService } from '../../../../platform/accessibility/browser/accessibilityService.js'; diff --git a/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts b/src/vs/workbench/services/auxiliaryWindow/electron-browser/auxiliaryWindowService.ts similarity index 99% rename from src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts rename to src/vs/workbench/services/auxiliaryWindow/electron-browser/auxiliaryWindowService.ts index 2c6f4addc8e..2c01f6fd5cf 100644 --- a/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts +++ b/src/vs/workbench/services/auxiliaryWindow/electron-browser/auxiliaryWindowService.ts @@ -7,7 +7,7 @@ import { localize } from '../../../../nls.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { IWorkbenchLayoutService } from '../../layout/browser/layoutService.js'; import { AuxiliaryWindow, AuxiliaryWindowMode, BrowserAuxiliaryWindowService, IAuxiliaryWindowOpenOptions, IAuxiliaryWindowService } from '../browser/auxiliaryWindowService.js'; -import { ISandboxGlobals } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { ISandboxGlobals } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { DisposableStore } from '../../../../base/common/lifecycle.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; @@ -19,7 +19,7 @@ import { ShutdownReason } from '../../lifecycle/common/lifecycle.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { Barrier } from '../../../../base/common/async.js'; import { IHostService } from '../../host/browser/host.js'; -import { applyZoom } from '../../../../platform/window/electron-sandbox/window.js'; +import { applyZoom } from '../../../../platform/window/electron-browser/window.js'; import { getZoomLevel, isFullscreen, setFullscreen } from '../../../../base/browser/browser.js'; import { getActiveWindow } from '../../../../base/browser/dom.js'; import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService.js'; diff --git a/src/vs/workbench/services/browserElements/electron-sandbox/browserElementsService.ts b/src/vs/workbench/services/browserElements/electron-browser/browserElementsService.ts similarity index 97% rename from src/vs/workbench/services/browserElements/electron-sandbox/browserElementsService.ts rename to src/vs/workbench/services/browserElements/electron-browser/browserElementsService.ts index 0f28cde37f5..b2aae31f500 100644 --- a/src/vs/workbench/services/browserElements/electron-sandbox/browserElementsService.ts +++ b/src/vs/workbench/services/browserElements/electron-browser/browserElementsService.ts @@ -5,12 +5,12 @@ import { BrowserType, IElementData, INativeBrowserElementsService } from '../../../../platform/browserElements/common/browserElements.js'; import { IRectangle } from '../../../../platform/window/common/window.js'; -import { ipcRenderer } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { ipcRenderer } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; import { IBrowserElementsService } from '../browser/browserElementsService.js'; import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { NativeBrowserElementsService } from '../../../../platform/browserElements/common/nativeBrowserElementsService.js'; class WorkbenchNativeBrowserElementsService extends NativeBrowserElementsService { diff --git a/src/vs/workbench/services/checksum/electron-sandbox/checksumService.ts b/src/vs/workbench/services/checksum/electron-browser/checksumService.ts similarity index 92% rename from src/vs/workbench/services/checksum/electron-sandbox/checksumService.ts rename to src/vs/workbench/services/checksum/electron-browser/checksumService.ts index 57824e93880..93b88334fba 100644 --- a/src/vs/workbench/services/checksum/electron-sandbox/checksumService.ts +++ b/src/vs/workbench/services/checksum/electron-browser/checksumService.ts @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { IChecksumService } from '../../../../platform/checksum/common/checksumService.js'; -import { registerSharedProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; registerSharedProcessRemoteService(IChecksumService, 'checksum'); diff --git a/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts b/src/vs/workbench/services/clipboard/electron-browser/clipboardService.ts similarity index 100% rename from src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts rename to src/vs/workbench/services/clipboard/electron-browser/clipboardService.ts diff --git a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts similarity index 96% rename from src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts rename to src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts index 0e228ecb9f6..f169e776482 100644 --- a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; @@ -13,7 +13,7 @@ import { IConfigurationResolverService } from '../common/configurationResolver.j import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { BaseConfigurationResolverService } from '../browser/baseConfigurationResolverService.js'; import { ILabelService } from '../../../../platform/label/common/label.js'; -import { IShellEnvironmentService } from '../../environment/electron-sandbox/shellEnvironmentService.js'; +import { IShellEnvironmentService } from '../../environment/electron-browser/shellEnvironmentService.js'; import { IPathService } from '../../path/common/pathService.js'; import { IExtensionService } from '../../extensions/common/extensions.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; diff --git a/src/vs/workbench/services/configurationResolver/test/electron-sandbox/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts similarity index 100% rename from src/vs/workbench/services/configurationResolver/test/electron-sandbox/configurationResolverService.test.ts rename to src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts diff --git a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts similarity index 99% rename from src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts rename to src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index a7999fb3b67..fb971f742d5 100644 --- a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -14,7 +14,7 @@ import { INotificationService } from '../../../../platform/notification/common/n import { IContextMenuDelegate, IContextMenuEvent } from '../../../../base/browser/contextmenu.js'; import { createSingleCallFunction } from '../../../../base/common/functional.js'; import { IContextMenuItem } from '../../../../base/parts/contextmenu/common/contextmenu.js'; -import { popup } from '../../../../base/parts/contextmenu/electron-sandbox/contextmenu.js'; +import { popup } from '../../../../base/parts/contextmenu/electron-browser/contextmenu.js'; import { hasNativeContextMenu, MenuSettings } from '../../../../platform/window/common/window.js'; import { isMacintosh, isWindows } from '../../../../base/common/platform.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; diff --git a/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts similarity index 100% rename from src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts rename to src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts diff --git a/src/vs/workbench/services/dialogs/test/electron-sandbox/fileDialogService.test.ts b/src/vs/workbench/services/dialogs/test/electron-browser/fileDialogService.test.ts similarity index 99% rename from src/vs/workbench/services/dialogs/test/electron-sandbox/fileDialogService.test.ts rename to src/vs/workbench/services/dialogs/test/electron-browser/fileDialogService.test.ts index f75cd47844e..f97f6a1d418 100644 --- a/src/vs/workbench/services/dialogs/test/electron-sandbox/fileDialogService.test.ts +++ b/src/vs/workbench/services/dialogs/test/electron-browser/fileDialogService.test.ts @@ -25,7 +25,7 @@ import { IOpenerService } from '../../../../../platform/opener/common/opener.js' import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { IWorkspacesService } from '../../../../../platform/workspaces/common/workspaces.js'; import { ISimpleFileDialog } from '../../browser/simpleFileDialog.js'; -import { FileDialogService } from '../../electron-sandbox/fileDialogService.js'; +import { FileDialogService } from '../../electron-browser/fileDialogService.js'; import { IEditorService } from '../../../editor/common/editorService.js'; import { BrowserWorkbenchEnvironmentService } from '../../../environment/browser/environmentService.js'; import { IWorkbenchEnvironmentService } from '../../../environment/common/environmentService.js'; diff --git a/src/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts b/src/vs/workbench/services/encryption/electron-browser/encryptionService.ts similarity index 93% rename from src/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts rename to src/vs/workbench/services/encryption/electron-browser/encryptionService.ts index 8847433ce45..38d746bcd1f 100644 --- a/src/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts +++ b/src/vs/workbench/services/encryption/electron-browser/encryptionService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; import { IEncryptionService } from '../../../../platform/encryption/common/encryptionService.js'; registerMainProcessRemoteService(IEncryptionService, 'encryption'); diff --git a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts b/src/vs/workbench/services/environment/electron-browser/environmentService.ts similarity index 100% rename from src/vs/workbench/services/environment/electron-sandbox/environmentService.ts rename to src/vs/workbench/services/environment/electron-browser/environmentService.ts diff --git a/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts b/src/vs/workbench/services/environment/electron-browser/shellEnvironmentService.ts similarity index 98% rename from src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts rename to src/vs/workbench/services/environment/electron-browser/shellEnvironmentService.ts index a05b8eacd24..b8108603fff 100644 --- a/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts +++ b/src/vs/workbench/services/environment/electron-browser/shellEnvironmentService.ts @@ -5,7 +5,7 @@ import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { IProcessEnvironment } from '../../../../base/common/platform.js'; -import { process } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { process } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; export const IShellEnvironmentService = createDecorator('shellEnvironmentService'); diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionGalleryManifestService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionGalleryManifestService.ts similarity index 99% rename from src/vs/workbench/services/extensionManagement/electron-sandbox/extensionGalleryManifestService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/extensionGalleryManifestService.ts index 4e494937b12..92d78c4f30f 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionGalleryManifestService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-browser/extensionGalleryManifestService.ts @@ -15,7 +15,7 @@ import { ExtensionGalleryManifestService as ExtensionGalleryManifestService } fr import { resolveMarketplaceHeaders } from '../../../../platform/externalServices/common/marketplace.js'; import { IFileService } from '../../../../platform/files/common/files.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; import { asJson, IRequestService } from '../../../../platform/request/common/request.js'; diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts similarity index 99% rename from src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts index eaf010aafef..c76644b7c28 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts @@ -8,7 +8,7 @@ import { Schemas } from '../../../../base/common/network.js'; import { ExtensionInstallLocation, IExtensionManagementServer, IExtensionManagementServerService } from '../common/extensionManagement.js'; import { IRemoteAgentService } from '../../remote/common/remoteAgentService.js'; import { IChannel } from '../../../../base/parts/ipc/common/ipc.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { NativeRemoteExtensionManagementService } from './remoteExtensionManagementService.js'; import { ILabelService } from '../../../../platform/label/common/label.js'; diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementService.ts similarity index 99% rename from src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementService.ts index eeae819a083..68eddb835ba 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementService.ts @@ -13,7 +13,7 @@ import { Schemas } from '../../../../base/common/network.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IDownloadService } from '../../../../platform/download/common/download.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { joinPath } from '../../../../base/common/resources.js'; import { IUserDataSyncEnablementService } from '../../../../platform/userDataSync/common/userDataSync.js'; import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionTipsService.ts similarity index 98% rename from src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/extensionTipsService.ts index f27ddc63799..b20e96c6a97 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-browser/extensionTipsService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { IChannel } from '../../../../base/parts/ipc/common/ipc.js'; import { IExtensionTipsService, IExecutableBasedExtensionTip, IConfigBasedExtensionTip } from '../../../../platform/extensionManagement/common/extensionManagement.js'; import { URI } from '../../../../base/common/uri.js'; diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/nativeExtensionManagementService.ts similarity index 98% rename from src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/nativeExtensionManagementService.ts index b45ca0bcce6..cb1e06e97c8 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-browser/nativeExtensionManagementService.ts @@ -17,7 +17,7 @@ import { IFileService } from '../../../../platform/files/common/files.js'; import { generateUuid } from '../../../../base/common/uuid.js'; import { ProfileAwareExtensionManagementChannelClient } from '../common/extensionManagementChannelClient.js'; import { ExtensionIdentifier, ExtensionType, isResolverExtension } from '../../../../platform/extensions/common/extensions.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; export class NativeExtensionManagementService extends ProfileAwareExtensionManagementChannelClient implements IProfileAwareExtensionManagementService { diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/remoteExtensionManagementService.ts similarity index 100% rename from src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/remoteExtensionManagementService.ts diff --git a/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts similarity index 100% rename from src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts rename to src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts diff --git a/src/vs/workbench/services/extensions/electron-sandbox/extensionHostProfiler.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts similarity index 100% rename from src/vs/workbench/services/extensions/electron-sandbox/extensionHostProfiler.ts rename to src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts diff --git a/src/vs/workbench/services/extensions/electron-sandbox/extensionHostStarter.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostStarter.ts similarity index 93% rename from src/vs/workbench/services/extensions/electron-sandbox/extensionHostStarter.ts rename to src/vs/workbench/services/extensions/electron-browser/extensionHostStarter.ts index e8bcaabe8eb..cc0b19746e7 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/extensionHostStarter.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostStarter.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; import { IExtensionHostStarter, ipcExtensionHostStarterChannelName } from '../../../../platform/extensions/common/extensionHostStarter.js'; registerMainProcessRemoteService(IExtensionHostStarter, ipcExtensionHostStarterChannelName); diff --git a/src/vs/workbench/services/extensions/electron-sandbox/extensionsScannerService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionsScannerService.ts similarity index 100% rename from src/vs/workbench/services/extensions/electron-sandbox/extensionsScannerService.ts rename to src/vs/workbench/services/extensions/electron-browser/extensionsScannerService.ts diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts similarity index 99% rename from src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts rename to src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts index 41b8bc38af9..803a4fd75db 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts @@ -16,7 +16,7 @@ import { URI } from '../../../../base/common/uri.js'; import { generateUuid } from '../../../../base/common/uuid.js'; import { IMessagePassingProtocol } from '../../../../base/parts/ipc/common/ipc.js'; import { BufferedEmitter } from '../../../../base/parts/ipc/common/ipc.net.js'; -import { acquirePort } from '../../../../base/parts/ipc/electron-sandbox/ipc.mp.js'; +import { acquirePort } from '../../../../base/parts/ipc/electron-browser/ipc.mp.js'; import * as nls from '../../../../nls.js'; import { IExtensionHostDebugService } from '../../../../platform/debug/common/extensionHostDebug.js'; import { IExtensionHostProcessOptions, IExtensionHostStarter } from '../../../../platform/extensions/common/extensionHostStarter.js'; @@ -29,8 +29,8 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { isLoggingOnly } from '../../../../platform/telemetry/common/telemetryUtils.js'; import { IUserDataProfilesService } from '../../../../platform/userDataProfile/common/userDataProfile.js'; import { IWorkspaceContextService, WorkbenchState, isUntitledWorkspace } from '../../../../platform/workspace/common/workspace.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; -import { IShellEnvironmentService } from '../../environment/electron-sandbox/shellEnvironmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; +import { IShellEnvironmentService } from '../../environment/electron-browser/shellEnvironmentService.js'; import { MessagePortExtHostConnection, writeExtHostConnection } from '../common/extensionHostEnv.js'; import { IExtensionHostInitData, MessageType, NativeLogMarkers, UIKind, isMessageOfType } from '../common/extensionHostProtocol.js'; import { LocalProcessRunningLocation } from '../common/extensionRunningLocation.js'; diff --git a/src/vs/workbench/services/extensions/electron-sandbox/nativeExtensionService.ts b/src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts similarity index 100% rename from src/vs/workbench/services/extensions/electron-sandbox/nativeExtensionService.ts rename to src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts diff --git a/src/vs/workbench/services/files/electron-sandbox/diskFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts similarity index 99% rename from src/vs/workbench/services/files/electron-sandbox/diskFileSystemProvider.ts rename to src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts index 85b2f1eb68a..5c0af31e6b3 100644 --- a/src/vs/workbench/services/files/electron-sandbox/diskFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts @@ -16,7 +16,7 @@ import { DiskFileSystemProviderClient, LOCAL_FILE_SYSTEM_CHANNEL_NAME } from '.. import { ILogMessage, AbstractUniversalWatcherClient } from '../../../../platform/files/common/watcher.js'; import { UniversalWatcherClient } from './watcherClient.js'; import { ILoggerService, ILogService } from '../../../../platform/log/common/log.js'; -import { IUtilityProcessWorkerWorkbenchService } from '../../utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.js'; +import { IUtilityProcessWorkerWorkbenchService } from '../../utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.js'; import { LogService } from '../../../../platform/log/common/logService.js'; /** diff --git a/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts b/src/vs/workbench/services/files/electron-browser/elevatedFileService.ts similarity index 98% rename from src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts rename to src/vs/workbench/services/files/electron-browser/elevatedFileService.ts index 158a5ac0f4c..19c2a1c0640 100644 --- a/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/elevatedFileService.ts @@ -12,7 +12,7 @@ import { IFileService, IFileStatWithMetadata, IWriteFileOptions } from '../../.. import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; import { IWorkspaceTrustRequestService } from '../../../../platform/workspace/common/workspaceTrust.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IElevatedFileService } from '../common/elevatedFileService.js'; import { isWindows } from '../../../../base/common/platform.js'; import { ILabelService } from '../../../../platform/label/common/label.js'; diff --git a/src/vs/workbench/services/files/electron-sandbox/watcherClient.ts b/src/vs/workbench/services/files/electron-browser/watcherClient.ts similarity index 97% rename from src/vs/workbench/services/files/electron-sandbox/watcherClient.ts rename to src/vs/workbench/services/files/electron-browser/watcherClient.ts index 2c8554796b3..39bcfbd0bbe 100644 --- a/src/vs/workbench/services/files/electron-sandbox/watcherClient.ts +++ b/src/vs/workbench/services/files/electron-browser/watcherClient.ts @@ -7,7 +7,7 @@ import { DisposableStore } from '../../../../base/common/lifecycle.js'; import { getDelayedChannel, ProxyChannel } from '../../../../base/parts/ipc/common/ipc.js'; import { IFileChange } from '../../../../platform/files/common/files.js'; import { AbstractUniversalWatcherClient, ILogMessage, IRecursiveWatcher } from '../../../../platform/files/common/watcher.js'; -import { IUtilityProcessWorkerWorkbenchService } from '../../utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.js'; +import { IUtilityProcessWorkerWorkbenchService } from '../../utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.js'; export class UniversalWatcherClient extends AbstractUniversalWatcherClient { diff --git a/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts b/src/vs/workbench/services/host/electron-browser/nativeHostService.ts similarity index 99% rename from src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts rename to src/vs/workbench/services/host/electron-browser/nativeHostService.ts index f3d99829c08..cb7dcc810e2 100644 --- a/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts +++ b/src/vs/workbench/services/host/electron-browser/nativeHostService.ts @@ -12,7 +12,7 @@ import { IWorkbenchEnvironmentService } from '../../environment/common/environme import { IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions, IPoint, IRectangle } from '../../../../platform/window/common/window.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { NativeHostService } from '../../../../platform/native/common/nativeHostService.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js'; import { disposableWindowInterval, getActiveDocument, getWindowId, getWindowsCount, hasWindow, onDidRegisterWindow } from '../../../../base/browser/dom.js'; import { memoize } from '../../../../base/common/decorators.js'; diff --git a/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts b/src/vs/workbench/services/integrity/electron-browser/integrityService.ts similarity index 100% rename from src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts rename to src/vs/workbench/services/integrity/electron-browser/integrityService.ts diff --git a/src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout.ts b/src/vs/workbench/services/keybinding/electron-browser/nativeKeyboardLayout.ts similarity index 100% rename from src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout.ts rename to src/vs/workbench/services/keybinding/electron-browser/nativeKeyboardLayout.ts diff --git a/src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayoutService.ts b/src/vs/workbench/services/keybinding/electron-browser/nativeKeyboardLayoutService.ts similarity index 100% rename from src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayoutService.ts rename to src/vs/workbench/services/keybinding/electron-browser/nativeKeyboardLayoutService.ts diff --git a/src/vs/workbench/services/lifecycle/electron-sandbox/lifecycleService.ts b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts similarity index 99% rename from src/vs/workbench/services/lifecycle/electron-sandbox/lifecycleService.ts rename to src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts index b7fe1aadac3..762840ba2f2 100644 --- a/src/vs/workbench/services/lifecycle/electron-sandbox/lifecycleService.ts +++ b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts @@ -6,7 +6,7 @@ import { handleVetos } from '../../../../platform/lifecycle/common/lifecycle.js'; import { ShutdownReason, ILifecycleService, IWillShutdownEventJoiner, WillShutdownJoinerOrder } from '../common/lifecycle.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; -import { ipcRenderer } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { ipcRenderer } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { AbstractLifecycleService } from '../common/lifecycleService.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; diff --git a/src/vs/workbench/services/lifecycle/test/electron-sandbox/lifecycleService.test.ts b/src/vs/workbench/services/lifecycle/test/electron-browser/lifecycleService.test.ts similarity index 98% rename from src/vs/workbench/services/lifecycle/test/electron-sandbox/lifecycleService.test.ts rename to src/vs/workbench/services/lifecycle/test/electron-browser/lifecycleService.test.ts index 7afb9dd0ab0..fe043e7004d 100644 --- a/src/vs/workbench/services/lifecycle/test/electron-sandbox/lifecycleService.test.ts +++ b/src/vs/workbench/services/lifecycle/test/electron-browser/lifecycleService.test.ts @@ -9,8 +9,8 @@ import { DisposableStore } from '../../../../../base/common/lifecycle.js'; import { runWithFakedTimers } from '../../../../../base/test/common/timeTravelScheduler.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; import { ShutdownReason, WillShutdownJoinerOrder } from '../../common/lifecycle.js'; -import { NativeLifecycleService } from '../../electron-sandbox/lifecycleService.js'; -import { workbenchInstantiationService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { NativeLifecycleService } from '../../electron-browser/lifecycleService.js'; +import { workbenchInstantiationService } from '../../../../test/electron-browser/workbenchTestServices.js'; suite('Lifecycleservice', function () { diff --git a/src/vs/workbench/services/localization/electron-sandbox/languagePackService.ts b/src/vs/workbench/services/localization/electron-browser/languagePackService.ts similarity index 93% rename from src/vs/workbench/services/localization/electron-sandbox/languagePackService.ts rename to src/vs/workbench/services/localization/electron-browser/languagePackService.ts index 5c07673518d..a66deb42f13 100644 --- a/src/vs/workbench/services/localization/electron-sandbox/languagePackService.ts +++ b/src/vs/workbench/services/localization/electron-browser/languagePackService.ts @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { ILanguagePackService } from '../../../../platform/languagePacks/common/languagePacks.js'; -import { registerSharedProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; registerSharedProcessRemoteService(ILanguagePackService, 'languagePacks'); diff --git a/src/vs/workbench/services/localization/electron-sandbox/localeService.ts b/src/vs/workbench/services/localization/electron-browser/localeService.ts similarity index 100% rename from src/vs/workbench/services/localization/electron-sandbox/localeService.ts rename to src/vs/workbench/services/localization/electron-browser/localeService.ts diff --git a/src/vs/workbench/services/log/electron-sandbox/logService.ts b/src/vs/workbench/services/log/electron-browser/logService.ts similarity index 97% rename from src/vs/workbench/services/log/electron-sandbox/logService.ts rename to src/vs/workbench/services/log/electron-browser/logService.ts index 34245d85ff0..97ae7dbbf90 100644 --- a/src/vs/workbench/services/log/electron-sandbox/logService.ts +++ b/src/vs/workbench/services/log/electron-browser/logService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ConsoleLogger, ILogger } from '../../../../platform/log/common/log.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { LoggerChannelClient } from '../../../../platform/log/common/logIpc.js'; import { DisposableStore } from '../../../../base/common/lifecycle.js'; import { windowLogGroup, windowLogId } from '../common/logConstants.js'; diff --git a/src/vs/workbench/services/menubar/electron-sandbox/menubarService.ts b/src/vs/workbench/services/menubar/electron-browser/menubarService.ts similarity index 88% rename from src/vs/workbench/services/menubar/electron-sandbox/menubarService.ts rename to src/vs/workbench/services/menubar/electron-browser/menubarService.ts index 7b00164b381..bd5d8836993 100644 --- a/src/vs/workbench/services/menubar/electron-sandbox/menubarService.ts +++ b/src/vs/workbench/services/menubar/electron-browser/menubarService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IMenubarService } from '../../../../platform/menubar/electron-sandbox/menubar.js'; -import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { IMenubarService } from '../../../../platform/menubar/electron-browser/menubar.js'; +import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; registerMainProcessRemoteService(IMenubarService, 'menubar'); diff --git a/src/vs/workbench/services/path/electron-sandbox/pathService.ts b/src/vs/workbench/services/path/electron-browser/pathService.ts similarity index 96% rename from src/vs/workbench/services/path/electron-sandbox/pathService.ts rename to src/vs/workbench/services/path/electron-browser/pathService.ts index b2fbd6d92dd..5adc3bb3c6b 100644 --- a/src/vs/workbench/services/path/electron-sandbox/pathService.ts +++ b/src/vs/workbench/services/path/electron-browser/pathService.ts @@ -5,7 +5,7 @@ import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { IRemoteAgentService } from '../../remote/common/remoteAgentService.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IPathService, AbstractPathService } from '../common/pathService.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; diff --git a/src/vs/workbench/services/process/electron-sandbox/processService.ts b/src/vs/workbench/services/process/electron-browser/processService.ts similarity index 93% rename from src/vs/workbench/services/process/electron-sandbox/processService.ts rename to src/vs/workbench/services/process/electron-browser/processService.ts index e47499664b7..1d9b8f2b17f 100644 --- a/src/vs/workbench/services/process/electron-sandbox/processService.ts +++ b/src/vs/workbench/services/process/electron-browser/processService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; import { IProcessService } from '../../../../platform/process/common/process.js'; registerMainProcessRemoteService(IProcessService, 'process'); diff --git a/src/vs/workbench/services/remote/electron-sandbox/remoteAgentService.ts b/src/vs/workbench/services/remote/electron-browser/remoteAgentService.ts similarity index 100% rename from src/vs/workbench/services/remote/electron-sandbox/remoteAgentService.ts rename to src/vs/workbench/services/remote/electron-browser/remoteAgentService.ts diff --git a/src/vs/workbench/services/request/electron-sandbox/requestService.ts b/src/vs/workbench/services/request/electron-browser/requestService.ts similarity index 100% rename from src/vs/workbench/services/request/electron-sandbox/requestService.ts rename to src/vs/workbench/services/request/electron-browser/requestService.ts diff --git a/src/vs/workbench/services/search/electron-sandbox/searchService.ts b/src/vs/workbench/services/search/electron-browser/searchService.ts similarity index 100% rename from src/vs/workbench/services/search/electron-sandbox/searchService.ts rename to src/vs/workbench/services/search/electron-browser/searchService.ts diff --git a/src/vs/workbench/services/secrets/electron-sandbox/secretStorageService.ts b/src/vs/workbench/services/secrets/electron-browser/secretStorageService.ts similarity index 100% rename from src/vs/workbench/services/secrets/electron-sandbox/secretStorageService.ts rename to src/vs/workbench/services/secrets/electron-browser/secretStorageService.ts diff --git a/src/vs/workbench/services/sharedProcess/electron-sandbox/sharedProcessService.ts b/src/vs/workbench/services/sharedProcess/electron-browser/sharedProcessService.ts similarity index 98% rename from src/vs/workbench/services/sharedProcess/electron-sandbox/sharedProcessService.ts rename to src/vs/workbench/services/sharedProcess/electron-browser/sharedProcessService.ts index 8110886c226..ed735cbe689 100644 --- a/src/vs/workbench/services/sharedProcess/electron-sandbox/sharedProcessService.ts +++ b/src/vs/workbench/services/sharedProcess/electron-browser/sharedProcessService.ts @@ -7,11 +7,11 @@ import { Client as MessagePortClient } from '../../../../base/parts/ipc/common/i import { IChannel, IServerChannel, getDelayedChannel } from '../../../../base/parts/ipc/common/ipc.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { SharedProcessChannelConnection, SharedProcessRawConnection } from '../../../../platform/sharedProcess/common/sharedProcess.js'; import { mark } from '../../../../base/common/performance.js'; import { Barrier, timeout } from '../../../../base/common/async.js'; -import { acquirePort } from '../../../../base/parts/ipc/electron-sandbox/ipc.mp.js'; +import { acquirePort } from '../../../../base/parts/ipc/electron-browser/ipc.mp.js'; export class SharedProcessService extends Disposable implements ISharedProcessService { diff --git a/src/vs/workbench/services/storage/electron-sandbox/storageService.ts b/src/vs/workbench/services/storage/electron-browser/storageService.ts similarity index 100% rename from src/vs/workbench/services/storage/electron-sandbox/storageService.ts rename to src/vs/workbench/services/storage/electron-browser/storageService.ts diff --git a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts similarity index 97% rename from src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts rename to src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts index e49eaefbbab..75d61ed72d7 100644 --- a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts @@ -7,16 +7,16 @@ import { ITelemetryService, ITelemetryData, TelemetryLevel } from '../../../../p import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from '../../../../platform/telemetry/common/telemetryUtils.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { TelemetryAppenderClient } from '../../../../platform/telemetry/common/telemetryIpc.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; import { resolveWorkbenchCommonProperties } from '../common/workbenchCommonProperties.js'; import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from '../../../../platform/telemetry/common/telemetryService.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { ClassifiedEvent, StrictPropertyCheck, OmitMetadata, IGDPRProperty } from '../../../../platform/telemetry/common/gdprTypings.js'; -import { process } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { process } from '../../../../base/parts/sandbox/electron-browser/globals.js'; export class TelemetryService extends Disposable implements ITelemetryService { diff --git a/src/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts similarity index 99% rename from src/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts rename to src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index 913208b2221..79ef5c9ace6 100644 --- a/src/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -14,7 +14,7 @@ import { IUntitledTextEditorModelManager, IUntitledTextEditorService } from '../ import { ILifecycleService } from '../../lifecycle/common/lifecycle.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { IModelService } from '../../../../editor/common/services/model.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IDialogService, IFileDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { IFilesConfigurationService } from '../../filesConfiguration/common/filesConfigurationService.js'; import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; diff --git a/src/vs/workbench/services/textfile/test/electron-sandbox/nativeTextFileService.io.test.ts b/src/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.io.test.ts similarity index 98% rename from src/vs/workbench/services/textfile/test/electron-sandbox/nativeTextFileService.io.test.ts rename to src/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.io.test.ts index 9be96d96683..0fbc74192de 100644 --- a/src/vs/workbench/services/textfile/test/electron-sandbox/nativeTextFileService.io.test.ts +++ b/src/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.io.test.ts @@ -21,7 +21,7 @@ import { IWorkingCopyFileService, WorkingCopyFileService } from '../../../workin import { WorkingCopyService } from '../../../workingCopy/common/workingCopyService.js'; import { UriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentityService.js'; import { TestInMemoryFileSystemProvider } from '../../../../test/browser/workbenchTestServices.js'; -import { TestNativeTextFileServiceWithEncodingOverrides, workbenchInstantiationService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { TestNativeTextFileServiceWithEncodingOverrides, workbenchInstantiationService } from '../../../../test/electron-browser/workbenchTestServices.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; suite('Files - NativeTextFileService i/o', function () { diff --git a/src/vs/workbench/services/textfile/test/electron-sandbox/nativeTextFileService.test.ts b/src/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.test.ts similarity index 98% rename from src/vs/workbench/services/textfile/test/electron-sandbox/nativeTextFileService.test.ts rename to src/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.test.ts index 91250289f3a..6128845b778 100644 --- a/src/vs/workbench/services/textfile/test/electron-sandbox/nativeTextFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.test.ts @@ -12,7 +12,7 @@ import { ServiceCollection } from '../../../../../platform/instantiation/common/ import { DisposableStore } from '../../../../../base/common/lifecycle.js'; import { FileService } from '../../../../../platform/files/common/fileService.js'; import { NullLogService } from '../../../../../platform/log/common/log.js'; -import { TestNativeTextFileServiceWithEncodingOverrides, TestServiceAccessor, workbenchInstantiationService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { TestNativeTextFileServiceWithEncodingOverrides, TestServiceAccessor, workbenchInstantiationService } from '../../../../test/electron-browser/workbenchTestServices.js'; import { IWorkingCopyFileService, WorkingCopyFileService } from '../../../workingCopy/common/workingCopyFileService.js'; import { WorkingCopyService } from '../../../workingCopy/common/workingCopyService.js'; import { UriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentityService.js'; diff --git a/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts b/src/vs/workbench/services/themes/electron-browser/nativeHostColorSchemeService.ts similarity index 98% rename from src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts rename to src/vs/workbench/services/themes/electron-browser/nativeHostColorSchemeService.ts index b22de86f799..22cd3472570 100644 --- a/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/nativeHostColorSchemeService.ts @@ -8,7 +8,7 @@ import { INativeHostService } from '../../../../platform/native/common/native.js import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { IHostColorSchemeService } from '../common/hostColorSchemeService.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { isBoolean, isObject } from '../../../../base/common/types.js'; import { IColorScheme } from '../../../../platform/window/common/window.js'; diff --git a/src/vs/workbench/services/themes/electron-sandbox/themes.contribution.ts b/src/vs/workbench/services/themes/electron-browser/themes.contribution.ts similarity index 100% rename from src/vs/workbench/services/themes/electron-sandbox/themes.contribution.ts rename to src/vs/workbench/services/themes/electron-browser/themes.contribution.ts diff --git a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts similarity index 98% rename from src/vs/workbench/services/timer/electron-sandbox/timerService.ts rename to src/vs/workbench/services/timer/electron-browser/timerService.ts index e992d1fb55c..a12cfdc7d42 100644 --- a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { INativeHostService } from '../../../../platform/native/common/native.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; import { IExtensionService } from '../../extensions/common/extensions.js'; import { IUpdateService } from '../../../../platform/update/common/update.js'; @@ -13,7 +13,7 @@ import { IEditorService } from '../../editor/common/editorService.js'; import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js'; import { IStartupMetrics, AbstractTimerService, Writeable, ITimerService } from '../browser/timerService.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; -import { process } from '../../../../base/parts/sandbox/electron-sandbox/globals.js'; +import { process } from '../../../../base/parts/sandbox/electron-browser/globals.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { IWorkbenchLayoutService } from '../../layout/browser/layoutService.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; diff --git a/src/vs/workbench/services/title/electron-sandbox/titleService.ts b/src/vs/workbench/services/title/electron-browser/titleService.ts similarity index 90% rename from src/vs/workbench/services/title/electron-sandbox/titleService.ts rename to src/vs/workbench/services/title/electron-browser/titleService.ts index 00244e14a85..a7d742993ce 100644 --- a/src/vs/workbench/services/title/electron-sandbox/titleService.ts +++ b/src/vs/workbench/services/title/electron-browser/titleService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; -import { NativeTitleService } from '../../../electron-sandbox/parts/titlebar/titlebarPart.js'; +import { NativeTitleService } from '../../../electron-browser/parts/titlebar/titlebarPart.js'; import { ITitleService } from '../browser/titleService.js'; registerSingleton(ITitleService, NativeTitleService, InstantiationType.Eager); diff --git a/src/vs/workbench/services/tunnel/electron-sandbox/tunnelService.ts b/src/vs/workbench/services/tunnel/electron-browser/tunnelService.ts similarity index 99% rename from src/vs/workbench/services/tunnel/electron-sandbox/tunnelService.ts rename to src/vs/workbench/services/tunnel/electron-browser/tunnelService.ts index 0706995795a..f16f1c30360 100644 --- a/src/vs/workbench/services/tunnel/electron-sandbox/tunnelService.ts +++ b/src/vs/workbench/services/tunnel/electron-browser/tunnelService.ts @@ -14,7 +14,7 @@ import { ISharedProcessTunnelService } from '../../../../platform/remote/common/ import { ILifecycleService } from '../../lifecycle/common/lifecycle.js'; import { IRemoteAuthorityResolverService } from '../../../../platform/remote/common/remoteAuthorityResolver.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { OS } from '../../../../base/common/platform.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; diff --git a/src/vs/workbench/services/update/electron-sandbox/updateService.ts b/src/vs/workbench/services/update/electron-browser/updateService.ts similarity index 94% rename from src/vs/workbench/services/update/electron-sandbox/updateService.ts rename to src/vs/workbench/services/update/electron-browser/updateService.ts index 5ddd452efe4..c6bb0ae6063 100644 --- a/src/vs/workbench/services/update/electron-sandbox/updateService.ts +++ b/src/vs/workbench/services/update/electron-browser/updateService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IUpdateService } from '../../../../platform/update/common/update.js'; -import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerMainProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; import { UpdateChannelClient } from '../../../../platform/update/common/updateIpc.js'; registerMainProcessRemoteService(IUpdateService, 'update', { channelClientCtor: UpdateChannelClient }); diff --git a/src/vs/workbench/services/url/electron-sandbox/urlService.ts b/src/vs/workbench/services/url/electron-browser/urlService.ts similarity index 100% rename from src/vs/workbench/services/url/electron-sandbox/urlService.ts rename to src/vs/workbench/services/url/electron-browser/urlService.ts diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts similarity index 98% rename from src/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts rename to src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts index 5c265c0ee65..69503a49c1e 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IUserDataAutoSyncService, SyncOptions, UserDataSyncError } from '../../../../platform/userDataSync/common/userDataSync.js'; -import { ISharedProcessService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; import { IChannel } from '../../../../base/parts/ipc/common/ipc.js'; import { Event } from '../../../../base/common/event.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts similarity index 97% rename from src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts rename to src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts index dc701548db8..a5b5857741f 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IUserDataSyncResourceProviderService, IUserDataSyncService, IUserDataSyncStoreManagementService } from '../../../../platform/userDataSync/common/userDataSync.js'; -import { registerSharedProcessRemoteService } from '../../../../platform/ipc/electron-sandbox/services.js'; +import { registerSharedProcessRemoteService } from '../../../../platform/ipc/electron-browser/services.js'; import { UserDataSyncServiceChannelClient } from '../../../../platform/userDataSync/common/userDataSyncServiceIpc.js'; import { IUserDataSyncMachinesService } from '../../../../platform/userDataSync/common/userDataSyncMachines.js'; import { UserDataSyncAccountServiceChannelClient, UserDataSyncStoreManagementServiceChannelClient } from '../../../../platform/userDataSync/common/userDataSyncIpc.js'; diff --git a/src/vs/workbench/services/utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.ts b/src/vs/workbench/services/utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.ts similarity index 99% rename from src/vs/workbench/services/utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.ts rename to src/vs/workbench/services/utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.ts index 4f6672fda74..d074d17baeb 100644 --- a/src/vs/workbench/services/utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.ts +++ b/src/vs/workbench/services/utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.ts @@ -10,7 +10,7 @@ import { Client as MessagePortClient } from '../../../../base/parts/ipc/common/i import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { IPCClient, ProxyChannel } from '../../../../base/parts/ipc/common/ipc.js'; import { generateUuid } from '../../../../base/common/uuid.js'; -import { acquirePort } from '../../../../base/parts/ipc/electron-sandbox/ipc.mp.js'; +import { acquirePort } from '../../../../base/parts/ipc/electron-browser/ipc.mp.js'; import { IOnDidTerminateUtilityrocessWorkerProcess, ipcUtilityProcessWorkerChannelName, IUtilityProcessWorkerProcess, IUtilityProcessWorkerService } from '../../../../platform/utilityProcess/common/utilityProcessWorkerService.js'; import { Barrier, timeout } from '../../../../base/common/async.js'; diff --git a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts b/src/vs/workbench/services/workingCopy/electron-browser/workingCopyBackupService.ts similarity index 98% rename from src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts rename to src/vs/workbench/services/workingCopy/electron-browser/workingCopyBackupService.ts index fa5167d131e..ac4b7ec16ce 100644 --- a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts +++ b/src/vs/workbench/services/workingCopy/electron-browser/workingCopyBackupService.ts @@ -10,7 +10,7 @@ import { InstantiationType, registerSingleton } from '../../../../platform/insta import { IWorkingCopyBackupService } from '../common/workingCopyBackup.js'; import { IFileService } from '../../../../platform/files/common/files.js'; import { ILogService } from '../../../../platform/log/common/log.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js'; import { ILifecycleService } from '../../lifecycle/common/lifecycle.js'; import { NativeWorkingCopyBackupTracker } from './workingCopyBackupTracker.js'; diff --git a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts b/src/vs/workbench/services/workingCopy/electron-browser/workingCopyBackupTracker.ts similarity index 100% rename from src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts rename to src/vs/workbench/services/workingCopy/electron-browser/workingCopyBackupTracker.ts diff --git a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService.ts b/src/vs/workbench/services/workingCopy/electron-browser/workingCopyHistoryService.ts similarity index 100% rename from src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService.ts rename to src/vs/workbench/services/workingCopy/electron-browser/workingCopyHistoryService.ts diff --git a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupService.test.ts b/src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupService.test.ts similarity index 99% rename from src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupService.test.ts rename to src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupService.test.ts index 41d4150230f..b3fb5c37566 100644 --- a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupService.test.ts @@ -15,10 +15,10 @@ import { createTextModel } from '../../../../../editor/test/common/testTextModel import { Schemas } from '../../../../../base/common/network.js'; import { FileService } from '../../../../../platform/files/common/fileService.js'; import { LogLevel, NullLogService } from '../../../../../platform/log/common/log.js'; -import { NativeWorkbenchEnvironmentService } from '../../../environment/electron-sandbox/environmentService.js'; +import { NativeWorkbenchEnvironmentService } from '../../../environment/electron-browser/environmentService.js'; import { toBufferOrReadable } from '../../../textfile/common/textfiles.js'; import { IFileService } from '../../../../../platform/files/common/files.js'; -import { NativeWorkingCopyBackupService } from '../../electron-sandbox/workingCopyBackupService.js'; +import { NativeWorkingCopyBackupService } from '../../electron-browser/workingCopyBackupService.js'; import { FileUserDataProvider } from '../../../../../platform/userData/common/fileUserDataProvider.js'; import { bufferToReadable, bufferToStream, streamToBuffer, VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../../../base/common/buffer.js'; import { TestLifecycleService, toTypedWorkingCopyId, toUntypedWorkingCopyId } from '../../../../test/browser/workbenchTestServices.js'; diff --git a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupTracker.test.ts b/src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupTracker.test.ts similarity index 99% rename from src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupTracker.test.ts rename to src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupTracker.test.ts index ed1ce98a64c..a7ab03c1289 100644 --- a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupTracker.test.ts +++ b/src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupTracker.test.ts @@ -8,7 +8,7 @@ import { isMacintosh, isWindows } from '../../../../../base/common/platform.js'; import { join } from '../../../../../base/common/path.js'; import { URI } from '../../../../../base/common/uri.js'; import { hash } from '../../../../../base/common/hash.js'; -import { NativeWorkingCopyBackupTracker } from '../../electron-sandbox/workingCopyBackupTracker.js'; +import { NativeWorkingCopyBackupTracker } from '../../electron-browser/workingCopyBackupTracker.js'; import { TextFileEditorModelManager } from '../../../textfile/common/textFileEditorModelManager.js'; import { IEditorService } from '../../../editor/common/editorService.js'; import { EditorPart } from '../../../../browser/parts/editor/editorPart.js'; @@ -43,7 +43,7 @@ import { generateUuid } from '../../../../../base/common/uuid.js'; import { Schemas } from '../../../../../base/common/network.js'; import { joinPath } from '../../../../../base/common/resources.js'; import { VSBuffer } from '../../../../../base/common/buffer.js'; -import { TestServiceAccessor, workbenchInstantiationService } from '../../../../test/electron-sandbox/workbenchTestServices.js'; +import { TestServiceAccessor, workbenchInstantiationService } from '../../../../test/electron-browser/workbenchTestServices.js'; import { UriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentityService.js'; suite('WorkingCopyBackupTracker (native)', function () { diff --git a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryService.test.ts b/src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyHistoryService.test.ts similarity index 100% rename from src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryService.test.ts rename to src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyHistoryService.test.ts diff --git a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryTracker.test.ts b/src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyHistoryTracker.test.ts similarity index 100% rename from src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyHistoryTracker.test.ts rename to src/vs/workbench/services/workingCopy/test/electron-browser/workingCopyHistoryTracker.test.ts diff --git a/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts similarity index 99% rename from src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts rename to src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts index c285804f40a..cbdca7d06f9 100644 --- a/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts @@ -17,7 +17,7 @@ import { ICommandService } from '../../../../platform/commands/common/commands.j import { basename } from '../../../../base/common/resources.js'; import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; import { IFileService } from '../../../../platform/files/common/files.js'; -import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; +import { INativeWorkbenchEnvironmentService } from '../../environment/electron-browser/environmentService.js'; import { ILifecycleService, ShutdownReason } from '../../lifecycle/common/lifecycle.js'; import { IFileDialogService, IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; diff --git a/src/vs/workbench/services/workspaces/electron-sandbox/workspacesService.ts b/src/vs/workbench/services/workspaces/electron-browser/workspacesService.ts similarity index 100% rename from src/vs/workbench/services/workspaces/electron-sandbox/workspacesService.ts rename to src/vs/workbench/services/workspaces/electron-browser/workspacesService.ts diff --git a/src/vs/workbench/test/electron-sandbox/resolveExternal.test.ts b/src/vs/workbench/test/electron-browser/resolveExternal.test.ts similarity index 98% rename from src/vs/workbench/test/electron-sandbox/resolveExternal.test.ts rename to src/vs/workbench/test/electron-browser/resolveExternal.test.ts index 530b5eb4ef2..94f7576fbdd 100644 --- a/src/vs/workbench/test/electron-sandbox/resolveExternal.test.ts +++ b/src/vs/workbench/test/electron-browser/resolveExternal.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../base/test/common/utils.js'; -import { NativeWindow } from '../../electron-sandbox/window.js'; +import { NativeWindow } from '../../electron-browser/window.js'; import { ITunnelService, RemoteTunnel } from '../../../platform/tunnel/common/tunnel.js'; import { URI } from '../../../base/common/uri.js'; import { TestInstantiationService } from '../../../platform/instantiation/test/common/instantiationServiceMock.js'; diff --git a/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts similarity index 99% rename from src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts rename to src/vs/workbench/test/electron-browser/workbenchTestServices.ts index 83c50d25e72..84d5af6fe3f 100644 --- a/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -5,7 +5,7 @@ import { Event } from '../../../base/common/event.js'; import { workbenchInstantiationService as browserWorkbenchInstantiationService, ITestInstantiationService, TestEncodingOracle, TestEnvironmentService, TestFileDialogService, TestFilesConfigurationService, TestFileService, TestLifecycleService, TestTextFileService } from '../browser/workbenchTestServices.js'; -import { ISharedProcessService } from '../../../platform/ipc/electron-sandbox/services.js'; +import { ISharedProcessService } from '../../../platform/ipc/electron-browser/services.js'; import { INativeHostService, INativeHostOptions, IOSProperties, IOSStatistics } from '../../../platform/native/common/native.js'; import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../base/common/buffer.js'; import { DisposableStore, IDisposable } from '../../../base/common/lifecycle.js'; @@ -36,7 +36,7 @@ import { ILifecycleService } from '../../services/lifecycle/common/lifecycle.js' import { IWorkingCopyBackupService } from '../../services/workingCopy/common/workingCopyBackup.js'; import { IWorkingCopyService } from '../../services/workingCopy/common/workingCopyService.js'; import { TestContextService } from '../common/workbenchTestServices.js'; -import { NativeTextFileService } from '../../services/textfile/electron-sandbox/nativeTextFileService.js'; +import { NativeTextFileService } from '../../services/textfile/electron-browser/nativeTextFileService.js'; import { insert } from '../../../base/common/arrays.js'; import { Schemas } from '../../../base/common/network.js'; import { FileService } from '../../../platform/files/common/fileService.js'; @@ -44,7 +44,7 @@ import { InMemoryFileSystemProvider } from '../../../platform/files/common/inMem import { NullLogService } from '../../../platform/log/common/log.js'; import { FileUserDataProvider } from '../../../platform/userData/common/fileUserDataProvider.js'; import { IWorkingCopyIdentifier } from '../../services/workingCopy/common/workingCopy.js'; -import { NativeWorkingCopyBackupService } from '../../services/workingCopy/electron-sandbox/workingCopyBackupService.js'; +import { NativeWorkingCopyBackupService } from '../../services/workingCopy/electron-browser/workingCopyBackupService.js'; import { CancellationToken } from '../../../base/common/cancellation.js'; import { UriIdentityService } from '../../../platform/uriIdentity/common/uriIdentityService.js'; import { UserDataProfilesService } from '../../../platform/userDataProfile/common/userDataProfile.js'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index b05c17aac15..c9df215ea42 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -19,75 +19,75 @@ import './workbench.common.main.js'; //#region --- workbench (desktop main) -import './electron-sandbox/desktop.main.js'; -import './electron-sandbox/desktop.contribution.js'; +import './electron-browser/desktop.main.js'; +import './electron-browser/desktop.contribution.js'; //#endregion //#region --- workbench parts -import './electron-sandbox/parts/dialogs/dialog.contribution.js'; +import './electron-browser/parts/dialogs/dialog.contribution.js'; //#endregion //#region --- workbench services -import './services/textfile/electron-sandbox/nativeTextFileService.js'; -import './services/dialogs/electron-sandbox/fileDialogService.js'; -import './services/workspaces/electron-sandbox/workspacesService.js'; -import './services/menubar/electron-sandbox/menubarService.js'; -import './services/update/electron-sandbox/updateService.js'; -import './services/url/electron-sandbox/urlService.js'; -import './services/lifecycle/electron-sandbox/lifecycleService.js'; -import './services/title/electron-sandbox/titleService.js'; -import './services/host/electron-sandbox/nativeHostService.js'; -import './services/request/electron-sandbox/requestService.js'; -import './services/clipboard/electron-sandbox/clipboardService.js'; -import './services/contextmenu/electron-sandbox/contextmenuService.js'; -import './services/workspaces/electron-sandbox/workspaceEditingService.js'; -import './services/configurationResolver/electron-sandbox/configurationResolverService.js'; -import './services/accessibility/electron-sandbox/accessibilityService.js'; -import './services/keybinding/electron-sandbox/nativeKeyboardLayout.js'; -import './services/path/electron-sandbox/pathService.js'; -import './services/themes/electron-sandbox/nativeHostColorSchemeService.js'; -import './services/extensionManagement/electron-sandbox/extensionManagementService.js'; -import './services/encryption/electron-sandbox/encryptionService.js'; -import './services/browserElements/electron-sandbox/browserElementsService.js'; -import './services/secrets/electron-sandbox/secretStorageService.js'; -import './services/localization/electron-sandbox/languagePackService.js'; -import './services/telemetry/electron-sandbox/telemetryService.js'; -import './services/extensions/electron-sandbox/extensionHostStarter.js'; +import './services/textfile/electron-browser/nativeTextFileService.js'; +import './services/dialogs/electron-browser/fileDialogService.js'; +import './services/workspaces/electron-browser/workspacesService.js'; +import './services/menubar/electron-browser/menubarService.js'; +import './services/update/electron-browser/updateService.js'; +import './services/url/electron-browser/urlService.js'; +import './services/lifecycle/electron-browser/lifecycleService.js'; +import './services/title/electron-browser/titleService.js'; +import './services/host/electron-browser/nativeHostService.js'; +import './services/request/electron-browser/requestService.js'; +import './services/clipboard/electron-browser/clipboardService.js'; +import './services/contextmenu/electron-browser/contextmenuService.js'; +import './services/workspaces/electron-browser/workspaceEditingService.js'; +import './services/configurationResolver/electron-browser/configurationResolverService.js'; +import './services/accessibility/electron-browser/accessibilityService.js'; +import './services/keybinding/electron-browser/nativeKeyboardLayout.js'; +import './services/path/electron-browser/pathService.js'; +import './services/themes/electron-browser/nativeHostColorSchemeService.js'; +import './services/extensionManagement/electron-browser/extensionManagementService.js'; +import './services/encryption/electron-browser/encryptionService.js'; +import './services/browserElements/electron-browser/browserElementsService.js'; +import './services/secrets/electron-browser/secretStorageService.js'; +import './services/localization/electron-browser/languagePackService.js'; +import './services/telemetry/electron-browser/telemetryService.js'; +import './services/extensions/electron-browser/extensionHostStarter.js'; import '../platform/extensionResourceLoader/common/extensionResourceLoaderService.js'; -import './services/localization/electron-sandbox/localeService.js'; -import './services/extensions/electron-sandbox/extensionsScannerService.js'; -import './services/extensionManagement/electron-sandbox/extensionManagementServerService.js'; -import './services/extensionManagement/electron-sandbox/extensionGalleryManifestService.js'; -import './services/extensionManagement/electron-sandbox/extensionTipsService.js'; -import './services/userDataSync/electron-sandbox/userDataSyncService.js'; -import './services/userDataSync/electron-sandbox/userDataAutoSyncService.js'; -import './services/timer/electron-sandbox/timerService.js'; -import './services/environment/electron-sandbox/shellEnvironmentService.js'; -import './services/integrity/electron-sandbox/integrityService.js'; -import './services/workingCopy/electron-sandbox/workingCopyBackupService.js'; -import './services/checksum/electron-sandbox/checksumService.js'; -import '../platform/remote/electron-sandbox/sharedProcessTunnelService.js'; -import './services/tunnel/electron-sandbox/tunnelService.js'; -import '../platform/diagnostics/electron-sandbox/diagnosticsService.js'; -import '../platform/profiling/electron-sandbox/profilingService.js'; -import '../platform/telemetry/electron-sandbox/customEndpointTelemetryService.js'; -import '../platform/remoteTunnel/electron-sandbox/remoteTunnelService.js'; -import './services/files/electron-sandbox/elevatedFileService.js'; -import './services/search/electron-sandbox/searchService.js'; -import './services/workingCopy/electron-sandbox/workingCopyHistoryService.js'; +import './services/localization/electron-browser/localeService.js'; +import './services/extensions/electron-browser/extensionsScannerService.js'; +import './services/extensionManagement/electron-browser/extensionManagementServerService.js'; +import './services/extensionManagement/electron-browser/extensionGalleryManifestService.js'; +import './services/extensionManagement/electron-browser/extensionTipsService.js'; +import './services/userDataSync/electron-browser/userDataSyncService.js'; +import './services/userDataSync/electron-browser/userDataAutoSyncService.js'; +import './services/timer/electron-browser/timerService.js'; +import './services/environment/electron-browser/shellEnvironmentService.js'; +import './services/integrity/electron-browser/integrityService.js'; +import './services/workingCopy/electron-browser/workingCopyBackupService.js'; +import './services/checksum/electron-browser/checksumService.js'; +import '../platform/remote/electron-browser/sharedProcessTunnelService.js'; +import './services/tunnel/electron-browser/tunnelService.js'; +import '../platform/diagnostics/electron-browser/diagnosticsService.js'; +import '../platform/profiling/electron-browser/profilingService.js'; +import '../platform/telemetry/electron-browser/customEndpointTelemetryService.js'; +import '../platform/remoteTunnel/electron-browser/remoteTunnelService.js'; +import './services/files/electron-browser/elevatedFileService.js'; +import './services/search/electron-browser/searchService.js'; +import './services/workingCopy/electron-browser/workingCopyHistoryService.js'; import './services/userDataSync/browser/userDataSyncEnablementService.js'; -import './services/extensions/electron-sandbox/nativeExtensionService.js'; -import '../platform/userDataProfile/electron-sandbox/userDataProfileStorageService.js'; -import './services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.js'; -import '../platform/extensionManagement/electron-sandbox/extensionsProfileScannerService.js'; -import '../platform/webContentExtractor/electron-sandbox/webContentExtractorService.js'; -import './services/process/electron-sandbox/processService.js'; +import './services/extensions/electron-browser/nativeExtensionService.js'; +import '../platform/userDataProfile/electron-browser/userDataProfileStorageService.js'; +import './services/auxiliaryWindow/electron-browser/auxiliaryWindowService.js'; +import '../platform/extensionManagement/electron-browser/extensionsProfileScannerService.js'; +import '../platform/webContentExtractor/electron-browser/webContentExtractorService.js'; +import './services/process/electron-browser/processService.js'; import { registerSingleton } from '../platform/instantiation/common/extensions.js'; import { IUserDataInitializationService, UserDataInitializationService } from './services/userData/browser/userDataInit.js'; @@ -102,84 +102,84 @@ registerSingleton(IUserDataInitializationService, new SyncDescriptor(UserDataIni //#region --- workbench contributions // Logs -import './contrib/logs/electron-sandbox/logs.contribution.js'; +import './contrib/logs/electron-browser/logs.contribution.js'; // Localizations -import './contrib/localization/electron-sandbox/localization.contribution.js'; +import './contrib/localization/electron-browser/localization.contribution.js'; // Explorer -import './contrib/files/electron-sandbox/fileActions.contribution.js'; +import './contrib/files/electron-browser/fileActions.contribution.js'; // CodeEditor Contributions -import './contrib/codeEditor/electron-sandbox/codeEditor.contribution.js'; +import './contrib/codeEditor/electron-browser/codeEditor.contribution.js'; // Debug -import './contrib/debug/electron-sandbox/extensionHostDebugService.js'; +import './contrib/debug/electron-browser/extensionHostDebugService.js'; // Extensions Management -import './contrib/extensions/electron-sandbox/extensions.contribution.js'; +import './contrib/extensions/electron-browser/extensions.contribution.js'; // Issues -import './contrib/issue/electron-sandbox/issue.contribution.js'; +import './contrib/issue/electron-browser/issue.contribution.js'; // Process Explorer -import './contrib/processExplorer/electron-sandbox/processExplorer.contribution.js'; +import './contrib/processExplorer/electron-browser/processExplorer.contribution.js'; // Remote -import './contrib/remote/electron-sandbox/remote.contribution.js'; +import './contrib/remote/electron-browser/remote.contribution.js'; // Terminal -import './contrib/terminal/electron-sandbox/terminal.contribution.js'; +import './contrib/terminal/electron-browser/terminal.contribution.js'; // Themes import './contrib/themes/browser/themes.test.contribution.js'; -import './services/themes/electron-sandbox/themes.contribution.js'; +import './services/themes/electron-browser/themes.contribution.js'; // User Data Sync -import './contrib/userDataSync/electron-sandbox/userDataSync.contribution.js'; +import './contrib/userDataSync/electron-browser/userDataSync.contribution.js'; // Tags -import './contrib/tags/electron-sandbox/workspaceTagsService.js'; -import './contrib/tags/electron-sandbox/tags.contribution.js'; +import './contrib/tags/electron-browser/workspaceTagsService.js'; +import './contrib/tags/electron-browser/tags.contribution.js'; // Performance -import './contrib/performance/electron-sandbox/performance.contribution.js'; +import './contrib/performance/electron-browser/performance.contribution.js'; // Tasks -import './contrib/tasks/electron-sandbox/taskService.js'; +import './contrib/tasks/electron-browser/taskService.js'; // External terminal -import './contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.js'; +import './contrib/externalTerminal/electron-browser/externalTerminal.contribution.js'; // Webview -import './contrib/webview/electron-sandbox/webview.contribution.js'; +import './contrib/webview/electron-browser/webview.contribution.js'; // Splash -import './contrib/splash/electron-sandbox/splash.contribution.js'; +import './contrib/splash/electron-browser/splash.contribution.js'; // Local History -import './contrib/localHistory/electron-sandbox/localHistory.contribution.js'; +import './contrib/localHistory/electron-browser/localHistory.contribution.js'; // Merge Editor -import './contrib/mergeEditor/electron-sandbox/mergeEditor.contribution.js'; +import './contrib/mergeEditor/electron-browser/mergeEditor.contribution.js'; // Multi Diff Editor import './contrib/multiDiffEditor/browser/multiDiffEditor.contribution.js'; // Remote Tunnel -import './contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.js'; +import './contrib/remoteTunnel/electron-browser/remoteTunnel.contribution.js'; // Chat -import './contrib/chat/electron-sandbox/chat.contribution.js'; -import './contrib/inlineChat/electron-sandbox/inlineChat.contribution.js'; +import './contrib/chat/electron-browser/chat.contribution.js'; +import './contrib/inlineChat/electron-browser/inlineChat.contribution.js'; // Encryption -import './contrib/encryption/electron-sandbox/encryption.contribution.js'; +import './contrib/encryption/electron-browser/encryption.contribution.js'; // Emergency Alert -import './contrib/emergencyAlert/electron-sandbox/emergencyAlert.contribution.js'; +import './contrib/emergencyAlert/electron-browser/emergencyAlert.contribution.js'; // MCP -import './contrib/mcp/electron-sandbox/mcp.contribution.js'; +import './contrib/mcp/electron-browser/mcp.contribution.js'; //#endregion -export { main } from './electron-sandbox/desktop.main.js'; +export { main } from './electron-browser/desktop.main.js'; diff --git a/test/unit/browser/index.js b/test/unit/browser/index.js index e5cf68ccab5..d112d64ea80 100644 --- a/test/unit/browser/index.js +++ b/test/unit/browser/index.js @@ -114,7 +114,7 @@ function ensureIsArray(a) { const testModules = (async function () { - const excludeGlob = '**/{node,electron-sandbox,electron-main,electron-utility}/**/*.test.js'; + const excludeGlob = '**/{node,electron-browser,electron-main,electron-utility}/**/*.test.js'; let isDefaultModules = true; let promise; diff --git a/test/unit/node/index.js b/test/unit/node/index.js index 36c2164dd98..4dc32d7a0cf 100644 --- a/test/unit/node/index.js +++ b/test/unit/node/index.js @@ -57,7 +57,7 @@ Options: const TEST_GLOB = '**/test/**/*.test.js'; const excludeGlobs = [ - '**/{browser,electron-sandbox,electron-main,electron-utility}/**/*.test.js', + '**/{browser,electron-browser,electron-main,electron-utility}/**/*.test.js', '**/vs/platform/environment/test/node/nativeModules.test.js', // native modules are compiled against Electron and this test would fail with node.js '**/vs/base/parts/storage/test/node/storage.test.js', // same as above, due to direct dependency to sqlite native module '**/vs/workbench/contrib/testing/test/**' // flaky (https://github.com/microsoft/vscode/issues/137853) From 42a3aa76630c11088e02063ced6277a8cb992fc3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Jun 2025 09:36:07 +0200 Subject: [PATCH 116/236] check tool specific enablement when reading tool set (#250983) fixes https://github.com/microsoft/vscode-copilot/issues/18161 --- .../contrib/chat/browser/chatSelectedTools.ts | 5 +- .../test/browser/chatSelectedTools.test.ts | 115 ++++++++++++++++++ 2 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/vs/workbench/contrib/chat/test/browser/chatSelectedTools.test.ts diff --git a/src/vs/workbench/contrib/chat/browser/chatSelectedTools.ts b/src/vs/workbench/contrib/chat/browser/chatSelectedTools.ts index 3b3d03913e6..f341a75c4c8 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSelectedTools.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSelectedTools.ts @@ -151,6 +151,7 @@ export class ChatSelectedTools extends Disposable { asEnablementMap(): Map { const result = new Map(); + const map = this.entriesMap; const _set = (tool: IToolData, enabled: boolean) => { // ONLY disable a tool that isn't enabled yet @@ -160,10 +161,10 @@ export class ChatSelectedTools extends Disposable { } }; - for (const [item, enabled] of this.entriesMap) { + for (const [item, enabled] of map) { if (item instanceof ToolSet) { for (const tool of item.getTools()) { - _set(tool, enabled); + _set(tool, map.get(tool) ?? enabled); // tools from tool set can be explicitly set } } else { if (item.canBeReferencedInPrompt) { diff --git a/src/vs/workbench/contrib/chat/test/browser/chatSelectedTools.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatSelectedTools.test.ts new file mode 100644 index 00000000000..43cf96af5ae --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/browser/chatSelectedTools.test.ts @@ -0,0 +1,115 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js'; +import { ContextKeyService } from '../../../../../platform/contextkey/browser/contextKeyService.js'; +import { workbenchInstantiationService } from '../../../../test/browser/workbenchTestServices.js'; +import { LanguageModelToolsService } from '../../browser/languageModelToolsService.js'; +import { IChatService } from '../../common/chatService.js'; +import { ILanguageModelToolsService, IToolData, ToolDataSource } from '../../common/languageModelToolsService.js'; +import { MockChatService } from '../common/mockChatService.js'; +import { ChatSelectedTools } from '../../browser/chatSelectedTools.js'; +import { constObservable } from '../../../../../base/common/observable.js'; +import { ChatMode } from '../../common/constants.js'; +import { Iterable } from '../../../../../base/common/iterator.js'; +import { DisposableStore } from '../../../../../base/common/lifecycle.js'; +import { runWithFakedTimers } from '../../../../../base/test/common/timeTravelScheduler.js'; +import { timeout } from '../../../../../base/common/async.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; + +suite('ChatSelectedTools', () => { + + let store: DisposableStore; + + let toolsService: ILanguageModelToolsService; + let selectedTools: ChatSelectedTools; + + setup(() => { + + store = new DisposableStore(); + + const instaService = workbenchInstantiationService({ + contextKeyService: () => store.add(new ContextKeyService(new TestConfigurationService)), + }, store); + instaService.stub(IChatService, new MockChatService()); + instaService.stub(ILanguageModelToolsService, instaService.createInstance(LanguageModelToolsService)); + + store.add(instaService); + toolsService = instaService.get(ILanguageModelToolsService); + selectedTools = store.add(instaService.createInstance(ChatSelectedTools, constObservable(ChatMode.Agent))); + }); + + teardown(function () { + store.dispose(); + }); + + ensureNoDisposablesAreLeakedInTestSuite(); + + test('Can\'t enable/disable MCP tools directly #18161', () => { + + return runWithFakedTimers({}, async () => { + + const toolData1: IToolData = { + id: 'testTool1', + modelDescription: 'Test Tool 1', + displayName: 'Test Tool 1', + canBeReferencedInPrompt: true, + toolReferenceName: 't1', + source: ToolDataSource.Internal, + }; + + const toolData2: IToolData = { + id: 'testTool2', + modelDescription: 'Test Tool 2', + displayName: 'Test Tool 2', + source: ToolDataSource.Internal, + canBeReferencedInPrompt: true, + toolReferenceName: 't2', + }; + + const toolData3: IToolData = { + id: 'testTool3', + modelDescription: 'Test Tool 3', + displayName: 'Test Tool 3', + source: ToolDataSource.Internal, + canBeReferencedInPrompt: true, + toolReferenceName: 't3', + }; + + const toolset = toolsService.createToolSet( + ToolDataSource.Internal, + 'mcp', 'mcp' + ); + + store.add(toolsService.registerToolData(toolData1)); + store.add(toolsService.registerToolData(toolData2)); + store.add(toolsService.registerToolData(toolData3)); + + store.add(toolset); + store.add(toolset.addTool(toolData1)); + store.add(toolset.addTool(toolData2)); + store.add(toolset.addTool(toolData3)); + + assert.strictEqual(Iterable.length(toolsService.getTools()), 3); + + const size = Iterable.length(toolset.getTools()); + assert.strictEqual(size, 3); + + await timeout(1000); // UGLY the tools service updates its state sync but emits the event async (750ms) delay. This affects the observable that depends on the event + + assert.strictEqual(selectedTools.entriesMap.size, 4); // 1 toolset, 3 tools + + selectedTools.disable([], [toolData2, toolData3], false); + + const map = selectedTools.asEnablementMap(); + assert.strictEqual(map.size, 3); // 3 tools + + assert.strictEqual(map.get(toolData1), true); + assert.strictEqual(map.get(toolData2), false); + assert.strictEqual(map.get(toolData3), false); + }); + }); +}); From 5e8f6f2bb4f5302e4c34c273a5d35a552c583fd6 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 9 Jun 2025 17:53:41 +0900 Subject: [PATCH 117/236] chore: use node-gyp from build dir for the project (#250981) * chore: bump node-gyp on windows to 11.2.0 improves reliability of builds on windows includes https://github.com/nodejs/node-gyp/pull/3113 and https://github.com/nodejs/node-gyp/pull/3112 * use preinstalled node-gyp * use bundled node-gyp for subdirs too * chore: revert changes to package-lock.json * chore: rebuild package-lock.json * ci: rebuild cache --------- Co-authored-by: Aman Karmani --- .npmrc | 1 + build/.cachesalt | 2 +- build/npm/gyp/package-lock.json | 520 +++++++++++++++----------------- build/npm/gyp/package.json | 2 +- build/npm/postinstall.js | 6 + 5 files changed, 245 insertions(+), 286 deletions(-) diff --git a/.npmrc b/.npmrc index 98fd4adc9e0..c92d74a4227 100644 --- a/.npmrc +++ b/.npmrc @@ -5,3 +5,4 @@ runtime="electron" build_from_source="true" legacy-peer-deps="true" timeout=180000 +npm_config_node_gyp="node build/npm/gyp/node_modules/node-gyp/bin/node-gyp.js" diff --git a/build/.cachesalt b/build/.cachesalt index 2d02e2ba768..a3213b850c3 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2025-05-14T16:33:46.494Z +2025-06-09T07:16:15.626Z diff --git a/build/npm/gyp/package-lock.json b/build/npm/gyp/package-lock.json index a20d85c70dc..08b6ae29b01 100644 --- a/build/npm/gyp/package-lock.json +++ b/build/npm/gyp/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "node-gyp": "^10.1.0" + "node-gyp": "^11.2.0" } }, "node_modules/@isaacs/cliui": { @@ -30,10 +30,23 @@ "node": ">=12" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@npmcli/agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", - "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", + "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", "dev": true, "license": "ISC", "dependencies": { @@ -44,20 +57,20 @@ "socks-proxy-agent": "^8.0.3" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/@npmcli/fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", "dev": true, "license": "ISC", "dependencies": { "semver": "^7.3.5" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/@pkgjs/parseargs": { @@ -72,46 +85,29 @@ } }, "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", "dev": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, "engines": { "node": ">= 14" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -152,13 +148,13 @@ } }, "node_modules/cacache": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", - "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", "dev": true, "license": "ISC", "dependencies": { - "@npmcli/fs": "^3.1.0", + "@npmcli/fs": "^4.0.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", @@ -166,33 +162,23 @@ "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=10" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "node": ">=18" } }, "node_modules/color-convert": { @@ -216,9 +202,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -254,13 +240,13 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -320,14 +306,29 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/fdir": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -351,9 +352,9 @@ } }, "node_modules/glob": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", - "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { @@ -367,9 +368,6 @@ "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -382,9 +380,9 @@ "license": "ISC" }, "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, "license": "BSD-2-Clause" }, @@ -403,13 +401,13 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { @@ -440,16 +438,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -474,13 +462,6 @@ "node": ">=8" } }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -492,17 +473,14 @@ } }, "node_modules/jackspeak": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", - "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -518,47 +496,33 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", - "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } + "license": "ISC" }, "node_modules/make-fetch-happen": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", "dev": true, "license": "ISC", "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", + "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "proc-log": "^4.2.0", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", "promise-retry": "^2.0.1", - "ssri": "^10.0.0" + "ssri": "^12.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/minimatch": { @@ -601,18 +565,18 @@ } }, "node_modules/minipass-fetch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", "dev": true, "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "minizlib": "^3.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" }, "optionalDependencies": { "encoding": "^0.1.13" @@ -644,6 +608,13 @@ "node": ">=8" } }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -670,6 +641,13 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", @@ -696,57 +674,53 @@ "node": ">=8" } }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "minipass": "^7.1.2" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": ">= 18" } }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, "license": "MIT", "bin": { - "mkdirp": "bin/cmd.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, "license": "MIT", "engines": { @@ -754,66 +728,63 @@ } }, "node_modules/node-gyp": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", - "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.2.0.tgz", + "integrity": "sha512-T0S1zqskVUSxcsSTkAsLc7xCycrRYmtDHadDinzocrThjyQCn5kMlEBSj6H4qDbgsIOSLmmlRIeb0lZXj+UArA==", "dev": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^3.0.0", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^4.0.0" + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "dev": true, "license": "ISC", "dependencies": { - "abbrev": "^2.0.0" + "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", "dev": true, "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, "license": "BlueOak-1.0.0" }, @@ -844,14 +815,27 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", "dev": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/promise-retry": { @@ -887,14 +871,11 @@ "optional": true }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -902,19 +883,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -963,9 +931,9 @@ } }, "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", "dev": true, "license": "MIT", "dependencies": { @@ -978,13 +946,13 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.1", + "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" }, @@ -1000,16 +968,16 @@ "license": "BSD-3-Clause" }, "node_modules/ssri": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/string-width": { @@ -1117,89 +1085,70 @@ } }, "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "dev": true, "license": "ISC", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "fdir": "^6.4.4", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" + "node": ">=12.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", "dev": true, "license": "ISC", "dependencies": { - "unique-slug": "^4.0.0" + "unique-slug": "^5.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, "license": "ISC", "dependencies": { @@ -1209,7 +1158,7 @@ "node-which": "bin/which.js" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/wrap-ansi": { @@ -1311,11 +1260,14 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, - "license": "ISC" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } } } } diff --git a/build/npm/gyp/package.json b/build/npm/gyp/package.json index a1564133a1e..2fee83064b6 100644 --- a/build/npm/gyp/package.json +++ b/build/npm/gyp/package.json @@ -4,7 +4,7 @@ "private": true, "license": "MIT", "devDependencies": { - "node-gyp": "^10.1.0" + "node-gyp": "^11.2.0" }, "scripts": {} } diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index be0c6c24282..1033e4ecf68 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -77,6 +77,12 @@ function setNpmrcConfig(dir, env) { } } + // Use our bundled node-gyp version + env['npm_config_node_gyp'] = + process.platform === 'win32' + ? path.join(__dirname, 'gyp', 'node_modules', '.bin', 'node-gyp.cmd') + : path.join(__dirname, 'gyp', 'node_modules', '.bin', 'node-gyp'); + // Force node-gyp to use process.config on macOS // which defines clang variable as expected. Otherwise we // run into compilation errors due to incorrect compiler From 5586bddae5bdc07fd41cf20f737a27c52ab5175e Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 14:36:36 +0200 Subject: [PATCH 118/236] fix some cyclic dependencies --- src/vs/base/browser/dom.ts | 355 +++++++++++++++- src/vs/base/browser/domImpl/domObservable.ts | 17 - src/vs/base/browser/domImpl/n.ts | 373 ----------------- src/vs/base/browser/domStylesheets.ts | 10 + src/vs/base/common/observableInternal/map.ts | 4 +- src/vs/base/common/observableInternal/set.ts | 4 +- src/vs/code/electron-main/main.ts | 3 +- .../browser/view/inlineCompletionsView.ts | 2 +- .../theme/electron-main/themeMainService.ts | 385 +---------------- .../electron-main/themeMainServiceImpl.ts | 393 ++++++++++++++++++ .../codecs/tokens/promptSlashCommand.ts | 10 - .../codecs/tokens/promptVariable.ts | 18 - .../tasks/browser/task.contribution.ts | 7 +- .../tasks/browser/terminalTaskSystem.ts | 3 +- .../workbench/contrib/tasks/common/tasks.ts | 4 + 15 files changed, 770 insertions(+), 818 deletions(-) delete mode 100644 src/vs/base/browser/domImpl/domObservable.ts delete mode 100644 src/vs/base/browser/domImpl/n.ts create mode 100644 src/vs/platform/theme/electron-main/themeMainServiceImpl.ts diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 553c584a63d..97f35ccc34f 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -8,7 +8,7 @@ import { BrowserFeatures } from './canIUse.js'; import { IKeyboardEvent, StandardKeyboardEvent } from './keyboardEvent.js'; import { IMouseEvent, StandardMouseEvent } from './mouseEvent.js'; import { AbstractIdleValue, IntervalTimer, TimeoutTimer, _runWhenIdle, IdleDeadline } from '../common/async.js'; -import { onUnexpectedError } from '../common/errors.js'; +import { BugIndicatingError, onUnexpectedError } from '../common/errors.js'; import * as event from '../common/event.js'; import dompurify from './dompurify/dompurify.js'; import { KeyCode } from '../common/keyCodes.js'; @@ -19,8 +19,7 @@ import { URI } from '../common/uri.js'; import { hash } from '../common/hash.js'; import { CodeWindow, ensureCodeWindow, mainWindow } from './window.js'; import { isPointWithinTriangle } from '../common/numbers.js'; -export * from './domImpl/domObservable.js'; -export * from './domImpl/n.js'; +import { IObservable, derived, derivedOpts, IReader, observableValue } from '../common/observable.js'; export interface IRegisteredCodeWindow { readonly window: CodeWindow; @@ -2395,3 +2394,353 @@ export class SafeTriangle { return false; } } + + +export namespace n { + function nodeNs>(elementNs: string | undefined = undefined): DomTagCreateFn { + return (tag, attributes, children) => { + const className = attributes.class; + delete attributes.class; + const ref = attributes.ref; + delete attributes.ref; + const obsRef = attributes.obsRef; + delete attributes.obsRef; + + return new ObserverNodeWithElement(tag as any, ref, obsRef, elementNs, className, attributes, children); + }; + } + + function node, TKey extends keyof TMap>(tag: TKey, elementNs: string | undefined = undefined): DomCreateFn { + const f = nodeNs(elementNs) as any; + return (attributes, children) => { + return f(tag, attributes, children); + }; + } + + export const div: DomCreateFn = node('div'); + + export const elem = nodeNs(undefined); + + export const svg: DomCreateFn = node('svg', 'http://www.w3.org/2000/svg'); + + export const svgElem = nodeNs('http://www.w3.org/2000/svg'); + + export function ref(): IRefWithVal { + let value: T | undefined = undefined; + const result: IRef = function (val: T) { + value = val; + }; + Object.defineProperty(result, 'element', { + get() { + if (!value) { + throw new BugIndicatingError('Make sure the ref is set before accessing the element. Maybe wrong initialization order?'); + } + return value; + } + }); + return result as any; + } +} +type Value = T | IObservable; +type ValueOrList = Value | ValueOrList[]; +type ValueOrList2 = ValueOrList | ValueOrList>; +type HTMLOrSVGElement = HTMLElement | SVGElement; +type SVGElementTagNameMap2 = { + svg: SVGElement & { + width: number; + height: number; + transform: string; + viewBox: string; + fill: string; + }; + path: SVGElement & { + d: string; + stroke: string; + fill: string; + }; + linearGradient: SVGElement & { + id: string; + x1: string | number; + x2: string | number; + }; + stop: SVGElement & { + offset: string; + }; + rect: SVGElement & { + x: number; + y: number; + width: number; + height: number; + fill: string; + }; + defs: SVGElement; +}; +type DomTagCreateFn> = ( + tag: TTag, + attributes: ElementAttributeKeys & { class?: ValueOrList; ref?: IRef; obsRef?: IRef | null> }, + children?: ChildNode +) => ObserverNode; +type DomCreateFn = ( + attributes: ElementAttributeKeys & { class?: ValueOrList; ref?: IRef; obsRef?: IRef | null> }, + children?: ChildNode +) => ObserverNode; + +export type ChildNode = ValueOrList2; + +export type IRef = (value: T) => void; + +export interface IRefWithVal extends IRef { + readonly element: T; +} + +export abstract class ObserverNode { + private readonly _deriveds: (IObservable)[] = []; + + protected readonly _element: T; + + constructor( + tag: string, + ref: IRef | undefined, + obsRef: IRef | null> | undefined, + ns: string | undefined, + className: ValueOrList | undefined, + attributes: ElementAttributeKeys, + children: ChildNode + ) { + this._element = (ns ? document.createElementNS(ns, tag) : document.createElement(tag)) as unknown as T; + if (ref) { + ref(this._element); + } + if (obsRef) { + this._deriveds.push(derived((_reader) => { + obsRef(this as unknown as ObserverNodeWithElement); + _reader.store.add({ + dispose: () => { + obsRef(null); + } + }); + })); + } + + if (className) { + if (hasObservable(className)) { + this._deriveds.push(derived(this, reader => { + /** @description set.class */ + setClassName(this._element, getClassName(className, reader)); + })); + } else { + setClassName(this._element, getClassName(className, undefined)); + } + } + + for (const [key, value] of Object.entries(attributes)) { + if (key === 'style') { + for (const [cssKey, cssValue] of Object.entries(value)) { + const key = camelCaseToHyphenCase(cssKey); + if (isObservable(cssValue)) { + this._deriveds.push(derivedOpts({ owner: this, debugName: () => `set.style.${key}` }, reader => { + this._element.style.setProperty(key, convertCssValue(cssValue.read(reader))); + })); + } else { + this._element.style.setProperty(key, convertCssValue(cssValue)); + } + } + } else if (key === 'tabIndex') { + if (isObservable(value)) { + this._deriveds.push(derived(this, reader => { + /** @description set.tabIndex */ + this._element.tabIndex = value.read(reader) as any; + })); + } else { + this._element.tabIndex = value; + } + } else if (key.startsWith('on')) { + (this._element as any)[key] = value; + } else { + if (isObservable(value)) { + this._deriveds.push(derivedOpts({ owner: this, debugName: () => `set.${key}` }, reader => { + setOrRemoveAttribute(this._element, key, value.read(reader)); + })); + } else { + setOrRemoveAttribute(this._element, key, value); + } + } + } + + if (children) { + function getChildren(reader: IReader | undefined, children: ValueOrList2): (HTMLOrSVGElement | string)[] { + if (isObservable(children)) { + return getChildren(reader, children.read(reader)); + } + if (Array.isArray(children)) { + return children.flatMap(c => getChildren(reader, c)); + } + if (children instanceof ObserverNode) { + if (reader) { + children.readEffect(reader); + } + return [children._element]; + } + if (children) { + return [children]; + } + return []; + } + + const d = derived(this, reader => { + /** @description set.children */ + this._element.replaceChildren(...getChildren(reader, children)); + }); + this._deriveds.push(d); + if (!childrenIsObservable(children)) { + d.get(); + } + } + } + + readEffect(reader: IReader | undefined): void { + for (const d of this._deriveds) { + d.read(reader); + } + } + + keepUpdated(store: DisposableStore): ObserverNodeWithElement { + derived(reader => { + /** update */ + this.readEffect(reader); + }).recomputeInitiallyAndOnChange(store); + return this as unknown as ObserverNodeWithElement; + } + + /** + * Creates a live element that will keep the element updated as long as the returned object is not disposed. + */ + toDisposableLiveElement() { + const store = new DisposableStore(); + this.keepUpdated(store); + return new LiveElement(this._element, store); + } +} +function setClassName(domNode: HTMLOrSVGElement, className: string) { + if (isSVGElement(domNode)) { + domNode.setAttribute('class', className); + } else { + domNode.className = className; + } +} +function resolve(value: ValueOrList, reader: IReader | undefined, cb: (val: T) => void): void { + if (isObservable(value)) { + cb(value.read(reader)); + return; + } + if (Array.isArray(value)) { + for (const v of value) { + resolve(v, reader, cb); + } + return; + } + cb(value as any); +} +function getClassName(className: ValueOrList | undefined, reader: IReader | undefined): string { + let result = ''; + resolve(className, reader, val => { + if (val) { + if (result.length === 0) { + result = val; + } else { + result += ' ' + val; + } + } + }); + return result; +} +function hasObservable(value: ValueOrList): boolean { + if (isObservable(value)) { + return true; + } + if (Array.isArray(value)) { + return value.some(v => hasObservable(v)); + } + return false; +} +function convertCssValue(value: any): string { + if (typeof value === 'number') { + return value + 'px'; + } + return value; +} +function childrenIsObservable(children: ValueOrList2): boolean { + if (isObservable(children)) { + return true; + } + if (Array.isArray(children)) { + return children.some(c => childrenIsObservable(c)); + } + return false; +} + +export class LiveElement { + constructor( + public readonly element: T, + private readonly _disposable: IDisposable + ) { } + + dispose() { + this._disposable.dispose(); + } +} + +export class ObserverNodeWithElement extends ObserverNode { + public get element() { + return this._element; + } + + private _isHovered: IObservable | undefined = undefined; + + get isHovered(): IObservable { + if (!this._isHovered) { + const hovered = observableValue('hovered', false); + this._element.addEventListener('mouseenter', (_e) => hovered.set(true, undefined)); + this._element.addEventListener('mouseleave', (_e) => hovered.set(false, undefined)); + this._isHovered = hovered; + } + return this._isHovered; + } + + private _didMouseMoveDuringHover: IObservable | undefined = undefined; + + get didMouseMoveDuringHover(): IObservable { + if (!this._didMouseMoveDuringHover) { + let _hovering = false; + const hovered = observableValue('didMouseMoveDuringHover', false); + this._element.addEventListener('mouseenter', (_e) => { + _hovering = true; + }); + this._element.addEventListener('mousemove', (_e) => { + if (_hovering) { + hovered.set(true, undefined); + } + }); + this._element.addEventListener('mouseleave', (_e) => { + _hovering = false; + hovered.set(false, undefined); + }); + this._didMouseMoveDuringHover = hovered; + } + return this._didMouseMoveDuringHover; + } +} +function setOrRemoveAttribute(element: HTMLOrSVGElement, key: string, value: unknown) { + if (value === null || value === undefined) { + element.removeAttribute(camelCaseToHyphenCase(key)); + } else { + element.setAttribute(camelCaseToHyphenCase(key), String(value)); + } +} + +function isObservable(obj: unknown): obj is IObservable { + return !!obj && (>obj).read !== undefined && (>obj).reportChanges !== undefined; +} +type ElementAttributeKeys = Partial<{ + [K in keyof T]: T[K] extends Function ? never : T[K] extends object ? ElementAttributeKeys : Value; +}>; diff --git a/src/vs/base/browser/domImpl/domObservable.ts b/src/vs/base/browser/domImpl/domObservable.ts deleted file mode 100644 index c66a031de67..00000000000 --- a/src/vs/base/browser/domImpl/domObservable.ts +++ /dev/null @@ -1,17 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { DisposableStore, IDisposable } from '../../common/lifecycle.js'; -import { autorun, IObservable } from '../../common/observable.js'; -import { createStyleSheet2 } from '../domStylesheets.js'; - -export function createStyleSheetFromObservable(css: IObservable): IDisposable { - const store = new DisposableStore(); - const w = store.add(createStyleSheet2()); - store.add(autorun(reader => { - w.setStyle(css.read(reader)); - })); - return store; -} diff --git a/src/vs/base/browser/domImpl/n.ts b/src/vs/base/browser/domImpl/n.ts deleted file mode 100644 index a3c7653a51c..00000000000 --- a/src/vs/base/browser/domImpl/n.ts +++ /dev/null @@ -1,373 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { BugIndicatingError } from '../../common/errors.js'; -import { DisposableStore, IDisposable } from '../../common/lifecycle.js'; -import { derived, derivedOpts, IObservable, IReader, observableValue } from '../../common/observable.js'; -import { isSVGElement } from '../dom.js'; - -export namespace n { - function nodeNs>(elementNs: string | undefined = undefined): DomTagCreateFn { - return (tag, attributes, children) => { - const className = attributes.class; - delete attributes.class; - const ref = attributes.ref; - delete attributes.ref; - const obsRef = attributes.obsRef; - delete attributes.obsRef; - - return new ObserverNodeWithElement(tag as any, ref, obsRef, elementNs, className, attributes, children); - }; - } - - function node, TKey extends keyof TMap>(tag: TKey, elementNs: string | undefined = undefined): DomCreateFn { - const f = nodeNs(elementNs) as any; - return (attributes, children) => { - return f(tag, attributes, children); - }; - } - - export const div: DomCreateFn = node('div'); - - export const elem = nodeNs(undefined); - - export const svg: DomCreateFn = node('svg', 'http://www.w3.org/2000/svg'); - - export const svgElem = nodeNs('http://www.w3.org/2000/svg'); - - export function ref(): IRefWithVal { - let value: T | undefined = undefined; - const result: IRef = function (val: T) { - value = val; - }; - Object.defineProperty(result, 'element', { - get() { - if (!value) { - throw new BugIndicatingError('Make sure the ref is set before accessing the element. Maybe wrong initialization order?'); - } - return value; - } - }); - return result as any; - } -} - -type Value = T | IObservable; -type ValueOrList = Value | ValueOrList[]; -type ValueOrList2 = ValueOrList | ValueOrList>; -type Element = HTMLElement | SVGElement; -type SVGElementTagNameMap2 = { - svg: SVGElement & { - width: number; - height: number; - transform: string; - viewBox: string; - fill: string; - }; - path: SVGElement & { - d: string; - stroke: string; - fill: string; - }; - linearGradient: SVGElement & { - id: string; - x1: string | number; - x2: string | number; - }; - stop: SVGElement & { - offset: string; - }; - rect: SVGElement & { - x: number; - y: number; - width: number; - height: number; - fill: string; - }; - defs: SVGElement; -}; - -type DomTagCreateFn> = ( - tag: TTag, - attributes: ElementAttributeKeys & { class?: ValueOrList; ref?: IRef; obsRef?: IRef | null> }, - children?: ChildNode -) => ObserverNode; - -type DomCreateFn = ( - attributes: ElementAttributeKeys & { class?: ValueOrList; ref?: IRef; obsRef?: IRef | null> }, - children?: ChildNode -) => ObserverNode; - -export type ChildNode = ValueOrList2; - -export type IRef = (value: T) => void; - -export interface IRefWithVal extends IRef { - readonly element: T; -} - -export abstract class ObserverNode { - private readonly _deriveds: (IObservable)[] = []; - - protected readonly _element: T; - - constructor( - tag: string, - ref: IRef | undefined, - obsRef: IRef | null> | undefined, - ns: string | undefined, - className: ValueOrList | undefined, - attributes: ElementAttributeKeys, - children: ChildNode - ) { - this._element = (ns ? document.createElementNS(ns, tag) : document.createElement(tag)) as unknown as T; - if (ref) { - ref(this._element); - } - if (obsRef) { - this._deriveds.push(derived((_reader) => { - obsRef(this as unknown as ObserverNodeWithElement); - _reader.store.add({ - dispose: () => { - obsRef(null); - } - }); - })); - } - - if (className) { - if (hasObservable(className)) { - this._deriveds.push(derived(this, reader => { - /** @description set.class */ - setClassName(this._element, getClassName(className, reader)); - })); - } else { - setClassName(this._element, getClassName(className, undefined)); - } - } - - for (const [key, value] of Object.entries(attributes)) { - if (key === 'style') { - for (const [cssKey, cssValue] of Object.entries(value)) { - const key = camelCaseToHyphenCase(cssKey); - if (isObservable(cssValue)) { - this._deriveds.push(derivedOpts({ owner: this, debugName: () => `set.style.${key}` }, reader => { - this._element.style.setProperty(key, convertCssValue(cssValue.read(reader))); - })); - } else { - this._element.style.setProperty(key, convertCssValue(cssValue)); - } - } - } else if (key === 'tabIndex') { - if (isObservable(value)) { - this._deriveds.push(derived(this, reader => { - /** @description set.tabIndex */ - this._element.tabIndex = value.read(reader) as any; - })); - } else { - this._element.tabIndex = value; - } - } else if (key.startsWith('on')) { - (this._element as any)[key] = value; - } else { - if (isObservable(value)) { - this._deriveds.push(derivedOpts({ owner: this, debugName: () => `set.${key}` }, reader => { - setOrRemoveAttribute(this._element, key, value.read(reader)); - })); - } else { - setOrRemoveAttribute(this._element, key, value); - } - } - } - - if (children) { - function getChildren(reader: IReader | undefined, children: ValueOrList2): (Element | string)[] { - if (isObservable(children)) { - return getChildren(reader, children.read(reader)); - } - if (Array.isArray(children)) { - return children.flatMap(c => getChildren(reader, c)); - } - if (children instanceof ObserverNode) { - if (reader) { - children.readEffect(reader); - } - return [children._element]; - } - if (children) { - return [children]; - } - return []; - } - - const d = derived(this, reader => { - /** @description set.children */ - this._element.replaceChildren(...getChildren(reader, children)); - }); - this._deriveds.push(d); - if (!childrenIsObservable(children)) { - d.get(); - } - } - } - - readEffect(reader: IReader | undefined): void { - for (const d of this._deriveds) { - d.read(reader); - } - } - - keepUpdated(store: DisposableStore): ObserverNodeWithElement { - derived(reader => { - /** update */ - this.readEffect(reader); - }).recomputeInitiallyAndOnChange(store); - return this as unknown as ObserverNodeWithElement; - } - - /** - * Creates a live element that will keep the element updated as long as the returned object is not disposed. - */ - toDisposableLiveElement() { - const store = new DisposableStore(); - this.keepUpdated(store); - return new LiveElement(this._element, store); - } -} - -function setClassName(domNode: Element, className: string) { - if (isSVGElement(domNode)) { - domNode.setAttribute('class', className); - } else { - domNode.className = className; - } -} - -function resolve(value: ValueOrList, reader: IReader | undefined, cb: (val: T) => void): void { - if (isObservable(value)) { - cb(value.read(reader)); - return; - } - if (Array.isArray(value)) { - for (const v of value) { - resolve(v, reader, cb); - } - return; - } - cb(value as any); -} - -function getClassName(className: ValueOrList | undefined, reader: IReader | undefined): string { - let result = ''; - resolve(className, reader, val => { - if (val) { - if (result.length === 0) { - result = val; - } else { - result += ' ' + val; - } - } - }); - return result; -} - -function hasObservable(value: ValueOrList): boolean { - if (isObservable(value)) { - return true; - } - if (Array.isArray(value)) { - return value.some(v => hasObservable(v)); - } - return false; -} - -function convertCssValue(value: any): string { - if (typeof value === 'number') { - return value + 'px'; - } - return value; -} - -function childrenIsObservable(children: ValueOrList2): boolean { - if (isObservable(children)) { - return true; - } - if (Array.isArray(children)) { - return children.some(c => childrenIsObservable(c)); - } - return false; -} - -export class LiveElement { - constructor( - public readonly element: T, - private readonly _disposable: IDisposable - ) { } - - dispose() { - this._disposable.dispose(); - } -} - -export class ObserverNodeWithElement extends ObserverNode { - public get element() { - return this._element; - } - - private _isHovered: IObservable | undefined = undefined; - - get isHovered(): IObservable { - if (!this._isHovered) { - const hovered = observableValue('hovered', false); - this._element.addEventListener('mouseenter', (_e) => hovered.set(true, undefined)); - this._element.addEventListener('mouseleave', (_e) => hovered.set(false, undefined)); - this._isHovered = hovered; - } - return this._isHovered; - } - - private _didMouseMoveDuringHover: IObservable | undefined = undefined; - - get didMouseMoveDuringHover(): IObservable { - if (!this._didMouseMoveDuringHover) { - let _hovering = false; - const hovered = observableValue('didMouseMoveDuringHover', false); - this._element.addEventListener('mouseenter', (_e) => { - _hovering = true; - }); - this._element.addEventListener('mousemove', (_e) => { - if (_hovering) { - hovered.set(true, undefined); - } - }); - this._element.addEventListener('mouseleave', (_e) => { - _hovering = false; - hovered.set(false, undefined); - }); - this._didMouseMoveDuringHover = hovered; - } - return this._didMouseMoveDuringHover; - } -} - -function setOrRemoveAttribute(element: Element, key: string, value: unknown) { - if (value === null || value === undefined) { - element.removeAttribute(camelCaseToHyphenCase(key)); - } else { - element.setAttribute(camelCaseToHyphenCase(key), String(value)); - } -} - -function camelCaseToHyphenCase(str: string) { - return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); -} - -function isObservable(obj: unknown): obj is IObservable { - return !!obj && (>obj).read !== undefined && (>obj).reportChanges !== undefined; -} - -type ElementAttributeKeys = Partial<{ - [K in keyof T]: T[K] extends Function ? never : T[K] extends object ? ElementAttributeKeys : Value; -}>; diff --git a/src/vs/base/browser/domStylesheets.ts b/src/vs/base/browser/domStylesheets.ts index ebc249c6608..76a71c5402d 100644 --- a/src/vs/base/browser/domStylesheets.ts +++ b/src/vs/base/browser/domStylesheets.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { DisposableStore, toDisposable, IDisposable } from '../common/lifecycle.js'; +import { autorun, IObservable } from '../common/observable.js'; import { getWindows, sharedMutationObserver } from './dom.js'; import { mainWindow } from './window.js'; @@ -166,3 +167,12 @@ export function removeCSSRulesContainingSelector(ruleName: string, style = getSh function isCSSStyleRule(rule: CSSRule): rule is CSSStyleRule { return typeof (rule as CSSStyleRule).selectorText === 'string'; } + +export function createStyleSheetFromObservable(css: IObservable): IDisposable { + const store = new DisposableStore(); + const w = store.add(createStyleSheet2()); + store.add(autorun(reader => { + w.setStyle(css.read(reader)); + })); + return store; +} diff --git a/src/vs/base/common/observableInternal/map.ts b/src/vs/base/common/observableInternal/map.ts index 9959bd1a1e5..1db8c9ebb26 100644 --- a/src/vs/base/common/observableInternal/map.ts +++ b/src/vs/base/common/observableInternal/map.ts @@ -3,7 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { observableValueOpts, IObservable, ITransaction } from '../observable.js'; +import { IObservable, ITransaction } from '../observable.js'; +import { observableValueOpts } from './observables/observableValueOpts.js'; + export class ObservableMap implements Map { private readonly _data = new Map(); diff --git a/src/vs/base/common/observableInternal/set.ts b/src/vs/base/common/observableInternal/set.ts index 10a624dcbaa..294cdc73ca4 100644 --- a/src/vs/base/common/observableInternal/set.ts +++ b/src/vs/base/common/observableInternal/set.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { observableValueOpts, IObservable, ITransaction } from '../observable.js'; - +import { IObservable, ITransaction } from '../observable.js'; +import { observableValueOpts } from './observables/observableValueOpts.js'; export class ObservableSet implements Set { diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index d5e39554d43..ce0cce592e4 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -58,7 +58,7 @@ import { ISignService } from '../../platform/sign/common/sign.js'; import { SignService } from '../../platform/sign/node/signService.js'; import { IStateReadService, IStateService } from '../../platform/state/node/state.js'; import { NullTelemetryService } from '../../platform/telemetry/common/telemetryUtils.js'; -import { IThemeMainService, ThemeMainService } from '../../platform/theme/electron-main/themeMainService.js'; +import { IThemeMainService } from '../../platform/theme/electron-main/themeMainService.js'; import { IUserDataProfilesMainService, UserDataProfilesMainService } from '../../platform/userDataProfile/electron-main/userDataProfile.js'; import { IPolicyService, NullPolicyService } from '../../platform/policy/common/policy.js'; import { NativePolicyService } from '../../platform/policy/node/nativePolicyService.js'; @@ -72,6 +72,7 @@ import { massageMessageBoxOptions } from '../../platform/dialogs/common/dialogs. import { SaveStrategy, StateService } from '../../platform/state/node/stateService.js'; import { FileUserDataProvider } from '../../platform/userData/common/fileUserDataProvider.js'; import { addUNCHostToAllowlist, getUNCHost } from '../../base/node/unc.js'; +import { ThemeMainService } from '../../platform/theme/electron-main/themeMainServiceImpl.js'; /** * The main VS Code entry point. diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts index 0aca2fe89e5..f487e2a5bcd 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createStyleSheetFromObservable } from '../../../../../base/browser/dom.js'; +import { createStyleSheetFromObservable } from '../../../../../base/browser/domStylesheets.js'; import { Disposable } from '../../../../../base/common/lifecycle.js'; import { derived, mapObservableArrayCached, derivedDisposable, constObservable, derivedObservableWithCache, IObservable, ISettableObservable } from '../../../../../base/common/observable.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; diff --git a/src/vs/platform/theme/electron-main/themeMainService.ts b/src/vs/platform/theme/electron-main/themeMainService.ts index d530126a31a..531fc6171e6 100644 --- a/src/vs/platform/theme/electron-main/themeMainService.ts +++ b/src/vs/platform/theme/electron-main/themeMainService.ts @@ -3,57 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import electron from 'electron'; -import { Emitter, Event } from '../../../base/common/event.js'; -import { Disposable } from '../../../base/common/lifecycle.js'; -import { isLinux, isMacintosh, isWindows } from '../../../base/common/platform.js'; -import { IConfigurationService } from '../../configuration/common/configuration.js'; +import { Event } from '../../../base/common/event.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; -import { IStateService } from '../../state/node/state.js'; import { IPartsSplash } from '../common/themeService.js'; import { IColorScheme } from '../../window/common/window.js'; -import { ThemeTypeSelector } from '../common/theme.js'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from '../../workspace/common/workspace.js'; -import { coalesce } from '../../../base/common/arrays.js'; -import { getAllWindowsExcludingOffscreen } from '../../windows/electron-main/windows.js'; -import { ILogService } from '../../log/common/log.js'; - -// These default colors match our default themes -// editor background color ("Dark Modern", etc...) -const DEFAULT_BG_LIGHT = '#FFFFFF'; -const DEFAULT_BG_DARK = '#1F1F1F'; -const DEFAULT_BG_HC_BLACK = '#000000'; -const DEFAULT_BG_HC_LIGHT = '#FFFFFF'; - -const THEME_STORAGE_KEY = 'theme'; -const THEME_BG_STORAGE_KEY = 'themeBackground'; - -const THEME_WINDOW_SPLASH_KEY = 'windowSplash'; -const THEME_WINDOW_SPLASH_OVERRIDE_KEY = 'windowSplashWorkspaceOverride'; - -const AUXILIARYBAR_DEFAULT_VISIBILITY = 'workbench.secondarySideBar.defaultVisibility'; - -namespace ThemeSettings { - export const DETECT_COLOR_SCHEME = 'window.autoDetectColorScheme'; - export const DETECT_HC = 'window.autoDetectHighContrast'; - export const SYSTEM_COLOR_THEME = 'window.systemColorTheme'; -} - -interface IPartSplashOverrideWorkspaces { - [workspaceId: string]: { - sideBarVisible: boolean; - auxiliaryBarVisible: boolean; - }; -} - -interface IPartsSplashOverride { - layoutInfo: { - sideBarWidth: number; - auxiliaryBarWidth: number; - - workspaces: IPartSplashOverrideWorkspaces; - }; -} export const IThemeMainService = createDecorator('themeMainService'); @@ -70,340 +24,3 @@ export interface IThemeMainService { getColorScheme(): IColorScheme; } - -export class ThemeMainService extends Disposable implements IThemeMainService { - - declare readonly _serviceBrand: undefined; - - private static readonly DEFAULT_BAR_WIDTH = 300; - - private static readonly WORKSPACE_OVERRIDE_LIMIT = 50; - - private readonly _onDidChangeColorScheme = this._register(new Emitter()); - readonly onDidChangeColorScheme = this._onDidChangeColorScheme.event; - - constructor( - @IStateService private stateService: IStateService, - @IConfigurationService private configurationService: IConfigurationService, - @ILogService private logService: ILogService - ) { - super(); - - // System Theme - if (!isLinux) { - this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration(ThemeSettings.SYSTEM_COLOR_THEME) || e.affectsConfiguration(ThemeSettings.DETECT_COLOR_SCHEME)) { - this.updateSystemColorTheme(); - } - })); - } - this.updateSystemColorTheme(); - - // Color Scheme changes - this._register(Event.fromNodeEventEmitter(electron.nativeTheme, 'updated')(() => this._onDidChangeColorScheme.fire(this.getColorScheme()))); - } - - private updateSystemColorTheme(): void { - if (isLinux || this.configurationService.getValue(ThemeSettings.DETECT_COLOR_SCHEME)) { - electron.nativeTheme.themeSource = 'system'; // only with `system` we can detect the system color scheme - } else { - switch (this.configurationService.getValue<'default' | 'auto' | 'light' | 'dark'>(ThemeSettings.SYSTEM_COLOR_THEME)) { - case 'dark': - electron.nativeTheme.themeSource = 'dark'; - break; - case 'light': - electron.nativeTheme.themeSource = 'light'; - break; - case 'auto': - switch (this.getPreferredBaseTheme() ?? this.getStoredBaseTheme()) { - case ThemeTypeSelector.VS: electron.nativeTheme.themeSource = 'light'; break; - case ThemeTypeSelector.VS_DARK: electron.nativeTheme.themeSource = 'dark'; break; - default: electron.nativeTheme.themeSource = 'system'; - } - break; - default: - electron.nativeTheme.themeSource = 'system'; - break; - } - } - } - - getColorScheme(): IColorScheme { - - // high contrast is reflected by the shouldUseInvertedColorScheme property - if (isWindows) { - if (electron.nativeTheme.shouldUseHighContrastColors) { - // shouldUseInvertedColorScheme is dark, !shouldUseInvertedColorScheme is light - return { dark: electron.nativeTheme.shouldUseInvertedColorScheme, highContrast: true }; - } - } - - // high contrast is set if one of shouldUseInvertedColorScheme or shouldUseHighContrastColors is set, - // reflecting the 'Invert colours' and `Increase contrast` settings in MacOS - else if (isMacintosh) { - if (electron.nativeTheme.shouldUseInvertedColorScheme || electron.nativeTheme.shouldUseHighContrastColors) { - return { dark: electron.nativeTheme.shouldUseDarkColors, highContrast: true }; - } - } - - // ubuntu gnome seems to have 3 states, light dark and high contrast - else if (isLinux) { - if (electron.nativeTheme.shouldUseHighContrastColors) { - return { dark: true, highContrast: true }; - } - } - - return { - dark: electron.nativeTheme.shouldUseDarkColors, - highContrast: false - }; - } - - getPreferredBaseTheme(): ThemeTypeSelector | undefined { - const colorScheme = this.getColorScheme(); - if (this.configurationService.getValue(ThemeSettings.DETECT_HC) && colorScheme.highContrast) { - return colorScheme.dark ? ThemeTypeSelector.HC_BLACK : ThemeTypeSelector.HC_LIGHT; - } - - if (this.configurationService.getValue(ThemeSettings.DETECT_COLOR_SCHEME)) { - return colorScheme.dark ? ThemeTypeSelector.VS_DARK : ThemeTypeSelector.VS; - } - - return undefined; - } - - getBackgroundColor(): string { - const preferred = this.getPreferredBaseTheme(); - const stored = this.getStoredBaseTheme(); - - // If the stored theme has the same base as the preferred, we can return the stored background - if (preferred === undefined || preferred === stored) { - const storedBackground = this.stateService.getItem(THEME_BG_STORAGE_KEY, null); - if (storedBackground) { - return storedBackground; - } - } - - // Otherwise we return the default background for the preferred base theme. If there's no preferred, use the stored one. - switch (preferred ?? stored) { - case ThemeTypeSelector.VS: return DEFAULT_BG_LIGHT; - case ThemeTypeSelector.HC_BLACK: return DEFAULT_BG_HC_BLACK; - case ThemeTypeSelector.HC_LIGHT: return DEFAULT_BG_HC_LIGHT; - default: return DEFAULT_BG_DARK; - } - } - - private getStoredBaseTheme(): ThemeTypeSelector { - const baseTheme = this.stateService.getItem(THEME_STORAGE_KEY, ThemeTypeSelector.VS_DARK).split(' ')[0]; - switch (baseTheme) { - case ThemeTypeSelector.VS: return ThemeTypeSelector.VS; - case ThemeTypeSelector.HC_BLACK: return ThemeTypeSelector.HC_BLACK; - case ThemeTypeSelector.HC_LIGHT: return ThemeTypeSelector.HC_LIGHT; - default: return ThemeTypeSelector.VS_DARK; - } - } - - saveWindowSplash(windowId: number | undefined, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined, splash: IPartsSplash): void { - - // Update override as needed - const splashOverride = this.updateWindowSplashOverride(workspace, splash); - - // Update in storage - this.stateService.setItems(coalesce([ - { key: THEME_STORAGE_KEY, data: splash.baseTheme }, - { key: THEME_BG_STORAGE_KEY, data: splash.colorInfo.background }, - { key: THEME_WINDOW_SPLASH_KEY, data: splash }, - splashOverride ? { key: THEME_WINDOW_SPLASH_OVERRIDE_KEY, data: splashOverride } : undefined - ])); - - // Update in opened windows - if (typeof windowId === 'number') { - this.updateBackgroundColor(windowId, splash); - } - - // Update system theme - this.updateSystemColorTheme(); - } - - private updateWindowSplashOverride(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined, splash: IPartsSplash): IPartsSplashOverride | undefined { - let splashOverride: IPartsSplashOverride | undefined = undefined; - let changed = false; - if (workspace) { - splashOverride = { ...this.getWindowSplashOverride() }; // make a copy for modifications - - changed = this.doUpdateWindowSplashOverride(workspace, splash, splashOverride, 'sideBar'); - changed = this.doUpdateWindowSplashOverride(workspace, splash, splashOverride, 'auxiliaryBar') || changed; - } - - return changed ? splashOverride : undefined; - } - - private doUpdateWindowSplashOverride(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier, splash: IPartsSplash, splashOverride: IPartsSplashOverride, part: 'sideBar' | 'auxiliaryBar'): boolean { - const currentWidth = part === 'sideBar' ? splash.layoutInfo?.sideBarWidth : splash.layoutInfo?.auxiliarySideBarWidth; - const overrideWidth = part === 'sideBar' ? splashOverride.layoutInfo.sideBarWidth : splashOverride.layoutInfo.auxiliaryBarWidth; - - // No layout info: remove override - let changed = false; - if (typeof currentWidth !== 'number') { - if (splashOverride.layoutInfo.workspaces[workspace.id]) { - delete splashOverride.layoutInfo.workspaces[workspace.id]; - changed = true; - } - - return changed; - } - - let workspaceOverride = splashOverride.layoutInfo.workspaces[workspace.id]; - if (!workspaceOverride) { - const workspaceEntries = Object.keys(splashOverride.layoutInfo.workspaces); - if (workspaceEntries.length >= ThemeMainService.WORKSPACE_OVERRIDE_LIMIT) { - delete splashOverride.layoutInfo.workspaces[workspaceEntries[0]]; - changed = true; - } - - workspaceOverride = { sideBarVisible: false, auxiliaryBarVisible: false }; - splashOverride.layoutInfo.workspaces[workspace.id] = workspaceOverride; - changed = true; - } - - // Part has width: update width & visibility override - if (currentWidth > 0) { - if (overrideWidth !== currentWidth) { - splashOverride.layoutInfo[part === 'sideBar' ? 'sideBarWidth' : 'auxiliaryBarWidth'] = currentWidth; - changed = true; - } - - switch (part) { - case 'sideBar': - if (!workspaceOverride.sideBarVisible) { - workspaceOverride.sideBarVisible = true; - changed = true; - } - break; - case 'auxiliaryBar': - if (!workspaceOverride.auxiliaryBarVisible) { - workspaceOverride.auxiliaryBarVisible = true; - changed = true; - } - break; - } - } - - // Part is hidden: update visibility override - else { - switch (part) { - case 'sideBar': - if (workspaceOverride.sideBarVisible) { - workspaceOverride.sideBarVisible = false; - changed = true; - } - break; - case 'auxiliaryBar': - if (workspaceOverride.auxiliaryBarVisible) { - workspaceOverride.auxiliaryBarVisible = false; - changed = true; - } - break; - } - } - - return changed; - } - - private updateBackgroundColor(windowId: number, splash: IPartsSplash): void { - for (const window of getAllWindowsExcludingOffscreen()) { - if (window.id === windowId) { - window.setBackgroundColor(splash.colorInfo.background); - break; - } - } - } - - getWindowSplash(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): IPartsSplash | undefined { - try { - return this.doGetWindowSplash(workspace); - } catch (error) { - this.logService.error('[theme main service] Failed to get window splash', error); - - return undefined; - } - } - - private doGetWindowSplash(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): IPartsSplash | undefined { - const partSplash = this.stateService.getItem(THEME_WINDOW_SPLASH_KEY); - if (!partSplash?.layoutInfo) { - return partSplash; // return early: overrides currently only apply to layout info - } - - const override = this.getWindowSplashOverride(); - - // Figure out side bar width based on workspace and overrides - let sideBarWidth: number; - if (workspace) { - if (override.layoutInfo.workspaces[workspace.id]?.sideBarVisible === false) { - sideBarWidth = 0; - } else { - sideBarWidth = override.layoutInfo.sideBarWidth || partSplash.layoutInfo.sideBarWidth || ThemeMainService.DEFAULT_BAR_WIDTH; - } - } else { - sideBarWidth = 0; - } - - // Figure out auxiliary bar width based on workspace, configuration and overrides - const auxiliarySideBarDefaultVisibility = this.configurationService.getValue(AUXILIARYBAR_DEFAULT_VISIBILITY); - let auxiliarySideBarWidth: number; - if (workspace) { - const auxiliaryBarVisible = override.layoutInfo.workspaces[workspace.id]?.auxiliaryBarVisible; - if (auxiliaryBarVisible === true) { - auxiliarySideBarWidth = override.layoutInfo.auxiliaryBarWidth || partSplash.layoutInfo.auxiliarySideBarWidth || ThemeMainService.DEFAULT_BAR_WIDTH; - } else if (auxiliaryBarVisible === false) { - auxiliarySideBarWidth = 0; - } else { - if (auxiliarySideBarDefaultVisibility === 'visible' || auxiliarySideBarDefaultVisibility === 'visibleInWorkspace') { - auxiliarySideBarWidth = override.layoutInfo.auxiliaryBarWidth || partSplash.layoutInfo.auxiliarySideBarWidth || ThemeMainService.DEFAULT_BAR_WIDTH; - } else { - auxiliarySideBarWidth = 0; - } - } - } else { - auxiliarySideBarWidth = 0; // technically not true if configured 'visible', but we never store splash per empty window, so we decide on a default here - } - - return { - ...partSplash, - layoutInfo: { - ...partSplash.layoutInfo, - sideBarWidth, - auxiliarySideBarWidth - } - }; - } - - private getWindowSplashOverride(): IPartsSplashOverride { - let override = this.stateService.getItem(THEME_WINDOW_SPLASH_OVERRIDE_KEY); - - if (!override?.layoutInfo) { - override = { - layoutInfo: { - sideBarWidth: ThemeMainService.DEFAULT_BAR_WIDTH, - auxiliaryBarWidth: ThemeMainService.DEFAULT_BAR_WIDTH, - workspaces: {} - } - }; - } - - if (!override.layoutInfo.sideBarWidth) { - override.layoutInfo.sideBarWidth = ThemeMainService.DEFAULT_BAR_WIDTH; - } - - if (!override.layoutInfo.auxiliaryBarWidth) { - override.layoutInfo.auxiliaryBarWidth = ThemeMainService.DEFAULT_BAR_WIDTH; - } - - if (!override.layoutInfo.workspaces) { - override.layoutInfo.workspaces = {}; - } - - return override; - } -} diff --git a/src/vs/platform/theme/electron-main/themeMainServiceImpl.ts b/src/vs/platform/theme/electron-main/themeMainServiceImpl.ts new file mode 100644 index 00000000000..a888ae35bf1 --- /dev/null +++ b/src/vs/platform/theme/electron-main/themeMainServiceImpl.ts @@ -0,0 +1,393 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import electron from 'electron'; +import { Emitter, Event } from '../../../base/common/event.js'; +import { Disposable } from '../../../base/common/lifecycle.js'; +import { isLinux, isMacintosh, isWindows } from '../../../base/common/platform.js'; +import { IConfigurationService } from '../../configuration/common/configuration.js'; +import { IStateService } from '../../state/node/state.js'; +import { IPartsSplash } from '../common/themeService.js'; +import { IColorScheme } from '../../window/common/window.js'; +import { ThemeTypeSelector } from '../common/theme.js'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from '../../workspace/common/workspace.js'; +import { coalesce } from '../../../base/common/arrays.js'; +import { getAllWindowsExcludingOffscreen } from '../../windows/electron-main/windows.js'; +import { ILogService } from '../../log/common/log.js'; +import { IThemeMainService } from './themeMainService.js'; + +// These default colors match our default themes +// editor background color ("Dark Modern", etc...) +const DEFAULT_BG_LIGHT = '#FFFFFF'; +const DEFAULT_BG_DARK = '#1F1F1F'; +const DEFAULT_BG_HC_BLACK = '#000000'; +const DEFAULT_BG_HC_LIGHT = '#FFFFFF'; + +const THEME_STORAGE_KEY = 'theme'; +const THEME_BG_STORAGE_KEY = 'themeBackground'; + +const THEME_WINDOW_SPLASH_KEY = 'windowSplash'; +const THEME_WINDOW_SPLASH_OVERRIDE_KEY = 'windowSplashWorkspaceOverride'; + +const AUXILIARYBAR_DEFAULT_VISIBILITY = 'workbench.secondarySideBar.defaultVisibility'; + +namespace ThemeSettings { + export const DETECT_COLOR_SCHEME = 'window.autoDetectColorScheme'; + export const DETECT_HC = 'window.autoDetectHighContrast'; + export const SYSTEM_COLOR_THEME = 'window.systemColorTheme'; +} + +interface IPartSplashOverrideWorkspaces { + [workspaceId: string]: { + sideBarVisible: boolean; + auxiliaryBarVisible: boolean; + }; +} + +interface IPartsSplashOverride { + layoutInfo: { + sideBarWidth: number; + auxiliaryBarWidth: number; + + workspaces: IPartSplashOverrideWorkspaces; + }; +} + +export class ThemeMainService extends Disposable implements IThemeMainService { + + declare readonly _serviceBrand: undefined; + + private static readonly DEFAULT_BAR_WIDTH = 300; + + private static readonly WORKSPACE_OVERRIDE_LIMIT = 50; + + private readonly _onDidChangeColorScheme = this._register(new Emitter()); + readonly onDidChangeColorScheme = this._onDidChangeColorScheme.event; + + constructor( + @IStateService private stateService: IStateService, + @IConfigurationService private configurationService: IConfigurationService, + @ILogService private logService: ILogService + ) { + super(); + + // System Theme + if (!isLinux) { + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(ThemeSettings.SYSTEM_COLOR_THEME) || e.affectsConfiguration(ThemeSettings.DETECT_COLOR_SCHEME)) { + this.updateSystemColorTheme(); + } + })); + } + this.updateSystemColorTheme(); + + // Color Scheme changes + this._register(Event.fromNodeEventEmitter(electron.nativeTheme, 'updated')(() => this._onDidChangeColorScheme.fire(this.getColorScheme()))); + } + + private updateSystemColorTheme(): void { + if (isLinux || this.configurationService.getValue(ThemeSettings.DETECT_COLOR_SCHEME)) { + electron.nativeTheme.themeSource = 'system'; // only with `system` we can detect the system color scheme + } else { + switch (this.configurationService.getValue<'default' | 'auto' | 'light' | 'dark'>(ThemeSettings.SYSTEM_COLOR_THEME)) { + case 'dark': + electron.nativeTheme.themeSource = 'dark'; + break; + case 'light': + electron.nativeTheme.themeSource = 'light'; + break; + case 'auto': + switch (this.getPreferredBaseTheme() ?? this.getStoredBaseTheme()) { + case ThemeTypeSelector.VS: electron.nativeTheme.themeSource = 'light'; break; + case ThemeTypeSelector.VS_DARK: electron.nativeTheme.themeSource = 'dark'; break; + default: electron.nativeTheme.themeSource = 'system'; + } + break; + default: + electron.nativeTheme.themeSource = 'system'; + break; + } + } + } + + getColorScheme(): IColorScheme { + + // high contrast is reflected by the shouldUseInvertedColorScheme property + if (isWindows) { + if (electron.nativeTheme.shouldUseHighContrastColors) { + // shouldUseInvertedColorScheme is dark, !shouldUseInvertedColorScheme is light + return { dark: electron.nativeTheme.shouldUseInvertedColorScheme, highContrast: true }; + } + } + + // high contrast is set if one of shouldUseInvertedColorScheme or shouldUseHighContrastColors is set, + // reflecting the 'Invert colours' and `Increase contrast` settings in MacOS + else if (isMacintosh) { + if (electron.nativeTheme.shouldUseInvertedColorScheme || electron.nativeTheme.shouldUseHighContrastColors) { + return { dark: electron.nativeTheme.shouldUseDarkColors, highContrast: true }; + } + } + + // ubuntu gnome seems to have 3 states, light dark and high contrast + else if (isLinux) { + if (electron.nativeTheme.shouldUseHighContrastColors) { + return { dark: true, highContrast: true }; + } + } + + return { + dark: electron.nativeTheme.shouldUseDarkColors, + highContrast: false + }; + } + + getPreferredBaseTheme(): ThemeTypeSelector | undefined { + const colorScheme = this.getColorScheme(); + if (this.configurationService.getValue(ThemeSettings.DETECT_HC) && colorScheme.highContrast) { + return colorScheme.dark ? ThemeTypeSelector.HC_BLACK : ThemeTypeSelector.HC_LIGHT; + } + + if (this.configurationService.getValue(ThemeSettings.DETECT_COLOR_SCHEME)) { + return colorScheme.dark ? ThemeTypeSelector.VS_DARK : ThemeTypeSelector.VS; + } + + return undefined; + } + + getBackgroundColor(): string { + const preferred = this.getPreferredBaseTheme(); + const stored = this.getStoredBaseTheme(); + + // If the stored theme has the same base as the preferred, we can return the stored background + if (preferred === undefined || preferred === stored) { + const storedBackground = this.stateService.getItem(THEME_BG_STORAGE_KEY, null); + if (storedBackground) { + return storedBackground; + } + } + + // Otherwise we return the default background for the preferred base theme. If there's no preferred, use the stored one. + switch (preferred ?? stored) { + case ThemeTypeSelector.VS: return DEFAULT_BG_LIGHT; + case ThemeTypeSelector.HC_BLACK: return DEFAULT_BG_HC_BLACK; + case ThemeTypeSelector.HC_LIGHT: return DEFAULT_BG_HC_LIGHT; + default: return DEFAULT_BG_DARK; + } + } + + private getStoredBaseTheme(): ThemeTypeSelector { + const baseTheme = this.stateService.getItem(THEME_STORAGE_KEY, ThemeTypeSelector.VS_DARK).split(' ')[0]; + switch (baseTheme) { + case ThemeTypeSelector.VS: return ThemeTypeSelector.VS; + case ThemeTypeSelector.HC_BLACK: return ThemeTypeSelector.HC_BLACK; + case ThemeTypeSelector.HC_LIGHT: return ThemeTypeSelector.HC_LIGHT; + default: return ThemeTypeSelector.VS_DARK; + } + } + + saveWindowSplash(windowId: number | undefined, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined, splash: IPartsSplash): void { + + // Update override as needed + const splashOverride = this.updateWindowSplashOverride(workspace, splash); + + // Update in storage + this.stateService.setItems(coalesce([ + { key: THEME_STORAGE_KEY, data: splash.baseTheme }, + { key: THEME_BG_STORAGE_KEY, data: splash.colorInfo.background }, + { key: THEME_WINDOW_SPLASH_KEY, data: splash }, + splashOverride ? { key: THEME_WINDOW_SPLASH_OVERRIDE_KEY, data: splashOverride } : undefined + ])); + + // Update in opened windows + if (typeof windowId === 'number') { + this.updateBackgroundColor(windowId, splash); + } + + // Update system theme + this.updateSystemColorTheme(); + } + + private updateWindowSplashOverride(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined, splash: IPartsSplash): IPartsSplashOverride | undefined { + let splashOverride: IPartsSplashOverride | undefined = undefined; + let changed = false; + if (workspace) { + splashOverride = { ...this.getWindowSplashOverride() }; // make a copy for modifications + + changed = this.doUpdateWindowSplashOverride(workspace, splash, splashOverride, 'sideBar'); + changed = this.doUpdateWindowSplashOverride(workspace, splash, splashOverride, 'auxiliaryBar') || changed; + } + + return changed ? splashOverride : undefined; + } + + private doUpdateWindowSplashOverride(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier, splash: IPartsSplash, splashOverride: IPartsSplashOverride, part: 'sideBar' | 'auxiliaryBar'): boolean { + const currentWidth = part === 'sideBar' ? splash.layoutInfo?.sideBarWidth : splash.layoutInfo?.auxiliarySideBarWidth; + const overrideWidth = part === 'sideBar' ? splashOverride.layoutInfo.sideBarWidth : splashOverride.layoutInfo.auxiliaryBarWidth; + + // No layout info: remove override + let changed = false; + if (typeof currentWidth !== 'number') { + if (splashOverride.layoutInfo.workspaces[workspace.id]) { + delete splashOverride.layoutInfo.workspaces[workspace.id]; + changed = true; + } + + return changed; + } + + let workspaceOverride = splashOverride.layoutInfo.workspaces[workspace.id]; + if (!workspaceOverride) { + const workspaceEntries = Object.keys(splashOverride.layoutInfo.workspaces); + if (workspaceEntries.length >= ThemeMainService.WORKSPACE_OVERRIDE_LIMIT) { + delete splashOverride.layoutInfo.workspaces[workspaceEntries[0]]; + changed = true; + } + + workspaceOverride = { sideBarVisible: false, auxiliaryBarVisible: false }; + splashOverride.layoutInfo.workspaces[workspace.id] = workspaceOverride; + changed = true; + } + + // Part has width: update width & visibility override + if (currentWidth > 0) { + if (overrideWidth !== currentWidth) { + splashOverride.layoutInfo[part === 'sideBar' ? 'sideBarWidth' : 'auxiliaryBarWidth'] = currentWidth; + changed = true; + } + + switch (part) { + case 'sideBar': + if (!workspaceOverride.sideBarVisible) { + workspaceOverride.sideBarVisible = true; + changed = true; + } + break; + case 'auxiliaryBar': + if (!workspaceOverride.auxiliaryBarVisible) { + workspaceOverride.auxiliaryBarVisible = true; + changed = true; + } + break; + } + } + + // Part is hidden: update visibility override + else { + switch (part) { + case 'sideBar': + if (workspaceOverride.sideBarVisible) { + workspaceOverride.sideBarVisible = false; + changed = true; + } + break; + case 'auxiliaryBar': + if (workspaceOverride.auxiliaryBarVisible) { + workspaceOverride.auxiliaryBarVisible = false; + changed = true; + } + break; + } + } + + return changed; + } + + private updateBackgroundColor(windowId: number, splash: IPartsSplash): void { + for (const window of getAllWindowsExcludingOffscreen()) { + if (window.id === windowId) { + window.setBackgroundColor(splash.colorInfo.background); + break; + } + } + } + + getWindowSplash(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): IPartsSplash | undefined { + try { + return this.doGetWindowSplash(workspace); + } catch (error) { + this.logService.error('[theme main service] Failed to get window splash', error); + + return undefined; + } + } + + private doGetWindowSplash(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): IPartsSplash | undefined { + const partSplash = this.stateService.getItem(THEME_WINDOW_SPLASH_KEY); + if (!partSplash?.layoutInfo) { + return partSplash; // return early: overrides currently only apply to layout info + } + + const override = this.getWindowSplashOverride(); + + // Figure out side bar width based on workspace and overrides + let sideBarWidth: number; + if (workspace) { + if (override.layoutInfo.workspaces[workspace.id]?.sideBarVisible === false) { + sideBarWidth = 0; + } else { + sideBarWidth = override.layoutInfo.sideBarWidth || partSplash.layoutInfo.sideBarWidth || ThemeMainService.DEFAULT_BAR_WIDTH; + } + } else { + sideBarWidth = 0; + } + + // Figure out auxiliary bar width based on workspace, configuration and overrides + const auxiliarySideBarDefaultVisibility = this.configurationService.getValue(AUXILIARYBAR_DEFAULT_VISIBILITY); + let auxiliarySideBarWidth: number; + if (workspace) { + const auxiliaryBarVisible = override.layoutInfo.workspaces[workspace.id]?.auxiliaryBarVisible; + if (auxiliaryBarVisible === true) { + auxiliarySideBarWidth = override.layoutInfo.auxiliaryBarWidth || partSplash.layoutInfo.auxiliarySideBarWidth || ThemeMainService.DEFAULT_BAR_WIDTH; + } else if (auxiliaryBarVisible === false) { + auxiliarySideBarWidth = 0; + } else { + if (auxiliarySideBarDefaultVisibility === 'visible' || auxiliarySideBarDefaultVisibility === 'visibleInWorkspace') { + auxiliarySideBarWidth = override.layoutInfo.auxiliaryBarWidth || partSplash.layoutInfo.auxiliarySideBarWidth || ThemeMainService.DEFAULT_BAR_WIDTH; + } else { + auxiliarySideBarWidth = 0; + } + } + } else { + auxiliarySideBarWidth = 0; // technically not true if configured 'visible', but we never store splash per empty window, so we decide on a default here + } + + return { + ...partSplash, + layoutInfo: { + ...partSplash.layoutInfo, + sideBarWidth, + auxiliarySideBarWidth + } + }; + } + + private getWindowSplashOverride(): IPartsSplashOverride { + let override = this.stateService.getItem(THEME_WINDOW_SPLASH_OVERRIDE_KEY); + + if (!override?.layoutInfo) { + override = { + layoutInfo: { + sideBarWidth: ThemeMainService.DEFAULT_BAR_WIDTH, + auxiliaryBarWidth: ThemeMainService.DEFAULT_BAR_WIDTH, + workspaces: {} + } + }; + } + + if (!override.layoutInfo.sideBarWidth) { + override.layoutInfo.sideBarWidth = ThemeMainService.DEFAULT_BAR_WIDTH; + } + + if (!override.layoutInfo.auxiliaryBarWidth) { + override.layoutInfo.auxiliaryBarWidth = ThemeMainService.DEFAULT_BAR_WIDTH; + } + + if (!override.layoutInfo.workspaces) { + override.layoutInfo.workspaces = {}; + } + + return override; + } +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptSlashCommand.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptSlashCommand.ts index 72d1b4259bc..1069d4a7a89 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptSlashCommand.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptSlashCommand.ts @@ -4,9 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { PromptToken } from './promptToken.js'; -import { assert } from '../../../../../../../base/common/assert.js'; import { Range } from '../../../../../../../editor/common/core/range.js'; -import { INVALID_NAME_CHARACTERS, STOP_CHARACTERS } from '../parsers/promptSlashCommandParser.js'; /** * All prompt at-mentions start with `/` character. @@ -24,14 +22,6 @@ export class PromptSlashCommand extends PromptToken { */ public readonly name: string, ) { - // sanity check of characters used in the provided command name - for (const character of name) { - assert( - (INVALID_NAME_CHARACTERS.includes(character) === false) && - (STOP_CHARACTERS.includes(character) === false), - `Slash command 'name' cannot contain character '${character}', got '${name}'.`, - ); - } super(range); } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptVariable.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptVariable.ts index c84903e544f..ec5dd2e7a36 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptVariable.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/tokens/promptVariable.ts @@ -4,9 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { PromptToken } from './promptToken.js'; -import { assert } from '../../../../../../../base/common/assert.js'; import { IRange, Range } from '../../../../../../../editor/common/core/range.js'; -import { INVALID_NAME_CHARACTERS, STOP_CHARACTERS } from '../parsers/promptVariableParser.js'; /** * All prompt variables start with `#` character. @@ -29,14 +27,6 @@ export class PromptVariable extends PromptToken { */ public readonly name: string, ) { - // sanity check of characters used in the provided variable name - for (const character of name) { - assert( - (INVALID_NAME_CHARACTERS.includes(character) === false) && - (STOP_CHARACTERS.includes(character) === false), - `Variable 'name' cannot contain character '${character}', got '${name}'.`, - ); - } super(range); } @@ -74,14 +64,6 @@ export class PromptVariableWithData extends PromptVariable { public readonly data: string, ) { super(fullRange, name); - - // sanity check of characters used in the provided variable data - for (const character of data) { - assert( - (STOP_CHARACTERS.includes(character) === false), - `Variable 'data' cannot contain character '${character}', got '${data}'.`, - ); - } } /** diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index a9780480c6d..7c2219db3f2 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -20,7 +20,7 @@ import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatus import { IOutputChannelRegistry, Extensions as OutputExt } from '../../../services/output/common/output.js'; -import { ITaskEvent, TaskGroup, TaskSettingId, TASKS_CATEGORY, TASK_RUNNING_STATE, TASK_TERMINAL_ACTIVE, TaskEventKind } from '../common/tasks.js'; +import { ITaskEvent, TaskGroup, TaskSettingId, TASKS_CATEGORY, TASK_RUNNING_STATE, TASK_TERMINAL_ACTIVE, TaskEventKind, rerunTaskIcon, RerunForActiveTerminalCommandId } from '../common/tasks.js'; import { ITaskService, TaskCommandsRegistered, TaskExecutionSupportedContext } from '../common/taskService.js'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js'; @@ -40,8 +40,6 @@ import { TaskDefinitionRegistry } from '../common/taskDefinitionRegistry.js'; import { TerminalMenuBarGroup } from '../../terminal/browser/terminalMenus.js'; import { isString } from '../../../../base/common/types.js'; import { promiseWithResolvers } from '../../../../base/common/async.js'; -import { Codicon } from '../../../../base/common/codicons.js'; -import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js'; import { TerminalContextKeys } from '../../terminal/common/terminalContextKey.js'; import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js'; @@ -566,8 +564,6 @@ configurationRegistry.registerConfiguration({ } }); -export const rerunTaskIcon = registerIcon('rerun-task', Codicon.refresh, nls.localize('rerunTaskIcon', 'View icon of the rerun task.')); -export const RerunForActiveTerminalCommandId = 'workbench.action.tasks.rerunForActiveTerminal'; registerAction2(class extends Action2 { constructor() { super({ @@ -595,4 +591,3 @@ registerAction2(class extends Action2 { } } }); - diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 5b2f568a3c3..3fbca0976b9 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -40,7 +40,7 @@ import { TaskTerminalStatus } from './taskTerminalStatus.js'; import { ProblemCollectorEventKind, ProblemHandlingStrategy, StartStopProblemCollector, WatchingProblemCollector } from '../common/problemCollectors.js'; import { GroupKind } from '../common/taskConfiguration.js'; import { IResolveSet, IResolvedVariables, ITaskExecuteResult, ITaskResolver, ITaskSummary, ITaskSystem, ITaskSystemInfo, ITaskSystemInfoResolver, ITaskTerminateResponse, TaskError, TaskErrors, TaskExecuteKind, Triggers } from '../common/taskSystem.js'; -import { CommandOptions, CommandString, ContributedTask, CustomTask, DependsOrder, ICommandConfiguration, IConfigurationProperties, IExtensionTaskSource, IPresentationOptions, IShellConfiguration, IShellQuotingOptions, ITaskEvent, InMemoryTask, PanelKind, RevealKind, RevealProblemKind, RuntimeType, ShellQuoting, TASK_TERMINAL_ACTIVE, Task, TaskEvent, TaskEventKind, TaskScope, TaskSourceKind } from '../common/tasks.js'; +import { CommandOptions, CommandString, ContributedTask, CustomTask, DependsOrder, ICommandConfiguration, IConfigurationProperties, IExtensionTaskSource, IPresentationOptions, IShellConfiguration, IShellQuotingOptions, ITaskEvent, InMemoryTask, PanelKind, RerunForActiveTerminalCommandId, RevealKind, RevealProblemKind, RuntimeType, ShellQuoting, TASK_TERMINAL_ACTIVE, Task, TaskEvent, TaskEventKind, TaskScope, TaskSourceKind, rerunTaskIcon } from '../common/tasks.js'; import { ITerminalGroupService, ITerminalInstance, ITerminalService } from '../../terminal/browser/terminal.js'; import { VSCodeOscProperty, VSCodeOscPt, VSCodeSequence } from '../../terminal/browser/terminalEscapeSequences.js'; import { TerminalProcessExtHostProxy } from '../../terminal/browser/terminalProcessExtHostProxy.js'; @@ -50,7 +50,6 @@ import { IWorkbenchEnvironmentService } from '../../../services/environment/comm import { IOutputService } from '../../../services/output/common/output.js'; import { IPaneCompositePartService } from '../../../services/panecomposite/browser/panecomposite.js'; import { IPathService } from '../../../services/path/common/pathService.js'; -import { RerunForActiveTerminalCommandId, rerunTaskIcon } from './task.contribution.js'; import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; interface ITerminalData { diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index f7acf37527e..8f40c65ffda 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -17,6 +17,8 @@ import { TaskDefinitionRegistry } from './taskDefinitionRegistry.js'; import { IExtensionDescription } from '../../../../platform/extensions/common/extensions.js'; import { ConfigurationTarget } from '../../../../platform/configuration/common/configuration.js'; import { TerminalExitReason } from '../../../../platform/terminal/common/terminal.js'; +import { Codicon } from '../../../../base/common/codicons.js'; +import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js'; @@ -1389,3 +1391,5 @@ export namespace TaskDefinition { return KeyedTaskIdentifier.create(literal); } } + +export const rerunTaskIcon = registerIcon('rerun-task', Codicon.refresh, nls.localize('rerunTaskIcon', 'View icon of the rerun task.')); export const RerunForActiveTerminalCommandId = 'workbench.action.tasks.rerunForActiveTerminal'; From 6bb80665066e1e7b827551e164a5b0f8539f6b53 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 14:37:05 +0200 Subject: [PATCH 119/236] fix tsb cyclic dependency check --- build/lib/tsb/builder.js | 33 ++++++++++---------- build/lib/tsb/builder.ts | 34 +++++++++++---------- build/lib/tsb/utils.js | 57 ++++++++++++++++------------------- build/lib/tsb/utils.ts | 65 +++++++++++++++++----------------------- 4 files changed, 88 insertions(+), 101 deletions(-) diff --git a/build/lib/tsb/builder.js b/build/lib/tsb/builder.js index 0da1f5c09e6..bd363137c15 100644 --- a/build/lib/tsb/builder.js +++ b/build/lib/tsb/builder.js @@ -63,7 +63,7 @@ function createTypeScriptBuilder(config, projectFile, cmd) { const _log = config.logFn; const host = new LanguageServiceHost(cmd, projectFile, _log); const outHost = new LanguageServiceHost({ ...cmd, options: { ...cmd.options, sourceRoot: cmd.options.outDir } }, cmd.options.outDir ?? '', _log); - let lastCycleCheckVersion; + const toBeCheckedForCycles = []; const service = typescript_1.default.createLanguageService(host, typescript_1.default.createDocumentRegistry()); const lastBuildVersion = Object.create(null); const lastDtsHash = Object.create(null); @@ -294,6 +294,7 @@ function createTypeScriptBuilder(config, projectFile, cmd) { const jsValue = value.files.find(candidate => candidate.basename.endsWith('.js')); if (jsValue) { outHost.addScriptSnapshot(jsValue.path, new ScriptSnapshot(String(jsValue.contents), new Date())); + toBeCheckedForCycles.push(jsValue.path); } }).catch(e => { // can't just skip this or make a result up.. @@ -387,24 +388,19 @@ function createTypeScriptBuilder(config, projectFile, cmd) { workOnNext(); }).then(() => { // check for cyclic dependencies - const thisCycleCheckVersion = outHost.getProjectVersion(); - if (thisCycleCheckVersion === lastCycleCheckVersion) { - return; - } - const oneCycle = outHost.hasCyclicDependency(); - lastCycleCheckVersion = thisCycleCheckVersion; - delete oldErrors[projectFile]; - if (oneCycle) { + const cycles = outHost.getCyclicDependencies(toBeCheckedForCycles); + toBeCheckedForCycles.length = 0; + for (const [filename, error] of cycles) { const cycleError = { category: typescript_1.default.DiagnosticCategory.Error, code: 1, file: undefined, start: undefined, length: undefined, - messageText: `CYCLIC dependency between ${oneCycle}` + messageText: `CYCLIC dependency: ${error}` }; onError(cycleError); - newErrors[projectFile] = [cycleError]; + newErrors[filename] = [cycleError]; } }).then(() => { // store the build versions to not rebuilt the next time @@ -588,15 +584,20 @@ class LanguageServiceHost { node.incoming.forEach(entry => target.push(entry.data)); } } - hasCyclicDependency() { + getCyclicDependencies(filenames) { // Ensure dependencies are up to date while (this._dependenciesRecomputeList.length) { this._processFile(this._dependenciesRecomputeList.pop()); } - const cycle = this._dependencies.findCycle(); - return cycle - ? cycle.join(' -> ') - : undefined; + const t2 = performance.now(); + console.log(`START CYCLE_CHECK for ${filenames.length} files`); + const cycles = this._dependencies.findCycles(filenames); + console.log(`END CYCLE_CHECK after ${performance.now() - t2}ms`); + const result = new Map(); + for (const [key, value] of cycles) { + result.set(key, value.join(' -> ')); + } + return result; } _processFile(filename) { if (filename.match(/.*\.d\.ts$/)) { diff --git a/build/lib/tsb/builder.ts b/build/lib/tsb/builder.ts index 1a68131f86d..da68e8a1e4e 100644 --- a/build/lib/tsb/builder.ts +++ b/build/lib/tsb/builder.ts @@ -44,7 +44,7 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str const host = new LanguageServiceHost(cmd, projectFile, _log); const outHost = new LanguageServiceHost({ ...cmd, options: { ...cmd.options, sourceRoot: cmd.options.outDir } }, cmd.options.outDir ?? '', _log); - let lastCycleCheckVersion: string; + const toBeCheckedForCycles: string[] = []; const service = ts.createLanguageService(host, ts.createDocumentRegistry()); const lastBuildVersion: { [path: string]: string } = Object.create(null); @@ -315,6 +315,7 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str const jsValue = value.files.find(candidate => candidate.basename.endsWith('.js')); if (jsValue) { outHost.addScriptSnapshot(jsValue.path, new ScriptSnapshot(String(jsValue.contents), new Date())); + toBeCheckedForCycles.push(jsValue.path); } }).catch(e => { @@ -424,25 +425,20 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str }).then(() => { // check for cyclic dependencies - const thisCycleCheckVersion = outHost.getProjectVersion(); - if (thisCycleCheckVersion === lastCycleCheckVersion) { - return; - } - const oneCycle = outHost.hasCyclicDependency(); - lastCycleCheckVersion = thisCycleCheckVersion; - delete oldErrors[projectFile]; + const cycles = outHost.getCyclicDependencies(toBeCheckedForCycles); + toBeCheckedForCycles.length = 0; - if (oneCycle) { + for (const [filename, error] of cycles) { const cycleError: ts.Diagnostic = { category: ts.DiagnosticCategory.Error, code: 1, file: undefined, start: undefined, length: undefined, - messageText: `CYCLIC dependency between ${oneCycle}` + messageText: `CYCLIC dependency: ${error}` }; onError(cycleError); - newErrors[projectFile] = [cycleError]; + newErrors[filename] = [cycleError]; } }).then(() => { @@ -666,15 +662,21 @@ class LanguageServiceHost implements ts.LanguageServiceHost { } } - hasCyclicDependency(): string | undefined { + getCyclicDependencies(filenames: string[]): Map { // Ensure dependencies are up to date while (this._dependenciesRecomputeList.length) { this._processFile(this._dependenciesRecomputeList.pop()!); } - const cycle = this._dependencies.findCycle(); - return cycle - ? cycle.join(' -> ') - : undefined; + const t2 = performance.now(); + console.log(`START CYCLE_CHECK for ${filenames.length} files`); + const cycles = this._dependencies.findCycles(filenames); + console.log(`END CYCLE_CHECK after ${performance.now() - t2}ms`); + + const result = new Map(); + for (const [key, value] of cycles) { + result.set(key, value.join(' -> ')); + } + return result; } _processFile(filename: string): void { diff --git a/build/lib/tsb/utils.js b/build/lib/tsb/utils.js index 29cccf0f833..28080a9d8df 100644 --- a/build/lib/tsb/utils.js +++ b/build/lib/tsb/utils.js @@ -55,44 +55,39 @@ var graph; lookup(data) { return this._nodes.get(data) ?? null; } - findCycle() { - let result; - let foundStartNodes = false; + findCycles(allData) { + const result = new Map(); const checked = new Set(); - for (const [_start, value] of this._nodes) { - if (Object.values(value.incoming).length > 0) { + for (const data of allData) { + const node = this.lookup(data); + if (!node) { continue; } - foundStartNodes = true; - const dfs = (node, visited) => { - if (checked.has(node)) { - return; - } - if (visited.has(node)) { - result = [...visited, node].map(n => n.data); - const idx = result.indexOf(node.data); - result = result.slice(idx); - return; - } - visited.add(node); - for (const child of Object.values(node.outgoing)) { - dfs(child, visited); - if (result) { - break; - } - } - visited.delete(node); - checked.add(node); - }; - dfs(value, new Set()); + const r = this._findCycle(node, checked, new Set()) ?? []; + result.set(node.data, r); + } + return result; + } + _findCycle(node, checked, seen) { + if (checked.has(node.data)) { + return undefined; + } + let result; + for (const child of node.outgoing.values()) { + if (seen.has(child.data)) { + const seenArr = Array.from(seen); + const idx = seenArr.indexOf(child.data); + seenArr.push(child.data); + return idx > 0 ? seenArr.slice(idx) : seenArr; + } + seen.add(child.data); + result = this._findCycle(child, checked, seen); + seen.delete(child.data); if (result) { break; } } - if (!foundStartNodes) { - // everything is a cycle - return Array.from(this._nodes.keys()); - } + checked.add(node.data); return result; } } diff --git a/build/lib/tsb/utils.ts b/build/lib/tsb/utils.ts index 59d1cab36d3..5a29ebf8f51 100644 --- a/build/lib/tsb/utils.ts +++ b/build/lib/tsb/utils.ts @@ -63,53 +63,42 @@ export namespace graph { return this._nodes.get(data) ?? null; } - findCycle(): T[] | undefined { - - let result: T[] | undefined; - let foundStartNodes = false; - const checked = new Set>(); - - for (const [_start, value] of this._nodes) { - - if (Object.values(value.incoming).length > 0) { + findCycles(allData: T[]): Map { + const result = new Map(); + const checked = new Set(); + for (const data of allData) { + const node = this.lookup(data); + if (!node) { continue; } + const r = this._findCycle(node, checked, new Set()) ?? []; + result.set(node.data, r); + } + return result; + } - foundStartNodes = true; + private _findCycle(node: Node, checked: Set, seen: Set): T[] | undefined { - const dfs = (node: Node, visited: Set>) => { + if (checked.has(node.data)) { + return undefined; + } - if (checked.has(node)) { - return; - } - - if (visited.has(node)) { - result = [...visited, node].map(n => n.data); - const idx = result.indexOf(node.data); - result = result.slice(idx); - return; - } - visited.add(node); - for (const child of Object.values(node.outgoing)) { - dfs(child, visited); - if (result) { - break; - } - } - visited.delete(node); - checked.add(node); - }; - dfs(value, new Set()); + let result: T[] | undefined; + for (const child of node.outgoing.values()) { + if (seen.has(child.data)) { + const seenArr = Array.from(seen); + const idx = seenArr.indexOf(child.data); + seenArr.push(child.data); + return idx > 0 ? seenArr.slice(idx) : seenArr; + } + seen.add(child.data); + result = this._findCycle(child, checked, seen); + seen.delete(child.data); if (result) { break; } } - - if (!foundStartNodes) { - // everything is a cycle - return Array.from(this._nodes.keys()); - } - + checked.add(node.data); return result; } } From 950ac255eae0954eff52c3ac0ad1108d6558de80 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 15:01:50 +0200 Subject: [PATCH 120/236] more cyclic dependency removal --- .../chatEditingModifiedDocumentEntry.ts | 4 +-- .../chatEditingModifiedFileEntry.ts | 23 +--------------- .../chatEditingModifiedNotebookEntry.ts | 4 +-- .../browser/chatEditing/chatEditingSession.ts | 4 +-- .../chatEditing/chatEditingSessionStorage.ts | 3 +-- .../chatEditingTextModelContentProviders.ts | 3 +-- .../chatEditingModifiedNotebookDiff.ts | 4 +-- .../chatEditingNotebookFileSystemProvider.ts | 3 +-- .../contrib/chat/common/chatEditingService.ts | 26 +++++++++++++++++++ .../browser/chatEditingSessionStorage.test.ts | 3 +-- 10 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts index 39bfb47d8c2..a42e9b3ce6f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts @@ -41,11 +41,11 @@ import { IEditorPane, SaveReason } from '../../../../common/editor.js'; import { IFilesConfigurationService } from '../../../../services/filesConfiguration/common/filesConfigurationService.js'; import { ITextFileService, isTextFileEditorModel, stringToSnapshot } from '../../../../services/textfile/common/textfiles.js'; import { ICellEditOperation } from '../../../notebook/common/notebookCommon.js'; -import { ChatEditKind, IModifiedFileEntry, IModifiedFileEntryEditorIntegration, ModifiedFileEntryState } from '../../common/chatEditingService.js'; +import { ChatEditKind, IModifiedEntryTelemetryInfo, IModifiedFileEntry, IModifiedFileEntryEditorIntegration, ISnapshotEntry, ModifiedFileEntryState } from '../../common/chatEditingService.js'; import { IChatResponseModel } from '../../common/chatModel.js'; import { IChatService } from '../../common/chatService.js'; import { ChatEditingCodeEditorIntegration, IDocumentDiff2 } from './chatEditingCodeEditorIntegration.js'; -import { AbstractChatEditingModifiedFileEntry, IModifiedEntryTelemetryInfo, ISnapshotEntry, pendingRewriteMinimap } from './chatEditingModifiedFileEntry.js'; +import { AbstractChatEditingModifiedFileEntry, pendingRewriteMinimap } from './chatEditingModifiedFileEntry.js'; import { ChatEditingSnapshotTextModelContentProvider, ChatEditingTextModelContentProvider } from './chatEditingTextModelContentProviders.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts index 08328ef44d4..ac4474ae213 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts @@ -10,7 +10,6 @@ import { Schemas } from '../../../../../base/common/network.js'; import { clamp } from '../../../../../base/common/numbers.js'; import { autorun, derived, IObservable, ITransaction, observableValue, observableValueOpts, transaction } from '../../../../../base/common/observable.js'; import { URI } from '../../../../../base/common/uri.js'; -import { StringEdit } from '../../../../../editor/common/core/edits/stringEdit.js'; import { TextEdit } from '../../../../../editor/common/languages.js'; import { localize } from '../../../../../nls.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; @@ -22,8 +21,7 @@ import { IUndoRedoElement, IUndoRedoService } from '../../../../../platform/undo import { IEditorPane } from '../../../../common/editor.js'; import { IFilesConfigurationService } from '../../../../services/filesConfiguration/common/filesConfigurationService.js'; import { ICellEditOperation } from '../../../notebook/common/notebookCommon.js'; -import { IChatAgentResult } from '../../common/chatAgents.js'; -import { ChatEditKind, IModifiedFileEntry, IModifiedFileEntryEditorIntegration, ModifiedFileEntryState } from '../../common/chatEditingService.js'; +import { ChatEditKind, IModifiedEntryTelemetryInfo, IModifiedFileEntry, IModifiedFileEntryEditorIntegration, ISnapshotEntry, ModifiedFileEntryState } from '../../common/chatEditingService.js'; import { IChatResponseModel } from '../../common/chatModel.js'; import { IChatService } from '../../common/chatService.js'; @@ -318,22 +316,3 @@ export abstract class AbstractChatEditingModifiedFileEntry extends Disposable im abstract initialContent: string; } - -export interface IModifiedEntryTelemetryInfo { - readonly agentId: string | undefined; - readonly command: string | undefined; - readonly sessionId: string; - readonly requestId: string; - readonly result: IChatAgentResult | undefined; -} - -export interface ISnapshotEntry { - readonly resource: URI; - readonly languageId: string; - readonly snapshotUri: URI; - readonly original: string; - readonly current: string; - readonly originalToCurrentEdit: StringEdit; - readonly state: ModifiedFileEntryState; - telemetryInfo: IModifiedEntryTelemetryInfo; -} diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts index cc23b401827..d5616bc8221 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts @@ -43,10 +43,10 @@ import { INotebookEditorModelResolverService } from '../../../notebook/common/no import { INotebookLoggingService } from '../../../notebook/common/notebookLoggingService.js'; import { INotebookService } from '../../../notebook/common/notebookService.js'; import { INotebookEditorWorkerService } from '../../../notebook/common/services/notebookWorkerService.js'; -import { ChatEditKind, IModifiedFileEntryEditorIntegration, ModifiedFileEntryState } from '../../common/chatEditingService.js'; +import { ChatEditKind, IModifiedEntryTelemetryInfo, IModifiedFileEntryEditorIntegration, ISnapshotEntry, ModifiedFileEntryState } from '../../common/chatEditingService.js'; import { IChatResponseModel } from '../../common/chatModel.js'; import { IChatService } from '../../common/chatService.js'; -import { AbstractChatEditingModifiedFileEntry, IModifiedEntryTelemetryInfo, ISnapshotEntry } from './chatEditingModifiedFileEntry.js'; +import { AbstractChatEditingModifiedFileEntry } from './chatEditingModifiedFileEntry.js'; import { createSnapshot, deserializeSnapshot, getNotebookSnapshotFileURI, restoreSnapshot, SnapshotComparer } from './notebook/chatEditingModifiedNotebookSnapshot.js'; import { ChatEditingNewNotebookContentEdits } from './notebook/chatEditingNewNotebookContentEdits.js'; import { ChatEditingNotebookCellEntry } from './notebook/chatEditingNotebookCellEntry.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts index b78e1f354de..edc6531ff88 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts @@ -35,11 +35,11 @@ import { MultiDiffEditor } from '../../../multiDiffEditor/browser/multiDiffEdito import { MultiDiffEditorInput } from '../../../multiDiffEditor/browser/multiDiffEditorInput.js'; import { CellUri, ICellEditOperation } from '../../../notebook/common/notebookCommon.js'; import { INotebookService } from '../../../notebook/common/notebookService.js'; -import { ChatEditingSessionState, ChatEditKind, getMultiDiffSourceUri, IChatEditingSession, IEditSessionEntryDiff, IModifiedFileEntry, IStreamingEdits, ModifiedFileEntryState } from '../../common/chatEditingService.js'; +import { ChatEditingSessionState, ChatEditKind, getMultiDiffSourceUri, IChatEditingSession, IEditSessionEntryDiff, IModifiedEntryTelemetryInfo, IModifiedFileEntry, ISnapshotEntry, IStreamingEdits, ModifiedFileEntryState } from '../../common/chatEditingService.js'; import { IChatRequestDisablement, IChatResponseModel } from '../../common/chatModel.js'; import { IChatService } from '../../common/chatService.js'; import { ChatEditingModifiedDocumentEntry } from './chatEditingModifiedDocumentEntry.js'; -import { AbstractChatEditingModifiedFileEntry, IModifiedEntryTelemetryInfo, ISnapshotEntry } from './chatEditingModifiedFileEntry.js'; +import { AbstractChatEditingModifiedFileEntry } from './chatEditingModifiedFileEntry.js'; import { ChatEditingModifiedNotebookEntry } from './chatEditingModifiedNotebookEntry.js'; import { ChatEditingSessionStorage, IChatEditingSessionSnapshot, IChatEditingSessionStop, StoredSessionState } from './chatEditingSessionStorage.js'; import { ChatEditingTextModelContentProvider } from './chatEditingTextModelContentProviders.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts index b44fc546d1f..93b386d4fb4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts @@ -13,8 +13,7 @@ import { IEnvironmentService } from '../../../../../platform/environment/common/ import { IFileService } from '../../../../../platform/files/common/files.js'; import { ILogService } from '../../../../../platform/log/common/log.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; -import { ISnapshotEntry } from './chatEditingModifiedFileEntry.js'; -import { WorkingSetDisplayMetadata, ModifiedFileEntryState } from '../../common/chatEditingService.js'; +import { WorkingSetDisplayMetadata, ModifiedFileEntryState, ISnapshotEntry } from '../../common/chatEditingService.js'; const STORAGE_CONTENTS_FOLDER = 'contents'; const STORAGE_STATE_FILE = 'state.json'; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelContentProviders.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelContentProviders.ts index 20b3d767623..a2654b956bc 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelContentProviders.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelContentProviders.ts @@ -8,7 +8,6 @@ import { ITextModel } from '../../../../../editor/common/model.js'; import { IModelService } from '../../../../../editor/common/services/model.js'; import { ITextModelContentProvider } from '../../../../../editor/common/services/resolverService.js'; import { chatEditingSnapshotScheme, IChatEditingService } from '../../common/chatEditingService.js'; -import { ChatEditingSession } from './chatEditingSession.js'; type ChatEditingTextModelContentQueryData = { kind: 'doc'; documentId: string; chatSessionId: string }; @@ -72,7 +71,7 @@ export class ChatEditingSnapshotTextModelContentProvider implements ITextModelCo const data: ChatEditingSnapshotTextModelContentQueryData = JSON.parse(resource.query); const session = this._chatEditingService.getEditingSession(data.sessionId); - if (!(session instanceof ChatEditingSession) || !data.requestId) { + if (!session || !data.requestId) { return null; } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingModifiedNotebookDiff.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingModifiedNotebookDiff.ts index 5521a153318..4d7726defd0 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingModifiedNotebookDiff.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingModifiedNotebookDiff.ts @@ -8,8 +8,8 @@ import { computeDiff } from '../../../../notebook/common/notebookDiff.js'; import { INotebookEditorModelResolverService } from '../../../../notebook/common/notebookEditorModelResolverService.js'; import { INotebookLoggingService } from '../../../../notebook/common/notebookLoggingService.js'; import { INotebookEditorWorkerService } from '../../../../notebook/common/services/notebookWorkerService.js'; -import { IEditSessionEntryDiff } from '../../../common/chatEditingService.js'; -import { ISnapshotEntry } from '../chatEditingModifiedFileEntry.js'; +import { IEditSessionEntryDiff, ISnapshotEntry } from '../../../common/chatEditingService.js'; + export class ChatEditingModifiedNotebookDiff { static NewModelCounter: number = 0; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookFileSystemProvider.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookFileSystemProvider.ts index b79dd102d43..885797824de 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookFileSystemProvider.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookFileSystemProvider.ts @@ -16,7 +16,6 @@ import { IWorkbenchContribution } from '../../../../../common/contributions.js'; import { INotebookService } from '../../../../notebook/common/notebookService.js'; import { IChatEditingService } from '../../../common/chatEditingService.js'; import { ChatEditingNotebookSnapshotScheme, deserializeSnapshot } from './chatEditingModifiedNotebookSnapshot.js'; -import { ChatEditingSession } from '../chatEditingSession.js'; export class ChatEditingNotebookFileSystemProviderContrib extends Disposable implements IWorkbenchContribution { @@ -89,7 +88,7 @@ export class ChatEditingNotebookFileSystemProvider implements IFileSystemProvide throw new Error('File not found, viewType not found'); } const session = this._chatEditingService.getEditingSession(queryData.sessionId); - if (!(session instanceof ChatEditingSession) || !queryData.requestId) { + if (!session || !queryData.requestId) { throw new Error('File not found, session not found'); } const snapshotEntry = session.getSnapshot(queryData.requestId, queryData.undoStop || undefined, resource); diff --git a/src/vs/workbench/contrib/chat/common/chatEditingService.ts b/src/vs/workbench/contrib/chat/common/chatEditingService.ts index 4bf57eee5b5..3b67848e26c 100644 --- a/src/vs/workbench/contrib/chat/common/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/common/chatEditingService.ts @@ -8,12 +8,15 @@ import { Event } from '../../../../base/common/event.js'; import { IDisposable } from '../../../../base/common/lifecycle.js'; import { IObservable, IReader } from '../../../../base/common/observable.js'; import { URI } from '../../../../base/common/uri.js'; +import { StringEdit } from '../../../../editor/common/core/edits/stringEdit.js'; import { TextEdit } from '../../../../editor/common/languages.js'; +import { ITextModel } from '../../../../editor/common/model.js'; import { localize } from '../../../../nls.js'; import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { IEditorPane } from '../../../common/editor.js'; import { ICellEditOperation } from '../../notebook/common/notebookCommon.js'; +import { IChatAgentResult } from './chatAgents.js'; import { ChatModel, IChatResponseModel } from './chatModel.js'; export const IChatEditingService = createDecorator('chatEditingService'); @@ -79,6 +82,25 @@ export interface IStreamingEdits { export const chatEditingSnapshotScheme = 'chat-editing-snapshot-text-model'; +export interface IModifiedEntryTelemetryInfo { + readonly agentId: string | undefined; + readonly command: string | undefined; + readonly sessionId: string; + readonly requestId: string; + readonly result: IChatAgentResult | undefined; +} + +export interface ISnapshotEntry { + readonly resource: URI; + readonly languageId: string; + readonly snapshotUri: URI; + readonly original: string; + readonly current: string; + readonly originalToCurrentEdit: StringEdit; + readonly state: ModifiedFileEntryState; + telemetryInfo: IModifiedEntryTelemetryInfo; +} + export interface IChatEditingSession extends IDisposable { readonly isGlobalEditingSession: boolean; readonly chatSessionId: string; @@ -100,6 +122,10 @@ export interface IChatEditingSession extends IDisposable { */ getSnapshotUri(requestId: string, uri: URI, stopId: string | undefined): URI | undefined; + getSnapshotModel(requestId: string, undoStop: string | undefined, snapshotUri: URI): Promise; + + getSnapshot(requestId: string, undoStop: string | undefined, snapshotUri: URI): ISnapshotEntry | undefined; + /** * Will lead to this object getting disposed */ diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts index cd07b1d1c9d..c2b24bcfaeb 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts @@ -15,10 +15,9 @@ import { FileService } from '../../../../../platform/files/common/fileService.js import { InMemoryFileSystemProvider } from '../../../../../platform/files/common/inMemoryFilesystemProvider.js'; import { NullLogService } from '../../../../../platform/log/common/log.js'; import { TestEnvironmentService } from '../../../../test/browser/workbenchTestServices.js'; -import { ISnapshotEntry } from '../../browser/chatEditing/chatEditingModifiedFileEntry.js'; import { ChatEditingSessionStorage, IChatEditingSessionStop, StoredSessionState } from '../../browser/chatEditing/chatEditingSessionStorage.js'; import { ChatEditingSnapshotTextModelContentProvider } from '../../browser/chatEditing/chatEditingTextModelContentProviders.js'; -import { ModifiedFileEntryState } from '../../common/chatEditingService.js'; +import { ISnapshotEntry, ModifiedFileEntryState } from '../../common/chatEditingService.js'; suite('ChatEditingSessionStorage', () => { const ds = ensureNoDisposablesAreLeakedInTestSuite(); From c5af7e242403bd699f55394fb938258adb2d73e9 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 15:02:25 +0200 Subject: [PATCH 121/236] fix & improve reporting of cyclic dependencies --- build/lib/tsb/builder.js | 27 +++++++++++++-------------- build/lib/tsb/builder.ts | 32 +++++++++++++++----------------- build/lib/tsb/utils.js | 2 +- build/lib/tsb/utils.ts | 6 +++--- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/build/lib/tsb/builder.js b/build/lib/tsb/builder.js index bd363137c15..0f4ea8c5e0b 100644 --- a/build/lib/tsb/builder.js +++ b/build/lib/tsb/builder.js @@ -391,16 +391,18 @@ function createTypeScriptBuilder(config, projectFile, cmd) { const cycles = outHost.getCyclicDependencies(toBeCheckedForCycles); toBeCheckedForCycles.length = 0; for (const [filename, error] of cycles) { - const cycleError = { - category: typescript_1.default.DiagnosticCategory.Error, - code: 1, - file: undefined, - start: undefined, - length: undefined, - messageText: `CYCLIC dependency: ${error}` - }; - onError(cycleError); - newErrors[filename] = [cycleError]; + const cyclicDepErrors = []; + if (error) { + cyclicDepErrors.push({ + category: typescript_1.default.DiagnosticCategory.Error, + code: 1, + file: undefined, + start: undefined, + length: undefined, + messageText: `CYCLIC dependency: ${error}` + }); + } + newErrors[filename] = cyclicDepErrors; } }).then(() => { // store the build versions to not rebuilt the next time @@ -589,13 +591,10 @@ class LanguageServiceHost { while (this._dependenciesRecomputeList.length) { this._processFile(this._dependenciesRecomputeList.pop()); } - const t2 = performance.now(); - console.log(`START CYCLE_CHECK for ${filenames.length} files`); const cycles = this._dependencies.findCycles(filenames); - console.log(`END CYCLE_CHECK after ${performance.now() - t2}ms`); const result = new Map(); for (const [key, value] of cycles) { - result.set(key, value.join(' -> ')); + result.set(key, value?.join(' -> ')); } return result; } diff --git a/build/lib/tsb/builder.ts b/build/lib/tsb/builder.ts index da68e8a1e4e..06c9b9ec24c 100644 --- a/build/lib/tsb/builder.ts +++ b/build/lib/tsb/builder.ts @@ -429,16 +429,18 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str toBeCheckedForCycles.length = 0; for (const [filename, error] of cycles) { - const cycleError: ts.Diagnostic = { - category: ts.DiagnosticCategory.Error, - code: 1, - file: undefined, - start: undefined, - length: undefined, - messageText: `CYCLIC dependency: ${error}` - }; - onError(cycleError); - newErrors[filename] = [cycleError]; + const cyclicDepErrors: ts.Diagnostic[] = []; + if (error) { + cyclicDepErrors.push({ + category: ts.DiagnosticCategory.Error, + code: 1, + file: undefined, + start: undefined, + length: undefined, + messageText: `CYCLIC dependency: ${error}` + }); + } + newErrors[filename] = cyclicDepErrors; } }).then(() => { @@ -662,19 +664,15 @@ class LanguageServiceHost implements ts.LanguageServiceHost { } } - getCyclicDependencies(filenames: string[]): Map { + getCyclicDependencies(filenames: string[]): Map { // Ensure dependencies are up to date while (this._dependenciesRecomputeList.length) { this._processFile(this._dependenciesRecomputeList.pop()!); } - const t2 = performance.now(); - console.log(`START CYCLE_CHECK for ${filenames.length} files`); const cycles = this._dependencies.findCycles(filenames); - console.log(`END CYCLE_CHECK after ${performance.now() - t2}ms`); - - const result = new Map(); + const result = new Map(); for (const [key, value] of cycles) { - result.set(key, value.join(' -> ')); + result.set(key, value?.join(' -> ')); } return result; } diff --git a/build/lib/tsb/utils.js b/build/lib/tsb/utils.js index 28080a9d8df..2ea820c6e6b 100644 --- a/build/lib/tsb/utils.js +++ b/build/lib/tsb/utils.js @@ -63,7 +63,7 @@ var graph; if (!node) { continue; } - const r = this._findCycle(node, checked, new Set()) ?? []; + const r = this._findCycle(node, checked, new Set()); result.set(node.data, r); } return result; diff --git a/build/lib/tsb/utils.ts b/build/lib/tsb/utils.ts index 5a29ebf8f51..16f93d6838f 100644 --- a/build/lib/tsb/utils.ts +++ b/build/lib/tsb/utils.ts @@ -63,15 +63,15 @@ export namespace graph { return this._nodes.get(data) ?? null; } - findCycles(allData: T[]): Map { - const result = new Map(); + findCycles(allData: T[]): Map { + const result = new Map(); const checked = new Set(); for (const data of allData) { const node = this.lookup(data); if (!node) { continue; } - const r = this._findCycle(node, checked, new Set()) ?? []; + const r = this._findCycle(node, checked, new Set()); result.set(node.data, r); } return result; From 9b5cee4c2c20a2c63d372d1cedd6bea30399ac1f Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 15:21:56 +0200 Subject: [PATCH 122/236] fix more cyclic dependencies --- .../chat/browser/chatContentParts/chatCollapsibleContentPart.ts | 2 +- .../chat/browser/chatContentParts/chatReferencesContentPart.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatCollapsibleContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatCollapsibleContentPart.ts index 976b3b74674..d0c6a600bad 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatCollapsibleContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatCollapsibleContentPart.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { $ } from '../../../../../base/browser/dom.js'; import { ButtonWithIcon } from '../../../../../base/browser/ui/button/button.js'; import { Codicon } from '../../../../../base/common/codicons.js'; import { Emitter } from '../../../../../base/common/event.js'; @@ -13,7 +14,6 @@ import { localize } from '../../../../../nls.js'; import { IChatRendererContent } from '../../common/chatViewModel.js'; import { ChatTreeItem } from '../chat.js'; import { IChatContentPart, IChatContentPartRenderContext } from './chatContentParts.js'; -import { $ } from './chatReferencesContentPart.js'; export abstract class ChatCollapsibleContentPart extends Disposable implements IChatContentPart { diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts index 282f80349a8..83ec99a7af8 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts @@ -46,7 +46,7 @@ import { ChatCollapsibleContentPart } from './chatCollapsibleContentPart.js'; import { IDisposableReference, ResourcePool } from './chatCollections.js'; import { IChatContentPartRenderContext } from './chatContentParts.js'; -export const $ = dom.$; +const $ = dom.$; export interface IChatReferenceListItem extends IChatContentReference { title?: string; From 9a7cbdef4d8d85e7db8eae94f8532112f9324947 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 15:38:23 +0200 Subject: [PATCH 123/236] stable cycle reporting --- build/lib/tsb/builder.js | 2 +- build/lib/tsb/builder.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/lib/tsb/builder.js b/build/lib/tsb/builder.js index 0f4ea8c5e0b..1a08badd113 100644 --- a/build/lib/tsb/builder.js +++ b/build/lib/tsb/builder.js @@ -591,7 +591,7 @@ class LanguageServiceHost { while (this._dependenciesRecomputeList.length) { this._processFile(this._dependenciesRecomputeList.pop()); } - const cycles = this._dependencies.findCycles(filenames); + const cycles = this._dependencies.findCycles(filenames.sort((a, b) => a.localeCompare(b))); const result = new Map(); for (const [key, value] of cycles) { result.set(key, value?.join(' -> ')); diff --git a/build/lib/tsb/builder.ts b/build/lib/tsb/builder.ts index 06c9b9ec24c..94fcf1483db 100644 --- a/build/lib/tsb/builder.ts +++ b/build/lib/tsb/builder.ts @@ -669,7 +669,7 @@ class LanguageServiceHost implements ts.LanguageServiceHost { while (this._dependenciesRecomputeList.length) { this._processFile(this._dependenciesRecomputeList.pop()!); } - const cycles = this._dependencies.findCycles(filenames); + const cycles = this._dependencies.findCycles(filenames.sort((a, b) => a.localeCompare(b))); const result = new Map(); for (const [key, value] of cycles) { result.set(key, value?.join(' -> ')); From 68c505b6ffee9845d4cd8d4b6b73ad5ae2c047f2 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 15:38:44 +0200 Subject: [PATCH 124/236] fix cycle with chat attachement widgets --- .../workbench/contrib/chat/browser/chatAttachmentWidgets.ts | 5 +++-- .../browser/chatContentParts/chatAttachmentsContentPart.ts | 5 ----- .../workbench/contrib/chat/browser/chatInlineAnchorWidget.ts | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts index 2eb7abd3f61..6bd7290848e 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts @@ -27,10 +27,9 @@ import { IResourceLabel, ResourceLabels, IFileLabelOptions } from '../../../brow import { revealInSideBarCommand } from '../../files/browser/fileActions.contribution.js'; import { IChatRequestPasteVariableEntry, IChatRequestToolEntry, IChatRequestToolSetEntry, IChatRequestVariableEntry, IElementVariableEntry, INotebookOutputVariableEntry, ISCMHistoryItemVariableEntry, OmittedState } from '../common/chatModel.js'; import { ILanguageModelChatMetadataAndIdentifier, ILanguageModelsService } from '../common/languageModels.js'; -import { chatAttachmentResourceContextKey } from './chatContentParts/chatAttachmentsContentPart.js'; import { KeyCode } from '../../../../base/common/keyCodes.js'; import { basename, dirname } from '../../../../base/common/path.js'; -import { IContextKey, IContextKeyService, IScopedContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService, IScopedContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { IMenuService, MenuId } from '../../../../platform/actions/common/actions.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { INotebookService } from '../../notebook/common/notebookService.js'; @@ -815,3 +814,5 @@ function addBasicContextMenu(accessor: ServicesAccessor, widget: HTMLElement, sc }); }); } + +export const chatAttachmentResourceContextKey = new RawContextKey('chatAttachmentResource', undefined, { type: 'URI', description: localize('resource', "The full value of the chat attachment resource, including scheme and path") }); diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts index ff5fcc3eda6..fa85b63ab26 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts @@ -10,17 +10,12 @@ import { Disposable, DisposableStore } from '../../../../../base/common/lifecycl import { basename } from '../../../../../base/common/path.js'; import { URI } from '../../../../../base/common/uri.js'; import { Range } from '../../../../../editor/common/core/range.js'; -import { localize } from '../../../../../nls.js'; -import { RawContextKey } from '../../../../../platform/contextkey/common/contextkey.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { ResourceLabels } from '../../../../browser/labels.js'; import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry, OmittedState } from '../../common/chatModel.js'; import { ChatResponseReferencePartStatusKind, IChatContentReference } from '../../common/chatService.js'; import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../chatAttachmentWidgets.js'; -export const chatAttachmentResourceContextKey = new RawContextKey('chatAttachmentResource', undefined, { type: 'URI', description: localize('resource', "The full value of the chat attachment resource, including scheme and path") }); - - export class ChatAttachmentsContentPart extends Disposable { private readonly attachedContextDisposables = this._register(new DisposableStore()); diff --git a/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts b/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts index 59f0cc16d5c..db18152a9be 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts @@ -41,8 +41,7 @@ import { ExplorerFolderContext } from '../../files/common/files.js'; import { IWorkspaceSymbol } from '../../search/common/search.js'; import { IChatContentInlineReference } from '../common/chatService.js'; import { IChatWidgetService } from './chat.js'; -import { hookUpSymbolAttachmentDragAndContextMenu } from './chatAttachmentWidgets.js'; -import { chatAttachmentResourceContextKey } from './chatContentParts/chatAttachmentsContentPart.js'; +import { chatAttachmentResourceContextKey, hookUpSymbolAttachmentDragAndContextMenu } from './chatAttachmentWidgets.js'; import { IChatMarkdownAnchorService } from './chatContentParts/chatMarkdownAnchorService.js'; type ContentRefData = From fe53fd206211d8ba815c3f3c43965c30b12b117d Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 15:41:02 +0200 Subject: [PATCH 125/236] fix cycle in treesitter land --- .../treeSitter/treeSitterSyntaxTokenBackend.ts | 15 --------------- .../model/tokens/treeSitter/treeSitterTree.ts | 14 +++++++++++++- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/vs/editor/common/model/tokens/treeSitter/treeSitterSyntaxTokenBackend.ts b/src/vs/editor/common/model/tokens/treeSitter/treeSitterSyntaxTokenBackend.ts index 02f789bce6a..5d61d664043 100644 --- a/src/vs/editor/common/model/tokens/treeSitter/treeSitterSyntaxTokenBackend.ts +++ b/src/vs/editor/common/model/tokens/treeSitter/treeSitterSyntaxTokenBackend.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type * as TreeSitter from '@vscode/tree-sitter-wasm'; import { Emitter, Event } from '../../../../../base/common/event.js'; import { toDisposable } from '../../../../../base/common/lifecycle.js'; import { StandardTokenType } from '../../../encodedTokenAttributes.js'; @@ -196,17 +195,3 @@ export class TreeSitterSyntaxTokenBackend extends AbstractSyntaxTokenBackend { return model.hasTokens(); } } - -export function rangesEqual(a: TreeSitter.Range, b: TreeSitter.Range) { - return (a.startPosition.row === b.startPosition.row) - && (a.startPosition.column === b.startPosition.column) - && (a.endPosition.row === b.endPosition.row) - && (a.endPosition.column === b.endPosition.column) - && (a.startIndex === b.startIndex) - && (a.endIndex === b.endIndex); -} - -export function rangesIntersect(a: TreeSitter.Range, b: TreeSitter.Range) { - return (a.startIndex <= b.startIndex && a.endIndex >= b.startIndex) || - (b.startIndex <= a.startIndex && b.endIndex >= a.startIndex); -} diff --git a/src/vs/editor/common/model/tokens/treeSitter/treeSitterTree.ts b/src/vs/editor/common/model/tokens/treeSitter/treeSitterTree.ts index 2ced0ac10d4..e60618d03d2 100644 --- a/src/vs/editor/common/model/tokens/treeSitter/treeSitterTree.ts +++ b/src/vs/editor/common/model/tokens/treeSitter/treeSitterTree.ts @@ -13,7 +13,6 @@ import { TextLength } from '../../../core/text/textLength.js'; import { IModelContentChangedEvent, IModelContentChange } from '../../../textModelEvents.js'; import { TextModel } from '../../textModel.js'; import { gotoParent, getClosestPreviousNodes, nextSiblingOrParentSibling, gotoNthChild } from './cursorUtils.js'; -import { rangesIntersect, rangesEqual } from './treeSitterSyntaxTokenBackend.js'; import { Range } from '../../../core/range.js'; export class TreeSitterTree extends Disposable { @@ -445,3 +444,16 @@ function newTimeOutProgressCallback(): (state: TreeSitter.ParseState) => void { return false; }; } +export function rangesEqual(a: TreeSitter.Range, b: TreeSitter.Range) { + return (a.startPosition.row === b.startPosition.row) + && (a.startPosition.column === b.startPosition.column) + && (a.endPosition.row === b.endPosition.row) + && (a.endPosition.column === b.endPosition.column) + && (a.startIndex === b.startIndex) + && (a.endIndex === b.endIndex); +} + +export function rangesIntersect(a: TreeSitter.Range, b: TreeSitter.Range) { + return (a.startIndex <= b.startIndex && a.endIndex >= b.startIndex) || + (b.startIndex <= a.startIndex && b.endIndex >= a.startIndex); +} From 8af456f97f1532ed623dee8edff314a05fe121ff Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Jun 2025 16:28:29 +0200 Subject: [PATCH 126/236] chore - "Remove File" and "Clear Working Set" action removal. (#250991) * chore - "Remove File" and "Clear Working Set" action removal. Both are from the time out working set and since a while we have list of modified files so both actions don't make sense anymore * fix compilo --- .../browser/chatEditing/chatEditingActions.ts | 87 ------------------- .../browser/chatEditing/chatEditingSession.ts | 22 ----- .../contrib/chat/browser/chatInputPart.ts | 4 +- .../contrib/chat/common/chatEditingService.ts | 1 - 4 files changed, 2 insertions(+), 112 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts index f50b6b77b57..c1aebb45553 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts @@ -101,58 +101,6 @@ abstract class WorkingSetAction extends EditingSessionAction { abstract runWorkingSetAction(accessor: ServicesAccessor, editingSession: IChatEditingSession, chatWidget: IChatWidget | undefined, ...uris: URI[]): any; } -registerAction2(class RemoveFileFromWorkingSet extends WorkingSetAction { - constructor() { - super({ - id: 'chatEditing.removeFileFromWorkingSet', - title: localize2('removeFileFromWorkingSet', 'Remove File'), - icon: Codicon.close, - precondition: ChatContextKeys.requestInProgress.negate(), - menu: [{ - id: MenuId.ChatEditingWidgetModifiedFilesToolbar, - // when: ContextKeyExpr.or(ContextKeyExpr.equals(chatEditingWidgetFileStateContextKey.key, WorkingSetEntryState.Attached), ContextKeyExpr.equals(chatEditingWidgetFileStateContextKey.key, WorkingSetEntryState.Suggested), ContextKeyExpr.equals(chatEditingWidgetFileStateContextKey.key, WorkingSetEntryState.Transient)), - order: 5, - group: 'navigation' - }], - }); - } - - async runWorkingSetAction(accessor: ServicesAccessor, currentEditingSession: IChatEditingSession, chatWidget: IChatWidget, ...uris: URI[]): Promise { - const dialogService = accessor.get(IDialogService); - - const pendingEntries = currentEditingSession.entries.get().filter((entry) => uris.includes(entry.modifiedURI) && entry.state.get() === ModifiedFileEntryState.Modified); - if (pendingEntries.length > 0) { - // Ask for confirmation if there are any pending edits - const file = pendingEntries.length > 1 - ? localize('chat.editing.removeFile.confirmationmanyFiles', "{0} files", pendingEntries.length) - : basename(pendingEntries[0].modifiedURI); - const confirmation = await dialogService.confirm({ - title: localize('chat.editing.removeFile.confirmation.title', "Remove {0} from working set?", file), - message: localize('chat.editing.removeFile.confirmation.message', "This will remove {0} from your working set and undo the edits made to it. Do you want to proceed?", file), - primaryButton: localize('chat.editing.removeFile.confirmation.primaryButton', "Yes"), - type: 'info' - }); - if (!confirmation.confirmed) { - return; - } - } - - // Remove from working set - await currentEditingSession.reject(...uris); - currentEditingSession.remove(...uris); - - // Remove from chat input part - for (const uri of uris) { - chatWidget.attachmentModel.delete(uri.toString()); - } - - // Clear all related file suggestions - if (chatWidget.attachmentModel.fileAttachments.length === 0) { - chatWidget.input.relatedFiles?.clear(); - } - } -}); - registerAction2(class OpenFileInDiffAction extends WorkingSetAction { constructor() { super({ @@ -328,41 +276,6 @@ export async function discardAllEditsWithConfirmation(accessor: ServicesAccessor return true; } -// TODO@roblourens this may be obsolete? -export class ChatEditingRemoveAllFilesAction extends EditingSessionAction { - static readonly ID = 'chatEditing.clearWorkingSet'; - - constructor() { - super({ - id: ChatEditingRemoveAllFilesAction.ID, - title: localize('clearWorkingSet', 'Clear Working Set'), - icon: Codicon.clearAll, - tooltip: localize('clearWorkingSet', 'Clear Working Set'), - precondition: ContextKeyExpr.and(ChatContextKeys.requestInProgress.negate()), - menu: [ - { - id: MenuId.ChatEditingWidgetToolbar, - group: 'navigation', - order: 5, - when: hasAppliedChatEditsContextKey.negate() - } - ] - }); - } - - override async runEditingSessionAction(accessor: ServicesAccessor, editingSession: IChatEditingSession, chatWidget: IChatWidget, ...args: any[]): Promise { - // Remove all files from working set - const uris = [...editingSession.entries.get()].map((e) => e.modifiedURI); - editingSession.remove(...uris); - - // Remove all file attachments - const fileAttachments = chatWidget.attachmentModel ? chatWidget.attachmentModel.fileAttachments : []; - const attachmentIdsToRemove = fileAttachments.map(attachment => attachment.toString()); - chatWidget.attachmentModel.delete(...attachmentIdsToRemove); - } -} -registerAction2(ChatEditingRemoveAllFilesAction); - export class ChatEditingShowChangesAction extends EditingSessionAction { static readonly ID = 'chatEditing.viewChanges'; static readonly LABEL = localize('chatEditing.viewChanges', 'View All Edits'); diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts index b78e1f354de..c41d8026148 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts @@ -529,28 +529,6 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio this._entriesObs.set(entriesArr, undefined); } - remove(...uris: URI[]): void { - this._assertNotDisposed(); - - let didRemoveUris = false; - for (const uri of uris) { - - const entry = this._entriesObs.get().find(e => isEqual(e.modifiedURI, uri)); - if (entry) { - entry.dispose(); - const newEntries = this._entriesObs.get().filter(e => !isEqual(e.modifiedURI, uri)); - this._entriesObs.set(newEntries, undefined); - didRemoveUris = true; - } - - } - - if (!didRemoveUris) { - return; // noop - } - - } - private _assertNotDisposed(): void { if (this._state.get() === ChatEditingSessionState.Disposed) { throw new BugIndicatingError(`Cannot access a disposed editing session`); diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 9caa28e5b2a..d93c620c611 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -93,7 +93,7 @@ import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmen import { IDisposableReference } from './chatContentParts/chatCollections.js'; import { CollapsibleListPool, IChatCollapsibleListItem } from './chatContentParts/chatReferencesContentPart.js'; import { ChatDragAndDrop } from './chatDragAndDrop.js'; -import { ChatEditingRemoveAllFilesAction, ChatEditingShowChangesAction, ViewPreviousEditsAction } from './chatEditing/chatEditingActions.js'; +import { ChatEditingShowChangesAction, ViewPreviousEditsAction } from './chatEditing/chatEditingActions.js'; import { ChatFollowups } from './chatFollowups.js'; import { ChatSelectedTools } from './chatSelectedTools.js'; import { IChatViewState } from './chatWidget.js'; @@ -1493,7 +1493,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge arg: { sessionId: chatEditingSession.chatSessionId }, }, buttonConfigProvider: (action) => { - if (action.id === ChatEditingShowChangesAction.ID || action.id === ChatEditingRemoveAllFilesAction.ID || action.id === ViewPreviousEditsAction.Id) { + if (action.id === ChatEditingShowChangesAction.ID || action.id === ViewPreviousEditsAction.Id) { return { showIcon: true, showLabel: false, isSecondary: true }; } return undefined; diff --git a/src/vs/workbench/contrib/chat/common/chatEditingService.ts b/src/vs/workbench/contrib/chat/common/chatEditingService.ts index 4bf57eee5b5..cf1f0161b1a 100644 --- a/src/vs/workbench/contrib/chat/common/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/common/chatEditingService.ts @@ -86,7 +86,6 @@ export interface IChatEditingSession extends IDisposable { readonly state: IObservable; readonly entries: IObservable; show(previousChanges?: boolean): Promise; - remove(...uris: URI[]): void; accept(...uris: URI[]): Promise; reject(...uris: URI[]): Promise; getEntry(uri: URI): IModifiedFileEntry | undefined; From a3beb7acb9b42b4dcbb6bd5e332fecd02a5d8868 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 9 Jun 2025 16:43:01 +0200 Subject: [PATCH 127/236] debt - ensure to remove listeners --- src/vs/code/browser/workbench/workbench.ts | 5 ++-- .../browser/stickyScrollController.ts | 18 ++++---------- .../browser/accessibilitySignalService.ts | 24 +++++++++++++------ .../browser/extensionFeaturesTab.ts | 8 +++---- .../testing/browser/testingDecorations.ts | 4 ++-- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 3928342a049..f9ee35ab370 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { isStandalone } from '../../../base/browser/browser.js'; +import { addDisposableListener } from '../../../base/browser/dom.js'; import { mainWindow } from '../../../base/browser/window.js'; import { VSBuffer, decodeBase64, encodeBase64 } from '../../../base/common/buffer.js'; import { Emitter } from '../../../base/common/event.js'; @@ -340,9 +341,7 @@ class LocalStorageURLCallbackProvider extends Disposable implements IURLCallback return; } - const fn = () => this.onDidChangeLocalStorage(); - mainWindow.addEventListener('storage', fn); - this.onDidChangeLocalStorageDisposable = { dispose: () => mainWindow.removeEventListener('storage', fn) }; + this.onDidChangeLocalStorageDisposable = addDisposableListener(mainWindow, 'storage', () => this.onDidChangeLocalStorage()); } private stopListening(): void { diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts index 9f443e037d6..736492e7292 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts @@ -310,26 +310,18 @@ export class StickyScrollController extends Disposable implements IEditorContrib } this._revealPosition(position); })); - const mouseMoveListener = (mouseEvent: MouseEvent) => { + this._register(dom.addDisposableListener(mainWindow, dom.EventType.MOUSE_MOVE, mouseEvent => { this._mouseTarget = mouseEvent.target; this._onMouseMoveOrKeyDown(mouseEvent); - }; - const keyDownListener = (mouseEvent: KeyboardEvent) => { + })); + this._register(dom.addDisposableListener(mainWindow, dom.EventType.KEY_DOWN, mouseEvent => { this._onMouseMoveOrKeyDown(mouseEvent); - }; - const keyUpListener = (e: KeyboardEvent) => { + })); + this._register(dom.addDisposableListener(mainWindow, dom.EventType.KEY_UP, () => { if (this._showEndForLine !== undefined) { this._showEndForLine = undefined; this._renderStickyScroll(); } - }; - mainWindow.addEventListener(dom.EventType.MOUSE_MOVE, mouseMoveListener); - mainWindow.addEventListener(dom.EventType.KEY_DOWN, keyDownListener); - mainWindow.addEventListener(dom.EventType.KEY_UP, keyUpListener); - this._register(toDisposable(() => { - mainWindow.removeEventListener(dom.EventType.MOUSE_MOVE, mouseMoveListener); - mainWindow.removeEventListener(dom.EventType.KEY_DOWN, keyDownListener); - mainWindow.removeEventListener(dom.EventType.KEY_UP, keyUpListener); })); this._register(gesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, _keyboardEvent]) => { diff --git a/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts b/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts index e4382f461f8..8bc11939b10 100644 --- a/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts +++ b/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { addDisposableListener } from '../../../base/browser/dom.js'; import { CachedFunction } from '../../../base/common/cache.js'; import { getStructuralKey } from '../../../base/common/equals.js'; import { Event, IValueWithChangeEvent } from '../../../base/common/event.js'; -import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../base/common/lifecycle.js'; import { FileAccess } from '../../../base/common/network.js'; import { derived, observableFromEvent, ValueWithChangeEventFromObservable } from '../../../base/common/observable.js'; import { localize } from '../../../nls.js'; @@ -277,17 +278,26 @@ function checkEnabledState(state: EnabledState, getScreenReaderAttached: () => b * Play the given audio url. * @volume value between 0 and 1 */ -function playAudio(url: string, volume: number): Promise { - return new Promise((resolve, reject) => { +async function playAudio(url: string, volume: number): Promise { + const disposables = new DisposableStore(); + try { + return await doPlayAudio(url, volume, disposables); + } finally { + disposables.dispose(); + } +} + +function doPlayAudio(url: string, volume: number, disposables: DisposableStore): Promise { + return new Promise((resolve, reject) => { const audio = new Audio(url); audio.volume = volume; - audio.addEventListener('ended', () => { + disposables.add(addDisposableListener(audio, 'ended', () => { resolve(audio); - }); - audio.addEventListener('error', (e) => { + })); + disposables.add(addDisposableListener(audio, 'error', (e) => { // When the error event fires, ended might not be called reject(e.error); - }); + })); audio.play().catch(e => { // When play fails, the error event is not fired. reject(e); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts b/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts index bcef6a198c0..0b7daf56e12 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; -import { $, append, clearNode } from '../../../../base/browser/dom.js'; +import { $, append, clearNode, addDisposableListener, EventType } from '../../../../base/browser/dom.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { ExtensionIdentifier, IExtensionManifest } from '../../../../platform/extensions/common/extensions.js'; import { Orientation, Sizing, SplitView } from '../../../../base/browser/ui/splitview/splitview.js'; @@ -304,15 +304,13 @@ class RuntimeStatusMarkdownRenderer extends Disposable implements IExtensionFeat hoverDisposable.value = undefined; } }; - svg.addEventListener('mousemove', mouseMoveListener); - disposables.add(toDisposable(() => svg.removeEventListener('mousemove', mouseMoveListener))); + disposables.add(addDisposableListener(svg, EventType.MOUSE_MOVE, mouseMoveListener)); const mouseLeaveListener = () => { highlightCircle.style.display = 'none'; hoverDisposable.value = undefined; }; - svg.addEventListener('mouseleave', mouseLeaveListener); - disposables.add(toDisposable(() => svg.removeEventListener('mouseleave', mouseLeaveListener))); + disposables.add(addDisposableListener(svg, EventType.MOUSE_LEAVE, mouseLeaveListener)); } } diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index ac47408247d..cac9d9f09d0 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -1387,10 +1387,10 @@ class TestErrorContentWidget extends Disposable implements IContentWidget { text = lf === -1 ? msg : msg.slice(0, lf); } - this.node.root.addEventListener('click', e => { + this._register(dom.addDisposableListener(this.node.root, dom.EventType.CLICK, e => { this.peekOpener.peekUri(uri); e.preventDefault(); - }); + })); const ctrl = TestingOutputPeekController.get(editor); if (ctrl) { From 1a2bacb0a084e24d673884a6fb8734d68f124abe Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Jun 2025 17:23:22 +0200 Subject: [PATCH 128/236] make sure the API doesn't allow to set an empty selections array (#251010) re https://github.com/microsoft/vscode-copilot/issues/18075 --- .../src/singlefolder-tests/editor.test.ts | 15 +++++++++++++++ src/vs/workbench/api/common/extHostTextEditor.ts | 3 +++ 2 files changed, 18 insertions(+) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts index 106ef702d69..e2105f2e017 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts @@ -295,4 +295,19 @@ suite('vscode API - editors', () => { assert.strictEqual(document.getText(), Buffer.from(await workspace.fs.readFile(file)).toString()); } + + test('extEditor.selection can be empty #18075', async function () { + await withRandomFileEditor('foo', async editor => { + + assert.ok(editor.selections.length > 0); + + editor.selections = []; + + assert.strictEqual(editor.selections.length, 1); + assert.strictEqual(editor.selections[0].start.line, 0); + assert.strictEqual(editor.selections[0].start.character, 0); + assert.strictEqual(editor.selections[0].end.line, 0); + assert.strictEqual(editor.selections[0].end.character, 0); + }); + }); }); diff --git a/src/vs/workbench/api/common/extHostTextEditor.ts b/src/vs/workbench/api/common/extHostTextEditor.ts index 86a322348a8..b523bf14a82 100644 --- a/src/vs/workbench/api/common/extHostTextEditor.ts +++ b/src/vs/workbench/api/common/extHostTextEditor.ts @@ -456,6 +456,9 @@ export class ExtHostTextEditor { if (!Array.isArray(value) || value.some(a => !(a instanceof Selection))) { throw illegalArgument('selections'); } + if (value.length === 0) { + value = [new Selection(0, 0, 0, 0)]; + } that._selections = value; that._trySetSelection(); }, From 1ab154c86679593cf944ed7dd8cce01cf5c14bf7 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Jun 2025 09:47:11 -0700 Subject: [PATCH 129/236] break variable entries into their own file for model/parserTypes cycle --- .../api/common/extHostTypeConverters.ts | 2 +- .../chat/browser/actions/chatContext.ts | 2 +- .../browser/actions/chatContextActions.ts | 2 +- .../attachments/implicitContextAttachment.ts | 2 +- .../chat/browser/chatAttachmentModel.ts | 2 +- .../chatPromptAttachmentsCollection.ts | 12 +- .../chat/browser/chatAttachmentResolve.ts | 3 +- .../chat/browser/chatAttachmentWidgets.ts | 2 +- .../chatAttachmentsContentPart.ts | 2 +- .../chatToolInputOutputContentPart.ts | 3 +- .../chat/browser/chatContextPickService.ts | 2 +- .../contrib/chat/browser/chatDragAndDrop.ts | 2 +- .../chatEditing/simpleBrowserEditorOverlay.ts | 2 +- .../contrib/chat/browser/chatInputPart.ts | 2 +- .../contrib/chat/browser/chatListRenderer.ts | 3 +- .../chat/browser/chatPasteProviders.ts | 2 +- .../contrib/chat/browser/chatSetup.ts | 3 +- .../contrib/chat/browser/chatWidget.ts | 3 +- .../browser/contrib/chatImplicitContext.ts | 2 +- .../browser/contrib/chatInputCompletions.ts | 3 +- .../chat/browser/contrib/screenshot.ts | 2 +- .../promptSyntax/attachInstructionsAction.ts | 2 +- .../contrib/chat/common/chatModel.ts | 254 +---------------- .../contrib/chat/common/chatParserTypes.ts | 2 +- .../contrib/chat/common/chatService.ts | 3 +- .../contrib/chat/common/chatServiceImpl.ts | 3 +- .../chat/common/chatVariableEntries.ts | 263 ++++++++++++++++++ .../contrib/chat/common/chatVariables.ts | 3 +- .../contrib/chat/common/chatViewModel.ts | 3 +- .../chat/common/chatWidgetHistoryService.ts | 2 +- .../browser/inlineChatController.ts | 3 +- .../markers/browser/markersChatContext.ts | 2 +- .../mcp/browser/mcpResourceQuickAccess.ts | 2 +- .../browser/contrib/chat/notebookChatUtils.ts | 2 +- .../scm/browser/scmHistoryChatContext.ts | 2 +- .../search/browser/chatContributions.ts | 2 +- 36 files changed, 316 insertions(+), 290 deletions(-) create mode 100644 src/vs/workbench/contrib/chat/common/chatVariableEntries.ts diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index be99e78a443..3677a226a47 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -41,7 +41,7 @@ import { DEFAULT_EDITOR_ASSOCIATION, SaveReason } from '../../common/editor.js'; import { IViewBadge } from '../../common/views.js'; import { IChatAgentRequest, IChatAgentResult } from '../../contrib/chat/common/chatAgents.js'; import { IChatRequestDraft } from '../../contrib/chat/common/chatEditingService.js'; -import { IChatRequestVariableEntry, isImageVariableEntry } from '../../contrib/chat/common/chatModel.js'; +import { IChatRequestVariableEntry, isImageVariableEntry } from '../../contrib/chat/common/chatVariableEntries.js'; import { IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatExtensionsContent, IChatFollowup, IChatMarkdownContent, IChatMoveMessage, IChatPrepareToolInvocationPart, IChatProgressMessage, IChatResponseCodeblockUriPart, IChatTaskDto, IChatTaskResult, IChatTextEdit, IChatTreeData, IChatUserActionEvent, IChatWarningMessage } from '../../contrib/chat/common/chatService.js'; import { IToolData, IToolResult } from '../../contrib/chat/common/languageModelToolsService.js'; import * as chatProvider from '../../contrib/chat/common/languageModels.js'; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts index 24391e9596d..1e32fa1041a 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContext.ts @@ -23,7 +23,7 @@ import { FileEditorInput } from '../../../files/browser/editors/fileEditorInput. import { NotebookEditorInput } from '../../../notebook/common/notebookEditorInput.js'; import { IChatContextPickService, IChatContextValueItem, IChatContextPickerItem, IChatContextPickerPickItem } from '../chatContextPickService.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { IChatRequestToolEntry, IChatRequestToolSetEntry, IChatRequestVariableEntry, IImageVariableEntry, OmittedState } from '../../common/chatModel.js'; +import { IChatRequestToolEntry, IChatRequestToolSetEntry, IChatRequestVariableEntry, IImageVariableEntry, OmittedState } from '../../common/chatVariableEntries.js'; import { IToolData, ToolDataSource, ToolSet } from '../../common/languageModelToolsService.js'; import { IChatWidget } from '../chat.js'; import { imageToHash, isImage } from '../chatPasteProviders.js'; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index ec16a17ef53..8100a6e6cfd 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -37,7 +37,7 @@ import { isSearchTreeFileMatch, isSearchTreeMatch } from '../../../search/browse import { ISymbolQuickPickItem, SymbolsQuickAccessProvider } from '../../../search/browser/symbolsQuickAccess.js'; import { SearchContext } from '../../../search/common/constants.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; -import { IChatRequestVariableEntry, OmittedState } from '../../common/chatModel.js'; +import { IChatRequestVariableEntry, OmittedState } from '../../common/chatVariableEntries.js'; import { ChatAgentLocation } from '../../common/constants.js'; import { IChatWidget, IChatWidgetService, IQuickChatService, showChatView } from '../chat.js'; import { IChatContextPickerItem, IChatContextPickService, IChatContextValueItem, isChatContextPickerPickItem } from '../chatContextPickService.js'; diff --git a/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts b/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts index e23f62baf59..c4e5e14c583 100644 --- a/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts +++ b/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts @@ -24,7 +24,7 @@ import { FileKind, IFileService } from '../../../../../platform/files/common/fil import { ILabelService } from '../../../../../platform/label/common/label.js'; import { ResourceLabels } from '../../../../browser/labels.js'; import { ResourceContextKey } from '../../../../common/contextkeys.js'; -import { IChatRequestImplicitVariableEntry } from '../../common/chatModel.js'; +import { IChatRequestImplicitVariableEntry } from '../../common/chatVariableEntries.js'; import { IChatWidgetService } from '../chat.js'; import { ChatAttachmentModel } from '../chatAttachmentModel.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts index abec2fdf5eb..4ee4a59ea99 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts @@ -8,7 +8,7 @@ import { Emitter } from '../../../../base/common/event.js'; import { basename } from '../../../../base/common/resources.js'; import { IRange } from '../../../../editor/common/core/range.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; -import { IChatRequestFileEntry, IChatRequestVariableEntry } from '../common/chatModel.js'; +import { IChatRequestFileEntry, IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ChatPromptAttachmentsCollection } from './chatAttachmentModel/chatPromptAttachmentsCollection.js'; import { IFileService } from '../../../../platform/files/common/files.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts index bab83dc9130..1732ee9508a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts @@ -3,16 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from '../../../../../base/common/uri.js'; import { Emitter } from '../../../../../base/common/event.js'; +import { Disposable, DisposableMap } from '../../../../../base/common/lifecycle.js'; import { basename, isEqual } from '../../../../../base/common/resources.js'; -import { ChatPromptAttachmentModel } from './chatPromptAttachmentModel.js'; +import { URI } from '../../../../../base/common/uri.js'; +import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; +import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; +import { IChatRequestVariableEntry, IPromptVariableEntry, isChatRequestFileEntry } from '../../common/chatVariableEntries.js'; import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IPromptFileReference } from '../../common/promptSyntax/parsers/types.js'; -import { Disposable, DisposableMap } from '../../../../../base/common/lifecycle.js'; -import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; -import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; -import { IChatRequestVariableEntry, IPromptVariableEntry, isChatRequestFileEntry } from '../../common/chatModel.js'; +import { ChatPromptAttachmentModel } from './chatPromptAttachmentModel.js'; /** * Prefix for all prompt instruction variable IDs. diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts index 87338b0e95c..934e20d3c5e 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts @@ -24,7 +24,8 @@ import { UntitledTextEditorInput } from '../../../services/untitled/common/untit import { createNotebookOutputVariableEntry, NOTEBOOK_CELL_OUTPUT_MIME_TYPE_LIST_FOR_CHAT_CONST } from '../../notebook/browser/contrib/chat/notebookChatUtils.js'; import { getOutputViewModelFromId } from '../../notebook/browser/controller/cellOutputActions.js'; import { getNotebookEditorFromEditorPane } from '../../notebook/browser/notebookBrowser.js'; -import { CHAT_ATTACHABLE_IMAGE_MIME_TYPES, getAttachableImageExtension, IChatRequestVariableEntry, IDiagnosticVariableEntry, IDiagnosticVariableEntryFilterData, ISymbolVariableEntry, OmittedState } from '../common/chatModel.js'; +import { CHAT_ATTACHABLE_IMAGE_MIME_TYPES, getAttachableImageExtension } from '../common/chatModel.js'; +import { IChatRequestVariableEntry, OmittedState, IDiagnosticVariableEntry, IDiagnosticVariableEntryFilterData, ISymbolVariableEntry } from '../common/chatVariableEntries.js'; import { imageToHash } from './chatPasteProviders.js'; import { resizeImage } from './imageUtils.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts index 6bd7290848e..eb6be7eaaf0 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts @@ -25,7 +25,7 @@ import { IOpenerService, OpenInternalOptions } from '../../../../platform/opener import { IThemeService, FolderThemeIcon } from '../../../../platform/theme/common/themeService.js'; import { IResourceLabel, ResourceLabels, IFileLabelOptions } from '../../../browser/labels.js'; import { revealInSideBarCommand } from '../../files/browser/fileActions.contribution.js'; -import { IChatRequestPasteVariableEntry, IChatRequestToolEntry, IChatRequestToolSetEntry, IChatRequestVariableEntry, IElementVariableEntry, INotebookOutputVariableEntry, ISCMHistoryItemVariableEntry, OmittedState } from '../common/chatModel.js'; +import { IChatRequestPasteVariableEntry, IChatRequestToolEntry, IChatRequestToolSetEntry, IChatRequestVariableEntry, IElementVariableEntry, INotebookOutputVariableEntry, ISCMHistoryItemVariableEntry, OmittedState } from '../common/chatVariableEntries.js'; import { ILanguageModelChatMetadataAndIdentifier, ILanguageModelsService } from '../common/languageModels.js'; import { KeyCode } from '../../../../base/common/keyCodes.js'; import { basename, dirname } from '../../../../base/common/path.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts index fa85b63ab26..3482a2296c2 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts @@ -12,7 +12,7 @@ import { URI } from '../../../../../base/common/uri.js'; import { Range } from '../../../../../editor/common/core/range.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { ResourceLabels } from '../../../../browser/labels.js'; -import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry, OmittedState } from '../../common/chatModel.js'; +import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry, OmittedState } from '../../common/chatVariableEntries.js'; import { ChatResponseReferencePartStatusKind, IChatContentReference } from '../../common/chatService.js'; import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../chatAttachmentWidgets.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInputOutputContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInputOutputContentPart.ts index ffc765e7940..873796c8a59 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInputOutputContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInputOutputContentPart.ts @@ -31,7 +31,8 @@ import { INotificationService } from '../../../../../platform/notification/commo import { IProgressService, ProgressLocation } from '../../../../../platform/progress/common/progress.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; import { REVEAL_IN_EXPLORER_COMMAND_ID } from '../../../files/browser/fileConstants.js'; -import { getAttachableImageExtension, IChatRequestVariableEntry } from '../../common/chatModel.js'; +import { getAttachableImageExtension } from '../../common/chatModel.js'; +import { IChatRequestVariableEntry } from '../../common/chatVariableEntries.js'; import { IChatRendererContent } from '../../common/chatViewModel.js'; import { ChatTreeItem, IChatCodeBlockInfo } from '../chat.js'; import { CodeBlockPart, ICodeBlockData, ICodeBlockRenderOptions } from '../codeBlockPart.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatContextPickService.ts b/src/vs/workbench/contrib/chat/browser/chatContextPickService.ts index 9220bee6f48..fc478c46c38 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContextPickService.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContextPickService.ts @@ -10,7 +10,7 @@ import { ThemeIcon } from '../../../../base/common/themables.js'; import { isObject } from '../../../../base/common/types.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { IQuickPickSeparator } from '../../../../platform/quickinput/common/quickInput.js'; -import { IChatRequestVariableEntry } from '../common/chatModel.js'; +import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; import { IChatWidget } from './chat.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts b/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts index e3f054946e5..bd7d0d9a249 100644 --- a/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts +++ b/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts @@ -23,7 +23,7 @@ import { IThemeService, Themable } from '../../../../platform/theme/common/theme import { ISharedWebContentExtractorService } from '../../../../platform/webContentExtractor/common/webContentExtractor.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { IExtensionService, isProposedApiEnabled } from '../../../services/extensions/common/extensions.js'; -import { IChatRequestVariableEntry } from '../common/chatModel.js'; +import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; import { IChatWidgetService } from './chat.js'; import { ImageTransferData, resolveEditorAttachContext, resolveImageAttachContext, resolveMarkerAttachContext, resolveNotebookOutputAttachContext, resolveSymbolsAttachContext } from './chatAttachmentResolve.js'; import { ChatAttachmentModel } from './chatAttachmentModel.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/simpleBrowserEditorOverlay.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/simpleBrowserEditorOverlay.ts index 5ba3da96625..5015b2af65c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/simpleBrowserEditorOverlay.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/simpleBrowserEditorOverlay.ts @@ -31,7 +31,7 @@ import { IFileService } from '../../../../../platform/files/common/files.js'; import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js'; import { URI } from '../../../../../base/common/uri.js'; import { ILogService } from '../../../../../platform/log/common/log.js'; -import { IChatRequestVariableEntry } from '../../common/chatModel.js'; +import { IChatRequestVariableEntry } from '../../common/chatVariableEntries.js'; import { IPreferencesService } from '../../../../services/preferences/common/preferences.js'; import { IBrowserElementsService } from '../../../../services/browserElements/browser/browserElementsService.js'; import { IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 9caa28e5b2a..b923b333c78 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -75,7 +75,7 @@ import { IChatAgentService } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { IChatEditingSession } from '../common/chatEditingService.js'; import { ChatEntitlement, IChatEntitlementService } from '../common/chatEntitlementService.js'; -import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry } from '../common/chatModel.js'; +import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry } from '../common/chatVariableEntries.js'; import { ChatMode2, IChatMode, IChatModeService, isBuiltinChatMode, validateChatMode2 } from '../common/chatModes.js'; import { IChatFollowup } from '../common/chatService.js'; import { IChatVariablesService } from '../common/chatVariables.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 68378263466..280a613236c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -47,7 +47,7 @@ import { annotateSpecialMarkdownContent } from '../common/annotations.js'; import { checkModeOption } from '../common/chat.js'; import { IChatAgentMetadata } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; -import { IChatRequestVariableEntry, IChatTextEditGroup } from '../common/chatModel.js'; +import { IChatTextEditGroup } from '../common/chatModel.js'; import { chatSubcommandLeader } from '../common/chatParserTypes.js'; import { ChatAgentVoteDirection, ChatAgentVoteDownReason, ChatErrorLevel, IChatConfirmation, IChatContentReference, IChatExtensionsContent, IChatFollowup, IChatMarkdownContent, IChatTask, IChatTaskSerialized, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop } from '../common/chatService.js'; import { IChatCodeCitations, IChatErrorDetailsPart, IChatReferences, IChatRendererContent, IChatRequestViewModel, IChatResponseViewModel, IChatWorkingProgress, isRequestVM, isResponseVM } from '../common/chatViewModel.js'; @@ -79,6 +79,7 @@ import { ChatMarkdownRenderer } from './chatMarkdownRenderer.js'; import { ChatEditorOptions } from './chatOptions.js'; import { ChatCodeBlockContentProvider, CodeBlockPart } from './codeBlockPart.js'; import { canceledName } from '../../../../base/common/errors.js'; +import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; const $ = dom.$; diff --git a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts index 6bdd4a6067f..eef54ec9891 100644 --- a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts +++ b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts @@ -22,7 +22,7 @@ import { IFileService } from '../../../../platform/files/common/files.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { IExtensionService, isProposedApiEnabled } from '../../../services/extensions/common/extensions.js'; -import { IChatRequestPasteVariableEntry, IChatRequestVariableEntry } from '../common/chatModel.js'; +import { IChatRequestPasteVariableEntry, IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; import { IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js'; import { IChatWidgetService } from './chat.js'; import { ChatInputPart } from './chatInputPart.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup.ts b/src/vs/workbench/contrib/chat/browser/chatSetup.ts index 0883840ff6f..1b504e9e195 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup.ts @@ -58,7 +58,8 @@ import { IExtensionsWorkbenchService } from '../../extensions/common/extensions. import { IChatAgentImplementation, IChatAgentRequest, IChatAgentResult, IChatAgentService } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { ChatEntitlement, ChatEntitlementContext, ChatEntitlementRequests, ChatEntitlementService, IChatEntitlementService, isProUser } from '../common/chatEntitlementService.js'; -import { ChatModel, ChatRequestModel, IChatRequestModel, IChatRequestToolEntry, IChatRequestVariableData } from '../common/chatModel.js'; +import { ChatModel, ChatRequestModel, IChatRequestModel, IChatRequestVariableData } from '../common/chatModel.js'; +import { IChatRequestToolEntry } from '../common/chatVariableEntries.js'; import { ChatRequestAgentPart, ChatRequestToolPart } from '../common/chatParserTypes.js'; import { IChatProgress, IChatService } from '../common/chatService.js'; import { ChatAgentLocation, ChatConfiguration, ChatMode, validateChatMode } from '../common/constants.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 727ae4db8e3..d24c33e180a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -43,7 +43,7 @@ import { checkModeOption } from '../common/chat.js'; import { IChatAgentCommand, IChatAgentData, IChatAgentService, IChatWelcomeMessageContent } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { applyingChatEditsFailedContextKey, decidedChatEditingResourceContextKey, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, inChatEditingSessionContextKey, ModifiedFileEntryState } from '../common/chatEditingService.js'; -import { ChatPauseState, IChatModel, IChatRequestVariableEntry, IChatResponseModel } from '../common/chatModel.js'; +import { ChatPauseState, IChatModel, IChatResponseModel } from '../common/chatModel.js'; import { chatAgentLeader, ChatRequestAgentPart, ChatRequestDynamicVariablePart, ChatRequestSlashPromptPart, ChatRequestToolPart, ChatRequestToolSetPart, chatSubcommandLeader, formatChatQuestion, IParsedChatRequest } from '../common/chatParserTypes.js'; import { ChatRequestParser } from '../common/chatRequestParser.js'; import { IChatLocationData, IChatSendRequestOptions, IChatService } from '../common/chatService.js'; @@ -68,6 +68,7 @@ import './media/chatAgentHover.css'; import './media/chatViewWelcome.css'; import { ChatViewWelcomePart } from './viewsWelcome/chatViewWelcomeController.js'; import { MicrotaskDelay } from '../../../../base/common/symbols.js'; +import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; const $ = dom.$; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts index 15e36a441f6..1d570246e68 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts @@ -21,7 +21,7 @@ import { EditorsOrder } from '../../../../common/editor.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { getNotebookEditorFromEditorPane, INotebookEditor } from '../../../notebook/browser/notebookBrowser.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { IChatRequestFileEntry, IChatRequestImplicitVariableEntry } from '../../common/chatModel.js'; +import { IChatRequestFileEntry, IChatRequestImplicitVariableEntry } from '../../common/chatVariableEntries.js'; import { IChatService } from '../../common/chatService.js'; import { ChatAgentLocation } from '../../common/constants.js'; import { ILanguageModelIgnoredFilesService } from '../../common/ignoredFiles.js'; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts index 04d8f730e70..f3dec9be600 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts @@ -46,9 +46,10 @@ import { IMcpPrompt, IMcpPromptMessage, IMcpServer, IMcpService, McpResourceURI import { searchFilesAndFolders } from '../../../search/browser/chatContributions.js'; import { IChatAgentData, IChatAgentNameService, IChatAgentService, getFullyQualifiedId } from '../../common/chatAgents.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { getAttachableImageExtension, IChatRequestVariableEntry } from '../../common/chatModel.js'; +import { getAttachableImageExtension } from '../../common/chatModel.js'; import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashPromptPart, ChatRequestTextPart, ChatRequestToolPart, ChatRequestToolSetPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from '../../common/chatParserTypes.js'; import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; +import { IChatRequestVariableEntry } from '../../common/chatVariableEntries.js'; import { IDynamicVariable } from '../../common/chatVariables.js'; import { ChatAgentLocation, ChatMode } from '../../common/constants.js'; import { ToolSet } from '../../common/languageModelToolsService.js'; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts b/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts index f030477d0df..8e18015fc20 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts @@ -5,7 +5,7 @@ import { VSBuffer } from '../../../../../base/common/buffer.js'; import { localize } from '../../../../../nls.js'; -import { IChatRequestVariableEntry } from '../../common/chatModel.js'; +import { IChatRequestVariableEntry } from '../../common/chatVariableEntries.js'; export const ScreenshotVariableId = 'screenshot-focused-window'; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts index 17839752416..d7ec82126ac 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts @@ -24,7 +24,7 @@ import { INSTRUCTIONS_LANGUAGE_ID, PromptsType } from '../../common/promptSyntax import { compare } from '../../../../../base/common/strings.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; import { dirname } from '../../../../../base/common/resources.js'; -import { IPromptFileVariableEntry } from '../../common/chatModel.js'; +import { IPromptFileVariableEntry } from '../../common/chatVariableEntries.js'; import { KeyMod, KeyCode } from '../../../../../base/common/keyCodes.js'; import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 1512b137bfc..4acb8302d77 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { asArray } from '../../../../base/common/arrays.js'; -import { Codicon } from '../../../../base/common/codicons.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { IMarkdownString, MarkdownString, isMarkdownString } from '../../../../base/common/htmlContent.js'; import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js'; @@ -18,265 +17,18 @@ import { ThemeIcon } from '../../../../base/common/themables.js'; import { URI, UriComponents, UriDto, isUriComponents } from '../../../../base/common/uri.js'; import { generateUuid } from '../../../../base/common/uuid.js'; import { IRange } from '../../../../editor/common/core/range.js'; -import { IOffsetRange, OffsetRange } from '../../../../editor/common/core/ranges/offsetRange.js'; -import { Location, SymbolKind, TextEdit, isLocation } from '../../../../editor/common/languages.js'; +import { OffsetRange } from '../../../../editor/common/core/ranges/offsetRange.js'; +import { TextEdit } from '../../../../editor/common/languages.js'; import { localize } from '../../../../nls.js'; import { ILogService } from '../../../../platform/log/common/log.js'; -import { IMarker, MarkerSeverity } from '../../../../platform/markers/common/markers.js'; import { CellUri, ICellEditOperation } from '../../notebook/common/notebookCommon.js'; -import { ISCMHistoryItem } from '../../scm/common/history.js'; import { IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, reviveSerializedAgent } from './chatAgents.js'; import { IChatEditingService, IChatEditingSession } from './chatEditingService.js'; import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js'; import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatNotebookEdit, IChatPrepareToolInvocationPart, IChatProgress, IChatProgressMessage, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTaskSerialized, IChatTextEdit, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js'; -import { IChatRequestVariableValue } from './chatVariables.js'; +import { IChatRequestVariableEntry } from './chatVariableEntries.js'; import { ChatAgentLocation, ChatMode } from './constants.js'; -interface IBaseChatRequestVariableEntry { - readonly id: string; - readonly fullName?: string; - readonly icon?: ThemeIcon; - readonly name: string; - readonly modelDescription?: string; - - /** - * The offset-range in the prompt. This means this entry has been explicitly typed out - * by the user. - */ - readonly range?: IOffsetRange; - readonly value: IChatRequestVariableValue; - readonly references?: IChatContentReference[]; - - omittedState?: OmittedState; -} - -export interface IGenericChatRequestVariableEntry extends IBaseChatRequestVariableEntry { - kind: 'generic'; -} - -export interface IChatRequestDirectoryEntry extends IBaseChatRequestVariableEntry { - kind: 'directory'; -} - -export interface IChatRequestFileEntry extends IBaseChatRequestVariableEntry { - kind: 'file'; -} - -export const enum OmittedState { - NotOmitted, - Partial, - Full, -} - -export interface IChatRequestToolEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'tool'; -} - -export interface IChatRequestToolSetEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'toolset'; - readonly value: IChatRequestToolEntry[]; -} - -export interface IChatRequestImplicitVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'implicit'; - readonly isFile: true; - readonly value: URI | Location | undefined; - readonly isSelection: boolean; - readonly isPromptFile: boolean; - readonly enabled: boolean; -} - -export interface IChatRequestPasteVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'paste'; - readonly code: string; - readonly language: string; - readonly pastedLines: string; - - // This is only used for old serialized data and should be removed once we no longer support it - readonly fileName: string; - - // This is only undefined on old serialized data - readonly copiedFrom: { - readonly uri: URI; - readonly range: IRange; - } | undefined; -} - -export interface ISymbolVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'symbol'; - readonly value: Location; - readonly symbolKind: SymbolKind; -} - -export interface ICommandResultVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'command'; -} - -export interface IImageVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'image'; - readonly isPasted?: boolean; - readonly isURL?: boolean; - readonly mimeType?: string; -} - -export interface INotebookOutputVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'notebookOutput'; - readonly outputIndex?: number; - readonly mimeType?: string; -} - -export interface IDiagnosticVariableEntryFilterData { - readonly owner?: string; - readonly problemMessage?: string; - readonly filterUri?: URI; - readonly filterSeverity?: MarkerSeverity; - readonly filterRange?: IRange; -} - -/** - * Chat variable that represents an attached prompt file. - */ -export interface IPromptVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'file'; - readonly value: URI | Location; - readonly isRoot: boolean; - readonly modelDescription: string; -} - -export namespace IDiagnosticVariableEntryFilterData { - export const icon = Codicon.error; - - export function fromMarker(marker: IMarker): IDiagnosticVariableEntryFilterData { - return { - filterUri: marker.resource, - owner: marker.owner, - problemMessage: marker.message, - filterRange: { startLineNumber: marker.startLineNumber, endLineNumber: marker.endLineNumber, startColumn: marker.startColumn, endColumn: marker.endColumn } - }; - } - - export function toEntry(data: IDiagnosticVariableEntryFilterData): IDiagnosticVariableEntry { - return { - id: id(data), - name: label(data), - icon, - value: data, - kind: 'diagnostic', - ...data, - }; - } - - export function id(data: IDiagnosticVariableEntryFilterData) { - return [data.filterUri, data.owner, data.filterSeverity, data.filterRange?.startLineNumber].join(':'); - } - - export function label(data: IDiagnosticVariableEntryFilterData) { - const enum TrimThreshold { - MaxChars = 30, - MaxSpaceLookback = 10, - } - if (data.problemMessage) { - if (data.problemMessage.length < TrimThreshold.MaxChars) { - return data.problemMessage; - } - - // Trim the message, on a space if it would not lose too much - // data (MaxSpaceLookback) or just blindly otherwise. - const lastSpace = data.problemMessage.lastIndexOf(' ', TrimThreshold.MaxChars); - if (lastSpace === -1 || lastSpace + TrimThreshold.MaxSpaceLookback < TrimThreshold.MaxChars) { - return data.problemMessage.substring(0, TrimThreshold.MaxChars) + '…'; - } - return data.problemMessage.substring(0, lastSpace) + '…'; - } - let labelStr = localize('chat.attachment.problems.all', "All Problems"); - if (data.filterUri) { - labelStr = localize('chat.attachment.problems.inFile', "Problems in {0}", basename(data.filterUri)); - } - - return labelStr; - } -} - -export interface IDiagnosticVariableEntry extends IBaseChatRequestVariableEntry, IDiagnosticVariableEntryFilterData { - readonly kind: 'diagnostic'; -} - -export interface IElementVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'element'; -} - -export interface IPromptFileVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'promptFile'; -} - -export interface ISCMHistoryItemVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'scmHistoryItem'; - readonly value: URI; - readonly historyItem: ISCMHistoryItem; -} - -export type IChatRequestVariableEntry = IGenericChatRequestVariableEntry | IChatRequestImplicitVariableEntry | IChatRequestPasteVariableEntry - | ISymbolVariableEntry | ICommandResultVariableEntry | IDiagnosticVariableEntry | IImageVariableEntry - | IChatRequestToolEntry | IChatRequestToolSetEntry - | IChatRequestDirectoryEntry | IChatRequestFileEntry | INotebookOutputVariableEntry | IElementVariableEntry - | IPromptFileVariableEntry | ISCMHistoryItemVariableEntry; - - -export namespace IChatRequestVariableEntry { - - /** - * Returns URI of the passed variant entry. Return undefined if not found. - */ - export function toUri(entry: IChatRequestVariableEntry): URI | undefined { - return URI.isUri(entry.value) - ? entry.value - : isLocation(entry.value) - ? entry.value.uri - : undefined; - } -} - - -export function isImplicitVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestImplicitVariableEntry { - return obj.kind === 'implicit'; -} - -export function isPasteVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestPasteVariableEntry { - return obj.kind === 'paste'; -} - -export function isImageVariableEntry(obj: IChatRequestVariableEntry): obj is IImageVariableEntry { - return obj.kind === 'image'; -} - -export function isNotebookOutputVariableEntry(obj: IChatRequestVariableEntry): obj is INotebookOutputVariableEntry { - return obj.kind === 'notebookOutput'; -} - -export function isElementVariableEntry(obj: IChatRequestVariableEntry): obj is IElementVariableEntry { - return obj.kind === 'element'; -} - -export function isDiagnosticsVariableEntry(obj: IChatRequestVariableEntry): obj is IDiagnosticVariableEntry { - return obj.kind === 'diagnostic'; -} - -export function isChatRequestFileEntry(obj: IChatRequestVariableEntry): obj is IChatRequestFileEntry { - return obj.kind === 'file'; -} - -export function isChatRequestVariableEntry(obj: unknown): obj is IChatRequestVariableEntry { - const entry = obj as IChatRequestVariableEntry; - return typeof entry === 'object' && - entry !== null && - typeof entry.id === 'string' && - typeof entry.name === 'string'; -} - -export function isSCMHistoryItemVariableEntry(obj: IChatRequestVariableEntry): obj is ISCMHistoryItemVariableEntry { - return obj.kind === 'scmHistoryItem'; -} - export const CHAT_ATTACHABLE_IMAGE_MIME_TYPES: Record = { png: 'image/png', diff --git a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts index d53289147c7..fefa954edf1 100644 --- a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts @@ -8,12 +8,12 @@ import { ThemeIcon } from '../../../../base/common/themables.js'; import { IOffsetRange, OffsetRange } from '../../../../editor/common/core/ranges/offsetRange.js'; import { IRange } from '../../../../editor/common/core/range.js'; import { IChatAgentCommand, IChatAgentData, IChatAgentService, reviveSerializedAgent } from './chatAgents.js'; -import { IChatRequestToolEntry, IChatRequestToolSetEntry, IChatRequestVariableEntry, IDiagnosticVariableEntryFilterData } from './chatModel.js'; import { IChatSlashData } from './chatSlashCommands.js'; import { IChatRequestProblemsVariable, IChatRequestVariableValue } from './chatVariables.js'; import { ChatAgentLocation } from './constants.js'; import { IToolData } from './languageModelToolsService.js'; import { IChatPromptSlashCommand } from './promptSyntax/service/promptsService.js'; +import { IChatRequestToolEntry, IChatRequestToolSetEntry, IChatRequestVariableEntry, IDiagnosticVariableEntryFilterData } from './chatVariableEntries.js'; // These are in a separate file to avoid circular dependencies with the dependencies of the parser diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 60c1f5d8684..fd1c29a7a04 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -18,9 +18,10 @@ import { createDecorator } from '../../../../platform/instantiation/common/insta import { ICellEditOperation } from '../../notebook/common/notebookCommon.js'; import { IWorkspaceSymbol } from '../../search/common/search.js'; import { IChatAgentCommand, IChatAgentData, IChatAgentResult } from './chatAgents.js'; -import { ChatModel, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatRequestVariableEntry, IChatResponseModel, IExportableChatData, ISerializableChatData } from './chatModel.js'; +import { ChatModel, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData } from './chatModel.js'; import { IParsedChatRequest } from './chatParserTypes.js'; import { IChatParserContext } from './chatRequestParser.js'; +import { IChatRequestVariableEntry } from './chatVariableEntries.js'; import { IChatRequestVariableValue } from './chatVariables.js'; import { ChatAgentLocation, ChatMode } from './constants.js'; import { IPreparedToolInvocation, IToolConfirmationMessages, IToolResult } from './languageModelToolsService.js'; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 3be67300df2..cec924742db 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -27,7 +27,7 @@ import { IWorkspaceContextService } from '../../../../platform/workspace/common/ import { IWorkbenchAssignmentService } from '../../../services/assignment/common/assignmentService.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; import { IChatAgent, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService } from './chatAgents.js'; -import { ChatModel, ChatRequestModel, ChatRequestRemovalReason, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatRequestVariableEntry, IChatResponseModel, IExportableChatData, ISerializableChatData, ISerializableChatDataIn, ISerializableChatsData, isImageVariableEntry, normalizeSerializableChatData, toChatHistoryContent, updateRanges } from './chatModel.js'; +import { ChatModel, ChatRequestModel, ChatRequestRemovalReason, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData, ISerializableChatDataIn, ISerializableChatsData, normalizeSerializableChatData, toChatHistoryContent, updateRanges } from './chatModel.js'; import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, IParsedChatRequest, chatAgentLeader, chatSubcommandLeader, getPromptText } from './chatParserTypes.js'; import { ChatRequestParser } from './chatRequestParser.js'; import { IChatCompleteResponse, IChatDetail, IChatFollowup, IChatProgress, IChatSendRequestData, IChatSendRequestOptions, IChatSendRequestResponseState, IChatService, IChatTransferredSessionData, IChatUserActionEvent } from './chatService.js'; @@ -35,6 +35,7 @@ import { ChatServiceTelemetry } from './chatServiceTelemetry.js'; import { ChatSessionStore, IChatTransfer2 } from './chatSessionStore.js'; import { IChatSlashCommandService } from './chatSlashCommands.js'; import { IChatTransferService } from './chatTransferService.js'; +import { IChatRequestVariableEntry, isImageVariableEntry } from './chatVariableEntries.js'; import { ChatAgentLocation, ChatConfiguration, ChatMode } from './constants.js'; import { ChatMessageRole, IChatMessage, ILanguageModelsService } from './languageModels.js'; import { ILanguageModelToolsService } from './languageModelToolsService.js'; diff --git a/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts b/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts new file mode 100644 index 00000000000..cd26353e890 --- /dev/null +++ b/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts @@ -0,0 +1,263 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Codicon } from '../../../../base/common/codicons.js'; +import { basename } from '../../../../base/common/resources.js'; +import { ThemeIcon } from '../../../../base/common/themables.js'; +import { URI } from '../../../../base/common/uri.js'; +import { IRange } from '../../../../editor/common/core/range.js'; +import { IOffsetRange } from '../../../../editor/common/core/ranges/offsetRange.js'; +import { isLocation, Location, SymbolKind } from '../../../../editor/common/languages.js'; +import { localize } from '../../../../nls.js'; +import { MarkerSeverity, IMarker } from '../../../../platform/markers/common/markers.js'; +import { ISCMHistoryItem } from '../../scm/common/history.js'; +import { IChatContentReference } from './chatService.js'; +import { IChatRequestVariableValue } from './chatVariables.js'; + + +interface IBaseChatRequestVariableEntry { + readonly id: string; + readonly fullName?: string; + readonly icon?: ThemeIcon; + readonly name: string; + readonly modelDescription?: string; + + /** + * The offset-range in the prompt. This means this entry has been explicitly typed out + * by the user. + */ + readonly range?: IOffsetRange; + readonly value: IChatRequestVariableValue; + readonly references?: IChatContentReference[]; + + omittedState?: OmittedState; +} + +export interface IGenericChatRequestVariableEntry extends IBaseChatRequestVariableEntry { + kind: 'generic'; +} + +export interface IChatRequestDirectoryEntry extends IBaseChatRequestVariableEntry { + kind: 'directory'; +} + +export interface IChatRequestFileEntry extends IBaseChatRequestVariableEntry { + kind: 'file'; +} + +export const enum OmittedState { + NotOmitted, + Partial, + Full, +} + +export interface IChatRequestToolEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'tool'; +} + +export interface IChatRequestToolSetEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'toolset'; + readonly value: IChatRequestToolEntry[]; +} + +export interface IChatRequestImplicitVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'implicit'; + readonly isFile: true; + readonly value: URI | Location | undefined; + readonly isSelection: boolean; + readonly isPromptFile: boolean; + readonly enabled: boolean; +} + +export interface IChatRequestPasteVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'paste'; + readonly code: string; + readonly language: string; + readonly pastedLines: string; + + // This is only used for old serialized data and should be removed once we no longer support it + readonly fileName: string; + + // This is only undefined on old serialized data + readonly copiedFrom: { + readonly uri: URI; + readonly range: IRange; + } | undefined; +} + +export interface ISymbolVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'symbol'; + readonly value: Location; + readonly symbolKind: SymbolKind; +} + +export interface ICommandResultVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'command'; +} + +export interface IImageVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'image'; + readonly isPasted?: boolean; + readonly isURL?: boolean; + readonly mimeType?: string; +} + +export interface INotebookOutputVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'notebookOutput'; + readonly outputIndex?: number; + readonly mimeType?: string; +} + +export interface IDiagnosticVariableEntryFilterData { + readonly owner?: string; + readonly problemMessage?: string; + readonly filterUri?: URI; + readonly filterSeverity?: MarkerSeverity; + readonly filterRange?: IRange; +} + +/** + * Chat variable that represents an attached prompt file. + */ +export interface IPromptVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'file'; + readonly value: URI | Location; + readonly isRoot: boolean; + readonly modelDescription: string; +} + +export namespace IDiagnosticVariableEntryFilterData { + export const icon = Codicon.error; + + export function fromMarker(marker: IMarker): IDiagnosticVariableEntryFilterData { + return { + filterUri: marker.resource, + owner: marker.owner, + problemMessage: marker.message, + filterRange: { startLineNumber: marker.startLineNumber, endLineNumber: marker.endLineNumber, startColumn: marker.startColumn, endColumn: marker.endColumn } + }; + } + + export function toEntry(data: IDiagnosticVariableEntryFilterData): IDiagnosticVariableEntry { + return { + id: id(data), + name: label(data), + icon, + value: data, + kind: 'diagnostic', + ...data, + }; + } + + export function id(data: IDiagnosticVariableEntryFilterData) { + return [data.filterUri, data.owner, data.filterSeverity, data.filterRange?.startLineNumber].join(':'); + } + + export function label(data: IDiagnosticVariableEntryFilterData) { + const enum TrimThreshold { + MaxChars = 30, + MaxSpaceLookback = 10, + } + if (data.problemMessage) { + if (data.problemMessage.length < TrimThreshold.MaxChars) { + return data.problemMessage; + } + + // Trim the message, on a space if it would not lose too much + // data (MaxSpaceLookback) or just blindly otherwise. + const lastSpace = data.problemMessage.lastIndexOf(' ', TrimThreshold.MaxChars); + if (lastSpace === -1 || lastSpace + TrimThreshold.MaxSpaceLookback < TrimThreshold.MaxChars) { + return data.problemMessage.substring(0, TrimThreshold.MaxChars) + '…'; + } + return data.problemMessage.substring(0, lastSpace) + '…'; + } + let labelStr = localize('chat.attachment.problems.all', "All Problems"); + if (data.filterUri) { + labelStr = localize('chat.attachment.problems.inFile', "Problems in {0}", basename(data.filterUri)); + } + + return labelStr; + } +} + +export interface IDiagnosticVariableEntry extends IBaseChatRequestVariableEntry, IDiagnosticVariableEntryFilterData { + readonly kind: 'diagnostic'; +} + +export interface IElementVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'element'; +} + +export interface IPromptFileVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'promptFile'; +} + +export interface ISCMHistoryItemVariableEntry extends IBaseChatRequestVariableEntry { + readonly kind: 'scmHistoryItem'; + readonly value: URI; + readonly historyItem: ISCMHistoryItem; +} + +export type IChatRequestVariableEntry = IGenericChatRequestVariableEntry | IChatRequestImplicitVariableEntry | IChatRequestPasteVariableEntry + | ISymbolVariableEntry | ICommandResultVariableEntry | IDiagnosticVariableEntry | IImageVariableEntry + | IChatRequestToolEntry | IChatRequestToolSetEntry + | IChatRequestDirectoryEntry | IChatRequestFileEntry | INotebookOutputVariableEntry | IElementVariableEntry + | IPromptFileVariableEntry | ISCMHistoryItemVariableEntry; + + +export namespace IChatRequestVariableEntry { + + /** + * Returns URI of the passed variant entry. Return undefined if not found. + */ + export function toUri(entry: IChatRequestVariableEntry): URI | undefined { + return URI.isUri(entry.value) + ? entry.value + : isLocation(entry.value) + ? entry.value.uri + : undefined; + } +} + + +export function isImplicitVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestImplicitVariableEntry { + return obj.kind === 'implicit'; +} + +export function isPasteVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestPasteVariableEntry { + return obj.kind === 'paste'; +} + +export function isImageVariableEntry(obj: IChatRequestVariableEntry): obj is IImageVariableEntry { + return obj.kind === 'image'; +} + +export function isNotebookOutputVariableEntry(obj: IChatRequestVariableEntry): obj is INotebookOutputVariableEntry { + return obj.kind === 'notebookOutput'; +} + +export function isElementVariableEntry(obj: IChatRequestVariableEntry): obj is IElementVariableEntry { + return obj.kind === 'element'; +} + +export function isDiagnosticsVariableEntry(obj: IChatRequestVariableEntry): obj is IDiagnosticVariableEntry { + return obj.kind === 'diagnostic'; +} + +export function isChatRequestFileEntry(obj: IChatRequestVariableEntry): obj is IChatRequestFileEntry { + return obj.kind === 'file'; +} + +export function isChatRequestVariableEntry(obj: unknown): obj is IChatRequestVariableEntry { + const entry = obj as IChatRequestVariableEntry; + return typeof entry === 'object' && + entry !== null && + typeof entry.id === 'string' && + typeof entry.name === 'string'; +} + +export function isSCMHistoryItemVariableEntry(obj: IChatRequestVariableEntry): obj is ISCMHistoryItemVariableEntry { + return obj.kind === 'scmHistoryItem'; +} diff --git a/src/vs/workbench/contrib/chat/common/chatVariables.ts b/src/vs/workbench/contrib/chat/common/chatVariables.ts index 93bbd3f343d..d1b1a554ea8 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariables.ts @@ -9,8 +9,9 @@ import { URI } from '../../../../base/common/uri.js'; import { IRange } from '../../../../editor/common/core/range.js'; import { Location } from '../../../../editor/common/languages.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; -import { IChatModel, IDiagnosticVariableEntryFilterData } from './chatModel.js'; +import { IChatModel } from './chatModel.js'; import { IChatContentReference, IChatProgressMessage } from './chatService.js'; +import { IDiagnosticVariableEntryFilterData } from './chatVariableEntries.js'; import { IToolData, ToolSet } from './languageModelToolsService.js'; export interface IChatVariableData { diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index a23e12b24cb..3ab1a20efe0 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -15,7 +15,8 @@ import { IInstantiationService } from '../../../../platform/instantiation/common import { ILogService } from '../../../../platform/log/common/log.js'; import { annotateVulnerabilitiesInText } from './annotations.js'; import { getFullyQualifiedId, IChatAgentCommand, IChatAgentData, IChatAgentNameService, IChatAgentResult } from './chatAgents.js'; -import { ChatPauseState, IChatModel, IChatProgressRenderableResponseContent, IChatRequestDisablement, IChatRequestModel, IChatRequestVariableEntry, IChatResponseModel, IChatTextEditGroup, IResponse } from './chatModel.js'; +import { ChatPauseState, IChatModel, IChatProgressRenderableResponseContent, IChatRequestDisablement, IChatRequestModel, IChatResponseModel, IChatTextEditGroup, IResponse } from './chatModel.js'; +import { IChatRequestVariableEntry } from './chatVariableEntries.js'; import { IParsedChatRequest } from './chatParserTypes.js'; import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatCodeCitation, IChatContentReference, IChatFollowup, IChatProgressMessage, IChatResponseErrorDetails, IChatTask, IChatUsedContext } from './chatService.js'; import { countWords } from './chatWordCounter.js'; diff --git a/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts b/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts index 9386d7f3f46..ac2590f8388 100644 --- a/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts +++ b/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts @@ -9,7 +9,7 @@ import { createDecorator } from '../../../../platform/instantiation/common/insta import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { Memento } from '../../../common/memento.js'; import { ModifiedFileEntryState } from './chatEditingService.js'; -import { IChatRequestVariableEntry } from './chatModel.js'; +import { IChatRequestVariableEntry } from './chatVariableEntries.js'; import { IChatMode } from './chatModes.js'; import { CHAT_PROVIDER_ID } from './chatParticipantContribTypes.js'; import { ChatAgentLocation, ChatMode } from './constants.js'; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 9ae4a8b1bda..b12fb8d7b14 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -43,7 +43,8 @@ import { IEditorService, SIDE_GROUP } from '../../../services/editor/common/edit import { IViewsService } from '../../../services/views/common/viewsService.js'; import { showChatView } from '../../chat/browser/chat.js'; import { IChatWidgetLocationOptions } from '../../chat/browser/chatWidget.js'; -import { ChatModel, ChatRequestRemovalReason, IChatRequestModel, IChatRequestVariableEntry, IChatTextEditGroup, IChatTextEditGroupState, IResponse } from '../../chat/common/chatModel.js'; +import { ChatModel, ChatRequestRemovalReason, IChatRequestModel, IChatTextEditGroup, IChatTextEditGroupState, IResponse } from '../../chat/common/chatModel.js'; +import { IChatRequestVariableEntry } from '../../chat/common/chatVariableEntries.js'; import { IChatService } from '../../chat/common/chatService.js'; import { INotebookEditorService } from '../../notebook/browser/services/notebookEditorService.js'; import { CTX_INLINE_CHAT_EDITING, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, CTX_INLINE_CHAT_VISIBLE, INLINE_CHAT_ID, InlineChatConfigKeys, InlineChatResponseType } from '../common/inlineChat.js'; diff --git a/src/vs/workbench/contrib/markers/browser/markersChatContext.ts b/src/vs/workbench/contrib/markers/browser/markersChatContext.ts index 83bff8daa8c..204c19c4f62 100644 --- a/src/vs/workbench/contrib/markers/browser/markersChatContext.ts +++ b/src/vs/workbench/contrib/markers/browser/markersChatContext.ts @@ -15,7 +15,7 @@ import { IMarkerService, MarkerSeverity } from '../../../../platform/markers/com import { IQuickPickSeparator } from '../../../../platform/quickinput/common/quickInput.js'; import { IWorkbenchContribution } from '../../../common/contributions.js'; import { IChatContextPickerItem, IChatContextPickerPickItem, IChatContextPickService } from '../../chat/browser/chatContextPickService.js'; -import { IDiagnosticVariableEntryFilterData } from '../../chat/common/chatModel.js'; +import { IDiagnosticVariableEntryFilterData } from '../../chat/common/chatVariableEntries.js'; class MarkerChatContextPick implements IChatContextPickerItem { diff --git a/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts b/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts index d844736de57..55bb13b8526 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts @@ -23,7 +23,7 @@ import { IEditorService } from '../../../services/editor/common/editorService.js import { IViewsService } from '../../../services/views/common/viewsService.js'; import { IChatWidgetService } from '../../chat/browser/chat.js'; import { resolveImageEditorAttachContext } from '../../chat/browser/chatAttachmentResolve.js'; -import { IChatRequestVariableEntry } from '../../chat/common/chatModel.js'; +import { IChatRequestVariableEntry } from '../../chat/common/chatVariableEntries.js'; import { IMcpResource, IMcpResourceTemplate, IMcpServer, IMcpService, isMcpResourceTemplate, McpCapability, McpConnectionState, McpResourceURI } from '../common/mcpTypes.js'; import { IUriTemplateVariable } from '../common/uriTemplate.js'; import { openPanelChatAndGetWidget } from './mcpCommands.js'; diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/chat/notebookChatUtils.ts b/src/vs/workbench/contrib/notebook/browser/contrib/chat/notebookChatUtils.ts index 69f25f754e6..c67c5f4ad7a 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/chat/notebookChatUtils.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/chat/notebookChatUtils.ts @@ -7,7 +7,7 @@ import { normalizeDriveLetter } from '../../../../../../base/common/labels.js'; import { basenameOrAuthority } from '../../../../../../base/common/resources.js'; import { ThemeIcon } from '../../../../../../base/common/themables.js'; import { localize } from '../../../../../../nls.js'; -import { INotebookOutputVariableEntry } from '../../../../chat/common/chatModel.js'; +import { INotebookOutputVariableEntry } from '../../../../chat/common/chatVariableEntries.js'; import { CellUri } from '../../../common/notebookCommon.js'; import { ICellOutputViewModel, INotebookEditor } from '../../notebookBrowser.js'; diff --git a/src/vs/workbench/contrib/scm/browser/scmHistoryChatContext.ts b/src/vs/workbench/contrib/scm/browser/scmHistoryChatContext.ts index 9de801b4541..7a2c3ab47f5 100644 --- a/src/vs/workbench/contrib/scm/browser/scmHistoryChatContext.ts +++ b/src/vs/workbench/contrib/scm/browser/scmHistoryChatContext.ts @@ -22,7 +22,7 @@ import { IViewsService } from '../../../services/views/common/viewsService.js'; import { IChatWidget, showChatView } from '../../chat/browser/chat.js'; import { IChatContextPickerItem, IChatContextPickerPickItem, IChatContextPickService, picksWithPromiseFn } from '../../chat/browser/chatContextPickService.js'; import { ChatContextKeys } from '../../chat/common/chatContextKeys.js'; -import { ISCMHistoryItemVariableEntry } from '../../chat/common/chatModel.js'; +import { ISCMHistoryItemVariableEntry } from '../../chat/common/chatVariableEntries.js'; import { ScmHistoryItemResolver } from '../../multiDiffEditor/browser/scmMultiDiffSourceResolver.js'; import { ISCMHistoryItem } from '../common/history.js'; import { ISCMProvider, ISCMService, ISCMViewService } from '../common/scm.js'; diff --git a/src/vs/workbench/contrib/search/browser/chatContributions.ts b/src/vs/workbench/contrib/search/browser/chatContributions.ts index 3a039e6d339..2e8aa007859 100644 --- a/src/vs/workbench/contrib/search/browser/chatContributions.ts +++ b/src/vs/workbench/contrib/search/browser/chatContributions.ts @@ -14,7 +14,7 @@ import { IWorkbenchContribution } from '../../../common/contributions.js'; import { getExcludes, IFileQuery, ISearchComplete, ISearchConfiguration, ISearchService, QueryType, VIEW_ID } from '../../../services/search/common/search.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; import { IChatContextPickerItem, IChatContextPickerPickItem, IChatContextPickService, IChatContextValueItem, picksWithPromiseFn } from '../../chat/browser/chatContextPickService.js'; -import { IChatRequestVariableEntry, ISymbolVariableEntry } from '../../chat/common/chatModel.js'; +import { IChatRequestVariableEntry, ISymbolVariableEntry } from '../../chat/common/chatVariableEntries.js'; import { SearchContext } from '../common/constants.js'; import { SearchView } from './searchView.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; From 63911265ebc7af68d28927d41e60c03b9fd919df Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Jun 2025 09:48:47 -0700 Subject: [PATCH 130/236] break mcp/tool picker cycle --- .../contrib/chat/browser/actions/chatToolPicker.ts | 3 ++- src/vs/workbench/contrib/mcp/browser/mcpCommands.ts | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts b/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts index 8206f1c2585..94877ee1e3a 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts @@ -18,6 +18,7 @@ import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSepara import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { IExtensionsWorkbenchService } from '../../../extensions/common/extensions.js'; import { AddConfigurationAction } from '../../../mcp/browser/mcpCommands.js'; +import { McpCommandIds } from '../../../mcp/common/mcpCommandIds.js'; import { IMcpRegistry } from '../../../mcp/common/mcpRegistryTypes.js'; import { IMcpServer, IMcpService, McpConnectionState } from '../../../mcp/common/mcpTypes.js'; import { IToolData, ToolSet, ToolDataSource, ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; @@ -86,7 +87,7 @@ export async function showToolsPicker( picked: false, }; - const addMcpPick: CallbackPick = { type: 'item', label: localize('addServer', "Add MCP Server..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false, run: () => commandService.executeCommand(AddConfigurationAction.ID) }; + const addMcpPick: CallbackPick = { type: 'item', label: localize('addServer', "Add MCP Server..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false, run: () => commandService.executeCommand(McpCommandIds.AddConfiguration) }; const configureToolSetsPick: CallbackPick = { type: 'item', label: localize('configToolSet', "Configure Tool Sets..."), iconClass: ThemeIcon.asClassName(Codicon.gear), pickable: false, run: () => commandService.executeCommand(ConfigureToolSets.ID) }; const addExpPick: CallbackPick = { type: 'item', label: localize('addExtension', "Install Extension..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false, run: () => extensionWorkbenchService.openSearch('@tag:language-model-tools') }; const addPick: CallbackPick = { diff --git a/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts b/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts index abf4f085d66..9598b0307e3 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts @@ -135,7 +135,7 @@ export class ListMcpServerCommand extends Action2 { if (!picked) { // no-op } else if (picked.id === '$add') { - commandService.executeCommand(AddConfigurationAction.ID); + commandService.executeCommand(McpCommandIds.AddConfiguration); } else { commandService.executeCommand(McpCommandIds.ServerOptions, picked.id); } @@ -454,11 +454,9 @@ export class ResetMcpCachedTools extends Action2 { } export class AddConfigurationAction extends Action2 { - static readonly ID = 'workbench.mcp.addConfiguration'; - constructor() { super({ - id: AddConfigurationAction.ID, + id: McpCommandIds.AddConfiguration, title: localize2('mcp.addConfiguration', "Add Server..."), metadata: { description: localize2('mcp.addConfiguration.description', "Installs a new Model Context protocol to the mcp.json settings"), From 59635563ffa5bee683fb5ec8f05d5e6d6a292ac0 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Jun 2025 09:49:09 -0700 Subject: [PATCH 131/236] break mcp/tool picker cycle --- .../workbench/contrib/chat/browser/actions/chatToolPicker.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts b/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts index 94877ee1e3a..112327bde07 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts @@ -17,11 +17,10 @@ import { ServicesAccessor } from '../../../../../platform/instantiation/common/i import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { IExtensionsWorkbenchService } from '../../../extensions/common/extensions.js'; -import { AddConfigurationAction } from '../../../mcp/browser/mcpCommands.js'; import { McpCommandIds } from '../../../mcp/common/mcpCommandIds.js'; import { IMcpRegistry } from '../../../mcp/common/mcpRegistryTypes.js'; import { IMcpServer, IMcpService, McpConnectionState } from '../../../mcp/common/mcpTypes.js'; -import { IToolData, ToolSet, ToolDataSource, ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; +import { ILanguageModelToolsService, IToolData, ToolDataSource, ToolSet } from '../../common/languageModelToolsService.js'; import { ConfigureToolSets } from '../tools/toolSetsContribution.js'; From 762dd6a6d2b8a2b6e90717e15856699bf60dbd8c Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Jun 2025 10:07:51 -0700 Subject: [PATCH 132/236] tmp relocate --- src/vs/workbench/contrib/chat/browser/chat.contribution.ts | 5 ++++- .../contrib/chat/browser/contrib/chatDynamicVariables.ts | 7 ++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index be5215d19e5..a2e6e603038 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -96,7 +96,7 @@ import { ChatResponseAccessibleView } from './chatResponseAccessibleView.js'; import { ChatSetupContribution } from './chatSetup.js'; import { ChatStatusBarEntry } from './chatStatus.js'; import { ChatVariablesService } from './chatVariables.js'; -import { ChatWidgetService } from './chatWidget.js'; +import { ChatWidget, ChatWidgetService } from './chatWidget.js'; import { ChatCodeBlockContextProviderService } from './codeBlockContextProviderService.js'; import { ChatImplicitContextContribution } from './contrib/chatImplicitContext.js'; import './contrib/chatInputCompletions.js'; @@ -110,6 +110,7 @@ import product from '../../../../platform/product/common/product.js'; import { ChatModeService, IChatModeService } from '../common/chatModes.js'; import { ChatResponseResourceFileSystemProvider } from '../common/chatResponseResourceFileSystemProvider.js'; import { runSaveToPromptAction, SAVE_TO_PROMPT_SLASH_COMMAND_NAME } from './promptSyntax/saveToPromptAction.js'; +import { ChatDynamicVariableModel } from './contrib/chatDynamicVariables.js'; // Register configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -765,3 +766,5 @@ registerPromptFileContributions(); registerWorkbenchContribution2(UserToolSetsContributions.ID, UserToolSetsContributions, WorkbenchPhase.Eventually); registerAction2(ConfigureToolSets); + +ChatWidget.CONTRIBS.push(ChatDynamicVariableModel); diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts index 3fafbb4cbc0..476653ffe4f 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts @@ -15,10 +15,10 @@ import { ICommandService } from '../../../../../platform/commands/common/command import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; -import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IChatRequestVariableValue, IDynamicVariable } from '../../common/chatVariables.js'; +import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IChatWidget } from '../chat.js'; -import { ChatWidget, IChatWidgetContrib } from '../chatWidget.js'; +import { IChatWidgetContrib } from '../chatWidget.js'; import { ChatFileReference } from './chatDynamicVariables/chatFileReference.js'; export const dynamicVariableDecorationType = 'chat-dynamic-variable'; @@ -221,9 +221,6 @@ function isDynamicVariable(obj: any): obj is IDynamicVariable { 'data' in obj; } -ChatWidget.CONTRIBS.push(ChatDynamicVariableModel); - - export interface IAddDynamicVariableContext { From 7c3bb3adbabdee15e25b52eccc97fac8301eacef Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 19:22:50 +0200 Subject: [PATCH 133/236] fix cyclic dependency in scmHistory fyi @lszomoru --- .../contrib/scm/browser/scmHistory.ts | 29 +++++++++++++++++- src/vs/workbench/contrib/scm/browser/util.ts | 30 +------------------ 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/scmHistory.ts b/src/vs/workbench/contrib/scm/browser/scmHistory.ts index 7a6e840155a..71faef70db0 100644 --- a/src/vs/workbench/contrib/scm/browser/scmHistory.ts +++ b/src/vs/workbench/contrib/scm/browser/scmHistory.ts @@ -10,7 +10,6 @@ import { asCssVariable, ColorIdentifier, registerColor } from '../../../../platf import { ISCMHistoryItem, ISCMHistoryItemGraphNode, ISCMHistoryItemRef, ISCMHistoryItemViewModel } from '../common/history.js'; import { rot } from '../../../../base/common/numbers.js'; import { svgElem } from '../../../../base/browser/dom.js'; -import { compareHistoryItemRefs } from './util.js'; export const SWIMLANE_HEIGHT = 22; export const SWIMLANE_WIDTH = 11; @@ -365,3 +364,31 @@ export function getHistoryItemIndex(historyItemViewModel: ISCMHistoryItemViewMod // Circle index - use the input swimlane index if present, otherwise add it to the end return inputIndex !== -1 ? inputIndex : inputSwimlanes.length; } + +export function compareHistoryItemRefs( + ref1: ISCMHistoryItemRef, + ref2: ISCMHistoryItemRef, + currentHistoryItemRef?: ISCMHistoryItemRef, + currentHistoryItemRemoteRef?: ISCMHistoryItemRef, + currentHistoryItemBaseRef?: ISCMHistoryItemRef +): number { + const getHistoryItemRefOrder = (ref: ISCMHistoryItemRef) => { + if (ref.id === currentHistoryItemRef?.id) { + return 1; + } else if (ref.id === currentHistoryItemRemoteRef?.id) { + return 2; + } else if (ref.id === currentHistoryItemBaseRef?.id) { + return 3; + } else if (ref.color !== undefined) { + return 4; + } + + return 99; + }; + + // Assign order (current > remote > base > color) + const ref1Order = getHistoryItemRefOrder(ref1); + const ref2Order = getHistoryItemRefOrder(ref2); + + return ref1Order - ref2Order; +} diff --git a/src/vs/workbench/contrib/scm/browser/util.ts b/src/vs/workbench/contrib/scm/browser/util.ts index 2334f15157f..f838ba6ac9b 100644 --- a/src/vs/workbench/contrib/scm/browser/util.ts +++ b/src/vs/workbench/contrib/scm/browser/util.ts @@ -5,7 +5,7 @@ import { localize } from '../../../../nls.js'; import * as platform from '../../../../base/common/platform.js'; -import { ISCMHistoryItem, ISCMHistoryItemRef, SCMHistoryItemChangeViewModelTreeElement, SCMHistoryItemLoadMoreTreeElement, SCMHistoryItemViewModelTreeElement } from '../common/history.js'; +import { ISCMHistoryItem, SCMHistoryItemChangeViewModelTreeElement, SCMHistoryItemLoadMoreTreeElement, SCMHistoryItemViewModelTreeElement } from '../common/history.js'; import { ISCMResource, ISCMRepository, ISCMResourceGroup, ISCMInput, ISCMActionButton, ISCMViewService, ISCMProvider } from '../common/scm.js'; import { IMenu, MenuItemAction } from '../../../../platform/actions/common/actions.js'; import { IActionViewItemProvider } from '../../../../base/browser/ui/actionbar/actionbar.js'; @@ -224,31 +224,3 @@ export function getHistoryItemHoverContent(themeService: IThemeService, historyI return { markdown, markdownNotSupportedFallback: historyItem.message }; } - -export function compareHistoryItemRefs( - ref1: ISCMHistoryItemRef, - ref2: ISCMHistoryItemRef, - currentHistoryItemRef?: ISCMHistoryItemRef, - currentHistoryItemRemoteRef?: ISCMHistoryItemRef, - currentHistoryItemBaseRef?: ISCMHistoryItemRef -): number { - const getHistoryItemRefOrder = (ref: ISCMHistoryItemRef) => { - if (ref.id === currentHistoryItemRef?.id) { - return 1; - } else if (ref.id === currentHistoryItemRemoteRef?.id) { - return 2; - } else if (ref.id === currentHistoryItemBaseRef?.id) { - return 3; - } else if (ref.color !== undefined) { - return 4; - } - - return 99; - }; - - // Assign order (current > remote > base > color) - const ref1Order = getHistoryItemRefOrder(ref1); - const ref2Order = getHistoryItemRefOrder(ref2); - - return ref1Order - ref2Order; -} From b2203d7a025857658360a8b288d0b288db64a0b3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Jun 2025 19:33:37 +0200 Subject: [PATCH 134/236] api notes/todos (#251020) --- src/vscode-dts/vscode.proposed.chatProvider.d.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vscode-dts/vscode.proposed.chatProvider.d.ts b/src/vscode-dts/vscode.proposed.chatProvider.d.ts index 59d832a1faa..2ba3a3a3f5f 100644 --- a/src/vscode-dts/vscode.proposed.chatProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.chatProvider.d.ts @@ -88,10 +88,18 @@ declare module 'vscode' { // TODO@API maybe an enum, LanguageModelChatProviderPickerAvailability? readonly isDefault?: boolean; readonly isUserSelectable?: boolean; + readonly capabilities?: { readonly vision?: boolean; + + // TODO@API should be `boolean | number` so extensions can express how many tools they support readonly toolCalling?: boolean; + + // TODO@API WHY is agentMode a capability? This seems wrong? readonly agentMode?: boolean; + + // TODO@API support prompt TSX style messages + // readonly promptTsx?:boolean }; /** @@ -105,6 +113,7 @@ declare module 'vscode' { export interface ChatResponseProviderMetadata { // limit this provider to some extensions + // TODO@API remove? unused? extensions?: string[]; } From 6812a1791ce9f17a29d1eadd2cc41efe954ef555 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 9 Jun 2025 19:45:50 +0200 Subject: [PATCH 135/236] fix cyclic dependency in notebook-land --- src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 531e14d8c8f..4c79dad2047 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -22,7 +22,7 @@ import { IEditorPane, IEditorPaneWithSelection } from '../../../common/editor.js import { CellViewModelStateChangeEvent, NotebookCellStateChangedEvent, NotebookLayoutInfo } from './notebookViewEvents.js'; import { NotebookCellTextModel } from '../common/model/notebookCellTextModel.js'; import { NotebookTextModel } from '../common/model/notebookTextModel.js'; -import { CellKind, ICellOutput, INotebookCellStatusBarItem, INotebookRendererInfo, INotebookFindOptions, IOrderedMimeType, NotebookCellInternalMetadata, NotebookCellMetadata, NOTEBOOK_EDITOR_ID } from '../common/notebookCommon.js'; +import { CellKind, ICellOutput, INotebookCellStatusBarItem, INotebookRendererInfo, INotebookFindOptions, IOrderedMimeType, NotebookCellInternalMetadata, NotebookCellMetadata, NOTEBOOK_EDITOR_ID, NOTEBOOK_DIFF_EDITOR_ID } from '../common/notebookCommon.js'; import { isCompositeNotebookEditorInput } from '../common/notebookEditorInput.js'; import { INotebookKernel } from '../common/notebookKernelService.js'; import { NotebookOptions } from './notebookOptions.js'; @@ -32,7 +32,6 @@ import { IEditorCommentsOptions, IEditorOptions } from '../../../../editor/commo import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { IObservable } from '../../../../base/common/observable.js'; -import { NotebookTextDiffEditor } from './diff/notebookDiffEditor.js'; import { INotebookTextDiffEditor } from './diff/notebookDiffEditorBrowser.js'; //#region Shared commands @@ -931,7 +930,7 @@ export function getNotebookEditorFromEditorPane(editorPane?: IEditorPane): INote return editorPane.getControl() as INotebookEditor | undefined; } - if (editorPane.getId() === NotebookTextDiffEditor.ID) { + if (editorPane.getId() === NOTEBOOK_DIFF_EDITOR_ID) { return (editorPane.getControl() as INotebookTextDiffEditor).inlineNotebookEditor; } From cac4de41867f2093e7e34ac7f2ae0bd1572d048e Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Jun 2025 10:57:38 -0700 Subject: [PATCH 136/236] fix cycle checker on windows --- build/lib/tsb/builder.js | 2 +- build/lib/tsb/builder.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/lib/tsb/builder.js b/build/lib/tsb/builder.js index 1a08badd113..71c7a78e9a1 100644 --- a/build/lib/tsb/builder.js +++ b/build/lib/tsb/builder.js @@ -294,7 +294,7 @@ function createTypeScriptBuilder(config, projectFile, cmd) { const jsValue = value.files.find(candidate => candidate.basename.endsWith('.js')); if (jsValue) { outHost.addScriptSnapshot(jsValue.path, new ScriptSnapshot(String(jsValue.contents), new Date())); - toBeCheckedForCycles.push(jsValue.path); + toBeCheckedForCycles.push(normalize(jsValue.path)); } }).catch(e => { // can't just skip this or make a result up.. diff --git a/build/lib/tsb/builder.ts b/build/lib/tsb/builder.ts index 94fcf1483db..3ca3a0d6ead 100644 --- a/build/lib/tsb/builder.ts +++ b/build/lib/tsb/builder.ts @@ -315,7 +315,7 @@ export function createTypeScriptBuilder(config: IConfiguration, projectFile: str const jsValue = value.files.find(candidate => candidate.basename.endsWith('.js')); if (jsValue) { outHost.addScriptSnapshot(jsValue.path, new ScriptSnapshot(String(jsValue.contents), new Date())); - toBeCheckedForCycles.push(jsValue.path); + toBeCheckedForCycles.push(normalize(jsValue.path)); } }).catch(e => { From 5e10a1c8568a1d75bb7d1ab48863ca3df2658a14 Mon Sep 17 00:00:00 2001 From: Elijah King Date: Mon, 9 Jun 2025 11:03:12 -0700 Subject: [PATCH 137/236] removed commented out code --- .../common/gettingStartedContent.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts index ad54bad1a33..fad3c94a4c5 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts @@ -731,18 +731,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ }, }, - // Removed settings slide from new welcome experience due to poor responses in user testing - /*{ - id: 'newSettingsAndSync', - title: localize('newgettingStarted.settings.title', "Customize every aspect of VS Code"), - description: localize('newgettingStarted.settingsAndSync.description.interpolated', "[Back up and sync](command:workbench.userDataSync.actions.turnOn) settings across all your devices.\n{0}", Button(localize('tweakSettings', "Open Settings"), 'command:toSide:workbench.action.openSettings')), - when: 'syncStatus != uninitialized', - completionEvents: ['onEvent:sync-enabled'], - media: { - type: 'svg', altText: 'VS Code Settings', path: 'settings.svg' - }, - },*/ - ] } } From 4e037b6e1f0f23f5e9404854350ae86c112efb44 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 9 Jun 2025 20:30:06 +0200 Subject: [PATCH 138/236] more API todos (#251023) https://github.com/microsoft/vscode/issues/250007 --- .../vscode.proposed.chatProvider.d.ts | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/vscode-dts/vscode.proposed.chatProvider.d.ts b/src/vscode-dts/vscode.proposed.chatProvider.d.ts index 2ba3a3a3f5f..47eb21e54f9 100644 --- a/src/vscode-dts/vscode.proposed.chatProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.chatProvider.d.ts @@ -5,10 +5,6 @@ declare module 'vscode' { - export interface ChatResponseFragment2 { - index: number; - part: LanguageModelTextPart | LanguageModelToolCallPart; - } // @API extension ship a d.ts files for their options @@ -16,6 +12,38 @@ declare module 'vscode' { // concrete models. The `provideLanguageModelChatData` would do the discovery and auth dances and later // the model data is passed to the concrete function for making a requested or counting token + + // TODO@API name scheme + export interface LanguageModelChatResponseOptions { + + // initiator + readonly extensionId: string; + + /** + * A set of options that control the behavior of the language model. These options are specific to the language model + * and need to be looked up in the respective documentation. + */ + readonly modelOptions: { [name: string]: any }; + + /** + * An optional list of tools that are available to the language model. These could be registered tools available via + * {@link lm.tools}, or private tools that are just implemented within the calling extension. + * + * If the LLM requests to call one of these tools, it will return a {@link LanguageModelToolCallPart} in + * {@link LanguageModelChatResponse.stream}. It's the caller's responsibility to invoke the tool. If it's a tool + * registered in {@link lm.tools}, that means calling {@link lm.invokeTool}. + * + * Then, the tool result can be provided to the LLM by creating an Assistant-type {@link LanguageModelChatMessage} with a + * {@link LanguageModelToolCallPart}, followed by a User-type message with a {@link LanguageModelToolResultPart}. + */ + tools?: LanguageModelChatTool[]; + + /** + * The tool-selecting mode to use. {@link LanguageModelChatToolMode.Auto} by default. + */ + toolMode?: LanguageModelChatToolMode; + } + export interface LanguageModelChatData { // like ChatResponseProviderMetadata } @@ -24,11 +52,19 @@ declare module 'vscode' { provideLanguageModelChatData(options: { force: boolean }, token: CancellationToken): ProviderResult; - provideResponse(model: LanguageModelChatData, messages: Array, options: LanguageModelChatRequestOptions, extensionId: string, progress: Progress, token: CancellationToken): Thenable; + provideResponse(model: LanguageModelChatData, messages: Array, options: LanguageModelChatResponseOptions, progress: Progress, token: CancellationToken): Thenable; provideTokenCount(model: LanguageModelChatData, text: string | LanguageModelChatMessage | LanguageModelChatMessage2, token: CancellationToken): Thenable; } + + + export interface ChatResponseFragment2 { + index: number; + part: LanguageModelTextPart | LanguageModelToolCallPart; + } + + /** * Represents a large language model that accepts ChatML messages and produces a streaming response */ @@ -37,6 +73,8 @@ declare module 'vscode' { // TODO@API remove or keep proposed? onDidReceiveLanguageModelResponse2?: Event<{ readonly extensionId: string; readonly participant?: string; readonly tokenCount?: number }>; + // TODO@API + // have dedicated options, don't reuse the LanguageModelChatRequestOptions so that consumer and provider part of the API can develop independently provideLanguageModelResponse(messages: Array, options: LanguageModelChatRequestOptions, extensionId: string, progress: Progress, token: CancellationToken): Thenable; provideTokenCount(text: string | LanguageModelChatMessage | LanguageModelChatMessage2, token: CancellationToken): Thenable; From 053aa12d6d8d3f60681484a67d78b5c135e8436a Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 9 Jun 2025 20:32:05 +0200 Subject: [PATCH 139/236] frontMatter parsers: fix cyclic runtime dependencies (#251024) --- .../frontMatterCodec/frontMatterDecoder.ts | 16 +++++--- .../parsers/frontMatterArray.ts | 6 ++- .../parsers/frontMatterParserFactory.ts | 41 +++++++++++++++++++ .../frontMatterRecord/frontMatterRecord.ts | 6 ++- .../frontMatterRecordName.ts | 6 ++- .../frontMatterRecordNameWithDelimiter.ts | 8 ++-- .../parsers/frontMatterRecord/index.ts | 8 ---- .../parsers/frontMatterValue.ts | 14 +++---- 8 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterParserFactory.ts delete mode 100644 src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/index.ts diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.ts index 89a6517e5f9..704e10f1754 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/frontMatterDecoder.ts @@ -11,8 +11,11 @@ import { ReadableStream } from '../../../../../../../../base/common/stream.js'; import { FrontMatterToken, FrontMatterRecord } from './tokens/index.js'; import { BaseDecoder } from '../baseDecoder.js'; import { SimpleDecoder, type TSimpleDecoderToken } from '../simpleCodec/simpleDecoder.js'; -import { PartialFrontMatterRecord, PartialFrontMatterRecordName, PartialFrontMatterRecordNameWithDelimiter } from './parsers/frontMatterRecord/index.js'; import { ObjectStream } from '../utils/objectStream.js'; +import { PartialFrontMatterRecordNameWithDelimiter } from './parsers/frontMatterRecord/frontMatterRecordNameWithDelimiter.js'; +import { PartialFrontMatterRecord } from './parsers/frontMatterRecord/frontMatterRecord.js'; +import { PartialFrontMatterRecordName } from './parsers/frontMatterRecord/frontMatterRecordName.js'; +import { FrontMatterParserFactory } from './parsers/frontMatterParserFactory.js'; /** * Tokens produced by this decoder. @@ -29,16 +32,17 @@ export class FrontMatterDecoder extends BaseDecoder | ObjectStream, ) { if (stream instanceof ObjectStream) { super(stream); - - return; + } else { + super(new SimpleDecoder(stream)); } - - super(new SimpleDecoder(stream)); + this.parserFactory = new FrontMatterParserFactory(); } protected override onStreamData(token: TSimpleDecoderToken): void { @@ -92,7 +96,7 @@ export class FrontMatterDecoder extends BaseDecoder { // comma or a closing square bracket must stop the parsing // process of the value represented by a generic sequence of tokens diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterParserFactory.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterParserFactory.ts new file mode 100644 index 00000000000..0be65371449 --- /dev/null +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterParserFactory.ts @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BaseToken } from '../../baseToken.js'; +import { LeftBracket } from '../../simpleCodec/tokens/brackets.js'; +import { Word } from '../../simpleCodec/tokens/word.js'; +import { FrontMatterRecordDelimiter, FrontMatterRecordName } from '../tokens/frontMatterRecord.js'; +import { TQuoteToken } from '../tokens/frontMatterString.js'; +import { PartialFrontMatterArray } from './frontMatterArray.js'; +import { PartialFrontMatterRecord } from './frontMatterRecord/frontMatterRecord.js'; +import { PartialFrontMatterRecordName } from './frontMatterRecord/frontMatterRecordName.js'; +import { PartialFrontMatterRecordNameWithDelimiter, TNameStopToken } from './frontMatterRecord/frontMatterRecordNameWithDelimiter.js'; +import { PartialFrontMatterSequence } from './frontMatterSequence.js'; +import { PartialFrontMatterString } from './frontMatterString.js'; +import { PartialFrontMatterValue } from './frontMatterValue.js'; + +export class FrontMatterParserFactory { + createRecord(tokens: [FrontMatterRecordName, FrontMatterRecordDelimiter]): PartialFrontMatterRecord { + return new PartialFrontMatterRecord(this, tokens); + } + createRecordName(startToken: Word): PartialFrontMatterRecordName { + return new PartialFrontMatterRecordName(this, startToken); + } + createRecordNameWithDelimiter(tokens: readonly [FrontMatterRecordName, TNameStopToken]): PartialFrontMatterRecordNameWithDelimiter { + return new PartialFrontMatterRecordNameWithDelimiter(this, tokens); + } + createArray(startToken: LeftBracket) { + return new PartialFrontMatterArray(this, startToken); + } + createValue(shouldStop: (token: BaseToken) => boolean): PartialFrontMatterValue { + return new PartialFrontMatterValue(this, shouldStop); + } + createString(startToken: TQuoteToken): PartialFrontMatterString { + return new PartialFrontMatterString(startToken); + } + createSequence(shouldStop: (token: BaseToken) => boolean): PartialFrontMatterSequence { + return new PartialFrontMatterSequence(shouldStop); + } +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts index 5ea54b01045..e4afee055b5 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/frontMatterRecord.ts @@ -14,6 +14,7 @@ import { type TSimpleDecoderToken } from '../../../simpleCodec/simpleDecoder.js' import { Word, FormFeed, SpacingToken } from '../../../simpleCodec/tokens/tokens.js'; import { assertNotConsumed, ParserBase, type TAcceptTokenResult } from '../../../simpleCodec/parserBase.js'; import { FrontMatterValueToken, FrontMatterRecordName, FrontMatterRecordDelimiter, FrontMatterRecord } from '../../tokens/index.js'; +import { type FrontMatterParserFactory } from '../frontMatterParserFactory.js'; /** * Type of a next parser that can be returned by {@link PartialFrontMatterRecord}. @@ -44,6 +45,7 @@ export class PartialFrontMatterRecord extends ParserBase { constructor( + private readonly factory: FrontMatterParserFactory, startToken: Word, ) { super([startToken]); @@ -57,7 +59,7 @@ export class PartialFrontMatterRecordName extends ParserBase { constructor( + private readonly factory: FrontMatterParserFactory, tokens: readonly [FrontMatterRecordName, TNameStopToken], ) { super([...tokens]); @@ -63,7 +65,7 @@ export class PartialFrontMatterRecordNameWithDelimiter extends ParserBase< this.isConsumed = true; return { result: 'success', - nextParser: new PartialFrontMatterRecord( + nextParser: this.factory.createRecord( [recordName, recordDelimiter], ), wasTokenConsumed: true, diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/index.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/index.ts deleted file mode 100644 index 5518e6ee0c5..00000000000 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterRecord/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -export { PartialFrontMatterRecord } from './frontMatterRecord.js'; -export { PartialFrontMatterRecordName } from './frontMatterRecordName.js'; -export { PartialFrontMatterRecordNameWithDelimiter } from './frontMatterRecordNameWithDelimiter.js'; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterValue.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterValue.ts index 668a757c827..710767aed40 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterValue.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/codecs/base/frontMatterCodec/parsers/frontMatterValue.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { BaseToken } from '../../baseToken.js'; -import { PartialFrontMatterArray } from './frontMatterArray.js'; -import { PartialFrontMatterString } from './frontMatterString.js'; +import { type PartialFrontMatterArray } from './frontMatterArray.js'; +import { type PartialFrontMatterString } from './frontMatterString.js'; import { asBoolean, FrontMatterBoolean } from '../tokens/frontMatterBoolean.js'; import { FrontMatterValueToken } from '../tokens/frontMatterToken.js'; import { PartialFrontMatterSequence } from './frontMatterSequence.js'; @@ -13,6 +13,7 @@ import { FrontMatterSequence } from '../tokens/frontMatterSequence.js'; import { TSimpleDecoderToken } from '../../simpleCodec/simpleDecoder.js'; import { Word, Quote, DoubleQuote, LeftBracket } from '../../simpleCodec/tokens/tokens.js'; import { assertNotConsumed, ParserBase, TAcceptTokenResult } from '../../simpleCodec/parserBase.js'; +import { type FrontMatterParserFactory } from './frontMatterParserFactory.js'; /** * List of tokens that can start a "value" sequence. @@ -54,6 +55,7 @@ export class PartialFrontMatterValue extends ParserBase Date: Mon, 9 Jun 2025 17:02:04 +0200 Subject: [PATCH 140/236] =?UTF-8?q?VS=20Code=20fails=20silently=20when=20n?= =?UTF-8?q?o=20default=20browser=20is=20set=20=E2=80=94=20GitHub=20authent?= =?UTF-8?q?ication=20hangs=20without=20fallback=20(fix=20#250895)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../electron-main/nativeHostMainService.ts | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 7e1dda7b1a4..26436e6bafe 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -558,9 +558,9 @@ export class NativeHostMainService extends Disposable implements INativeHostMain this.environmentMainService.unsetSnapExportedVariables(); try { if (matchesSomeScheme(url, Schemas.http, Schemas.https)) { - this.openExternalBrowser(url, defaultApplication); + this.openExternalBrowser(windowId, url, defaultApplication); } else { - shell.openExternal(url); + this.doOpenShellExternal(windowId, url); } } finally { this.environmentMainService.restoreSnapExportedVariables(); @@ -569,17 +569,17 @@ export class NativeHostMainService extends Disposable implements INativeHostMain return true; } - private async openExternalBrowser(url: string, defaultApplication?: string): Promise { + private async openExternalBrowser(windowId: number | undefined, url: string, defaultApplication?: string): Promise { const configuredBrowser = defaultApplication ?? this.configurationService.getValue('workbench.externalBrowser'); if (!configuredBrowser) { - return shell.openExternal(url); + return this.doOpenShellExternal(windowId, url); } if (configuredBrowser.includes(posix.sep) || configuredBrowser.includes(win32.sep)) { const browserPathExists = await Promises.exists(configuredBrowser); if (!browserPathExists) { this.logService.error(`Configured external browser path does not exist: ${configuredBrowser}`); - return shell.openExternal(url); + return this.doOpenShellExternal(windowId, url); } } @@ -602,12 +602,49 @@ export class NativeHostMainService extends Disposable implements INativeHostMain // (see also https://github.com/microsoft/vscode/issues/230636) res.stderr?.once('data', (data: Buffer) => { this.logService.error(`Error openening external URL '${url}' using browser '${configuredBrowser}': ${data.toString()}`); - return shell.openExternal(url); + return this.doOpenShellExternal(windowId, url); }); } } catch (error) { this.logService.error(`Unable to open external URL '${url}' using browser '${configuredBrowser}' due to ${error}.`); - return shell.openExternal(url); + return this.doOpenShellExternal(windowId, url); + } + } + + private async doOpenShellExternal(windowId: number | undefined, url: string): Promise { + try { + await shell.openExternal(url); + } catch (error) { + let isLink: boolean; + let title: string; + let message: string; + if (matchesSomeScheme(url, Schemas.http, Schemas.https)) { + isLink = true; + title = localize('openExternalErrorLinkTitle', "Error Opening Link"); + message = localize('openExternalErrorLinkMessage', "An error occurred opening a link in your default browser."); + } else { + isLink = false; + title = localize('openExternalProgramErrorTitle', "Error Opening External Program"); + message = localize('openExternalProgramErrorMessage', "An error occurred opening an external program."); + } + + const { response } = await this.dialogMainService.showMessageBox({ + title, + message, + detail: error.message, + buttons: isLink ? [ + localize({ key: 'copyLink', comment: ['&& denotes a mnemonic'] }, "&&Copy Link"), + localize('cancel', "Cancel") + ] : [ + localize({ key: 'ok', comment: ['&& denotes a mnemonic'] }, "&&OK") + ] + }, this.windowById(windowId)?.win ?? undefined); + + if (response === 1 /* Cancel */) { + return; + } + + this.writeClipboardText(windowId, url); } } From 325578a61db433e02ddf9647ff1ac5080f20bbcf Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 9 Jun 2025 20:35:14 +0200 Subject: [PATCH 141/236] remove title --- .../platform/native/electron-main/nativeHostMainService.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 26436e6bafe..37ecd52d628 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -616,20 +616,17 @@ export class NativeHostMainService extends Disposable implements INativeHostMain await shell.openExternal(url); } catch (error) { let isLink: boolean; - let title: string; let message: string; if (matchesSomeScheme(url, Schemas.http, Schemas.https)) { isLink = true; - title = localize('openExternalErrorLinkTitle', "Error Opening Link"); message = localize('openExternalErrorLinkMessage', "An error occurred opening a link in your default browser."); } else { isLink = false; - title = localize('openExternalProgramErrorTitle', "Error Opening External Program"); message = localize('openExternalProgramErrorMessage', "An error occurred opening an external program."); } const { response } = await this.dialogMainService.showMessageBox({ - title, + type: 'error', message, detail: error.message, buttons: isLink ? [ From 3d2e76831e79704656f7a34a5e9d3f193aa26fbf Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Jun 2025 12:35:15 -0700 Subject: [PATCH 142/236] chore: adopt EditorOption.lineHeight for various components (#251029) * chore: adopt EditorOption.lineHeight for various components Also adds an `ModelLineHeightChangedEvent.affects` method since I think a lot of people will want to use that, cc @aiday-mar. Feel free to refactor/remove that if you don't like it. Refs #248794 * rm test code --- src/vs/editor/common/textModelEvents.ts | 21 ++++++++++++++++++- .../browser/breakpointEditorContribution.ts | 18 +++++++++------- .../contrib/debug/browser/breakpointWidget.ts | 1 + .../workbench/contrib/debug/browser/repl.ts | 1 + .../testing/browser/testingDecorations.ts | 8 ++++++- 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/common/textModelEvents.ts b/src/vs/editor/common/textModelEvents.ts index 3123b120b28..8f9ab67df70 100644 --- a/src/vs/editor/common/textModelEvents.ts +++ b/src/vs/editor/common/textModelEvents.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IRange } from './core/range.js'; +import { IPosition } from './core/position.js'; +import { IRange, Range } from './core/range.js'; import { Selection } from './core/selection.js'; import { IModelDecoration, InjectedTextOptions } from './model.js'; @@ -403,6 +404,24 @@ export class ModelLineHeightChangedEvent { constructor(changes: ModelLineHeightChanged[]) { this.changes = changes; } + + public affects(rangeOrPosition: IRange | IPosition) { + if (Range.isIRange(rangeOrPosition)) { + for (const change of this.changes) { + if (change.lineNumber >= rangeOrPosition.startLineNumber && change.lineNumber <= rangeOrPosition.endLineNumber) { + return true; + } + } + return false; + } else { + for (const change of this.changes) { + if (change.lineNumber === rangeOrPosition.lineNumber) { + return true; + } + } + return false; + } + } } /** diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 929118f46c0..7a2073c81d4 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -730,6 +730,7 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { if (this.range && !this.range.equalsRange(range)) { this.range = range; this.editor.layoutContentWidget(this); + this.updateSize(); } })); this.create(cssClass); @@ -767,21 +768,22 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { }); })); - const updateSize = () => { - const lineHeight = this.editor.getOption(EditorOption.lineHeight); - this.domNode.style.height = `${lineHeight}px`; - this.domNode.style.width = `${Math.ceil(0.8 * lineHeight)}px`; - this.domNode.style.marginLeft = `4px`; - }; - updateSize(); + this.updateSize(); this.toDispose.push(this.editor.onDidChangeConfiguration(c => { if (c.hasChanged(EditorOption.fontSize) || c.hasChanged(EditorOption.lineHeight)) { - updateSize(); + this.updateSize(); } })); } + private updateSize() { + const lineHeight = this.range ? this.editor.getLineHeightForPosition(this.range.getStartPosition()) : this.editor.getOption(EditorOption.lineHeight); + this.domNode.style.height = `${lineHeight}px`; + this.domNode.style.width = `${Math.ceil(0.8 * lineHeight)}px`; + this.domNode.style.marginLeft = `4px`; + } + @memoize getId(): string { return generateUuid(); diff --git a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts index 07b92710f72..84524c76602 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts @@ -421,6 +421,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi options.lineHeight = editorConfig.lineHeight; options.fontLigatures = editorConfig.fontLigatures; options.ariaLabel = this.placeholder; + options.allowVariableLineHeights = false; return options; } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 930812de0f9..ce162293526 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -737,6 +737,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget { const config = this.configurationService.getValue('debug'); options.acceptSuggestionOnEnter = config.console.acceptSuggestionOnEnter === 'on' ? 'on' : 'off'; options.ariaLabel = this.getAriaLabel(); + options.allowVariableLineHeights = false; this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions()); diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index cac9d9f09d0..3c3a2f50f35 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -1367,11 +1367,17 @@ class TestErrorContentWidget extends Disposable implements IContentWidget { super(); const setMarginTop = () => { - const lineHeight = editor.getOption(EditorOption.lineHeight); + const lineHeight = editor.getLineHeightForPosition(position); this.node.root.style.marginTop = (lineHeight - ERROR_CONTENT_WIDGET_HEIGHT) / 2 + 'px'; }; setMarginTop(); + this._register(editor.onDidChangeLineHeight(e => { + if (e.affects(position)) { + setMarginTop(); + } + })); + this._register(editor.onDidChangeConfiguration(e => { if (e.hasChanged(EditorOption.lineHeight)) { setMarginTop(); From a0287f096c7a4679b89abda31d211a629d0c2d14 Mon Sep 17 00:00:00 2001 From: Josh Spicer <23246594+joshspicer@users.noreply.github.com> Date: Mon, 9 Jun 2025 12:50:27 -0700 Subject: [PATCH 143/236] clarify IPolicy.defaultValue (#251034) clarify IPolicy.defaultValue (https://github.com/microsoft/vscode/issues/248581) --- src/vs/base/common/policy.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/policy.ts b/src/vs/base/common/policy.ts index 8600c43854e..befbff12794 100644 --- a/src/vs/base/common/policy.ts +++ b/src/vs/base/common/policy.ts @@ -28,7 +28,10 @@ export interface IPolicy { readonly previewFeature?: boolean; /** - * Default value when enabled. Default is `false`. + * Default value for a 'previewFeature' policy. Default is `false`. + * Remarks: + * A default value is only relevant when previewFeature is `true`. + * In all other instances, a value is required when setting a policy. */ readonly defaultValue?: string | number | boolean; } From 4f2559f97fe6a2bf00796d613f33ff258bc4a681 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Jun 2025 13:01:27 -0700 Subject: [PATCH 144/236] Accessibility: Add severity prefixes to notification aria-labels for WCAG 4.1.3 compliance (#250864) --- .../notificationAccessibleView.ts | 8 +- .../notifications/notificationsCommands.ts | 12 ++- .../parts/notifications/notificationsList.ts | 14 ++- .../notifications/notificationsToasts.ts | 9 +- .../test/browser/notificationsList.test.ts | 102 ++++++++++++++++++ 5 files changed, 135 insertions(+), 10 deletions(-) create mode 100644 src/vs/workbench/test/browser/notificationsList.test.ts diff --git a/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts b/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts index 723c97a134c..59bf3253259 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts @@ -13,7 +13,7 @@ import { IAccessibilitySignalService, AccessibilitySignal } from '../../../../pl import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { IListService, WorkbenchList } from '../../../../platform/list/browser/listService.js'; -import { getNotificationFromContext } from './notificationsCommands.js'; +import { getNotificationFromContext, getSeverityPrefix } from './notificationsCommands.js'; import { NotificationFocusedContext } from '../../../common/contextkeys.js'; import { INotificationViewItem } from '../../../common/notifications.js'; @@ -59,7 +59,11 @@ export class NotificationAccessibleView implements IAccessibleViewImplementation if (!notification) { return; } - return notification.source ? localize('notification.accessibleViewSrc', '{0} Source: {1}', message, notification.source) : localize('notification.accessibleView', '{0}', message); + // Add severity prefix to match WCAG 4.1.3 Status Messages requirements + const severityPrefix = getSeverityPrefix(notification.severity); + const messageWithSeverity = `${severityPrefix}${message}`; + + return notification.source ? localize('notification.accessibleViewSrc', '{0} Source: {1}', messageWithSeverity, notification.source) : localize('notification.accessibleView', '{0}', messageWithSeverity); } const content = getContentForNotification(); if (!content) { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts index d3fff55ef7c..59bc44f6a35 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts @@ -13,7 +13,7 @@ import { localize, localize2 } from '../../../../nls.js'; import { IListService, WorkbenchList } from '../../../../platform/list/browser/listService.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { NotificationFocusedContext, NotificationsCenterVisibleContext, NotificationsToastsVisibleContext } from '../../../common/contextkeys.js'; -import { INotificationService, INotificationSourceFilter, NotificationsFilter } from '../../../../platform/notification/common/notification.js'; +import { INotificationService, INotificationSourceFilter, NotificationsFilter, Severity } from '../../../../platform/notification/common/notification.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ActionRunner, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from '../../../../base/common/actions.js'; import { IQuickInputService, IQuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; @@ -88,6 +88,16 @@ export function getNotificationFromContext(listService: IListService, context?: return undefined; } +export function getSeverityPrefix(severity: Severity): string { + if (severity === Severity.Error) { + return localize('severityPrefix.error', "Error: "); + } else if (severity === Severity.Warning) { + return localize('severityPrefix.warning', "Warning: "); + } else { + return localize('severityPrefix.info', "Info: "); + } +} + export function registerNotificationCommands(center: INotificationsCenterController, toasts: INotificationsToastController, model: NotificationsModel): void { // Show Notifications Cneter diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index cd5c2f5b6a5..fb0dd7d4fab 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -18,7 +18,7 @@ import { assertReturnsAllDefined } from '../../../../base/common/types.js'; import { NotificationFocusedContext } from '../../../common/contextkeys.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { AriaRole } from '../../../../base/browser/ui/aria/aria.js'; -import { NotificationActionRunner } from './notificationsCommands.js'; +import { getSeverityPrefix, NotificationActionRunner } from './notificationsCommands.js'; import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; @@ -244,7 +244,7 @@ export class NotificationsList extends Disposable { } } -class NotificationAccessibilityProvider implements IListAccessibilityProvider { +export class NotificationAccessibilityProvider implements IListAccessibilityProvider { constructor( private readonly _options: INotificationsListOptions, @IKeybindingService private readonly _keybindingService: IKeybindingService, @@ -256,12 +256,18 @@ class NotificationAccessibilityProvider implements IListAccessibilityProvider { + // Add severity prefix to match WCAG 4.1.3 Status Messages requirements + const severityPrefix = getSeverityPrefix(item.severity); + const messageWithSeverity = `${severityPrefix}${item.message.raw}`; if (!item.source) { - return localize('notificationAriaLabel', "{0}, notification", item.message.raw); + return localize('notificationAriaLabel', "{0}, notification", messageWithSeverity); } - return localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", item.message.raw, item.source); + return localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", messageWithSeverity, item.source); })() }); itemDisposables.add(notificationList); diff --git a/src/vs/workbench/test/browser/notificationsList.test.ts b/src/vs/workbench/test/browser/notificationsList.test.ts new file mode 100644 index 00000000000..c975c6533af --- /dev/null +++ b/src/vs/workbench/test/browser/notificationsList.test.ts @@ -0,0 +1,102 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { NotificationAccessibilityProvider } from '../../browser/parts/notifications/notificationsList.js'; +import { NotificationViewItem, INotificationsFilter, INotificationViewItem } from '../../common/notifications.js'; +import { Severity, NotificationsFilter } from '../../../platform/notification/common/notification.js'; +import { IKeybindingService } from '../../../platform/keybinding/common/keybinding.js'; +import { IConfigurationService } from '../../../platform/configuration/common/configuration.js'; +import { TestConfigurationService } from '../../../platform/configuration/test/common/testConfigurationService.js'; +import { MockKeybindingService } from '../../../platform/keybinding/test/common/mockKeybindingService.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../base/test/common/utils.js'; + +suite('NotificationsList AccessibilityProvider', () => { + + const noFilter: INotificationsFilter = { global: NotificationsFilter.OFF, sources: new Map() }; + let configurationService: IConfigurationService; + let keybindingService: IKeybindingService; + let accessibilityProvider: NotificationAccessibilityProvider; + const createdNotifications: INotificationViewItem[] = []; + + setup(() => { + configurationService = new TestConfigurationService(); + keybindingService = new MockKeybindingService(); + accessibilityProvider = new NotificationAccessibilityProvider({}, keybindingService, configurationService); + }); + + teardown(() => { + // Close all created notifications to prevent disposable leaks + for (const notification of createdNotifications) { + notification.close(); + } + createdNotifications.length = 0; + }); + + ensureNoDisposablesAreLeakedInTestSuite(); + + test('getAriaLabel includes severity prefix for Error notifications', () => { + const notification = NotificationViewItem.create({ severity: Severity.Error, message: 'Something went wrong' }, noFilter)!; + createdNotifications.push(notification); + const ariaLabel = accessibilityProvider.getAriaLabel(notification); + + assert.ok(ariaLabel.startsWith('Error: '), `Expected aria label to start with "Error: ", but got: ${ariaLabel}`); + assert.ok(ariaLabel.includes('Something went wrong'), 'Expected aria label to include original message'); + assert.ok(ariaLabel.includes('notification'), 'Expected aria label to include "notification"'); + }); + + test('getAriaLabel includes severity prefix for Warning notifications', () => { + const notification = NotificationViewItem.create({ severity: Severity.Warning, message: 'This is a warning' }, noFilter)!; + createdNotifications.push(notification); + const ariaLabel = accessibilityProvider.getAriaLabel(notification); + + assert.ok(ariaLabel.startsWith('Warning: '), `Expected aria label to start with "Warning: ", but got: ${ariaLabel}`); + assert.ok(ariaLabel.includes('This is a warning'), 'Expected aria label to include original message'); + assert.ok(ariaLabel.includes('notification'), 'Expected aria label to include "notification"'); + }); + + test('getAriaLabel includes severity prefix for Info notifications', () => { + const notification = NotificationViewItem.create({ severity: Severity.Info, message: 'Information message' }, noFilter)!; + createdNotifications.push(notification); + const ariaLabel = accessibilityProvider.getAriaLabel(notification); + + assert.ok(ariaLabel.startsWith('Info: '), `Expected aria label to start with "Info: ", but got: ${ariaLabel}`); + assert.ok(ariaLabel.includes('Information message'), 'Expected aria label to include original message'); + assert.ok(ariaLabel.includes('notification'), 'Expected aria label to include "notification"'); + }); + + test('getAriaLabel includes source when present', () => { + const notification = NotificationViewItem.create({ + severity: Severity.Error, + message: 'Error with source', + source: 'TestExtension' + }, noFilter)!; + createdNotifications.push(notification); + const ariaLabel = accessibilityProvider.getAriaLabel(notification); + + assert.ok(ariaLabel.startsWith('Error: '), 'Expected aria label to start with severity prefix'); + assert.ok(ariaLabel.includes('Error with source'), 'Expected aria label to include original message'); + assert.ok(ariaLabel.includes('source: TestExtension'), 'Expected aria label to include source information'); + assert.ok(ariaLabel.includes('notification'), 'Expected aria label to include "notification"'); + }); + + test('severity prefix consistency', () => { + // Test that the severity prefixes are consistent with the ARIA alerts + const errorNotification = NotificationViewItem.create({ severity: Severity.Error, message: 'Error message' }, noFilter)!; + const warningNotification = NotificationViewItem.create({ severity: Severity.Warning, message: 'Warning message' }, noFilter)!; + const infoNotification = NotificationViewItem.create({ severity: Severity.Info, message: 'Info message' }, noFilter)!; + + createdNotifications.push(errorNotification, warningNotification, infoNotification); + + const errorLabel = accessibilityProvider.getAriaLabel(errorNotification); + const warningLabel = accessibilityProvider.getAriaLabel(warningNotification); + const infoLabel = accessibilityProvider.getAriaLabel(infoNotification); + + // Check that each severity type gets the correct prefix + assert.ok(errorLabel.includes('Error: Error message'), 'Error notifications should have Error prefix'); + assert.ok(warningLabel.includes('Warning: Warning message'), 'Warning notifications should have Warning prefix'); + assert.ok(infoLabel.includes('Info: Info message'), 'Info notifications should have Info prefix'); + }); +}); From f4792a15b113b7f2b53b789dca711a6b929a939e Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:11:35 +0000 Subject: [PATCH 145/236] Fix scrolling not working when hovering on notebook sticky scroll (#251028) * Initial plan for issue * Fix scrolling not working when hovering on notebook sticky scroll Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Fix TypeScript error by casting WheelEvent to IMouseWheelEvent Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * typing fix, need to verify windows behavior --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> Co-authored-by: Michael Lively Co-authored-by: Michael Lively --- .../browser/viewParts/notebookEditorStickyScroll.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts index ea8227a1a69..813faae9352 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts @@ -6,7 +6,7 @@ import * as DOM from '../../../../../base/browser/dom.js'; import { EventType as TouchEventType } from '../../../../../base/browser/touch.js'; import { CancellationToken } from '../../../../../base/common/cancellation.js'; -import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js'; +import { IMouseWheelEvent, StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js'; import { Emitter, Event } from '../../../../../base/common/event.js'; import { Disposable, DisposableStore, type IReference } from '../../../../../base/common/lifecycle.js'; import { MenuId } from '../../../../../platform/actions/common/actions.js'; @@ -164,6 +164,11 @@ export class NotebookStickyScroll extends Disposable { this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.CONTEXT_MENU, async (event: MouseEvent) => { this.onContextMenu(event); })); + + // Forward wheel events to the notebook editor to enable scrolling when hovering over sticky scroll + this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.WHEEL, (event: WheelEvent) => { + this.notebookCellList.triggerScrollFromMouseWheelEvent(event as any as IMouseWheelEvent); + })); } private onContextMenu(e: MouseEvent) { From fcf63d27ccdb73e497a63f4c7d527d2cb214e55b Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Jun 2025 14:32:01 -0700 Subject: [PATCH 146/236] mcp: fix using vscode-remote schemes for MCP servers, use file uris instead (#251042) Fixes #250920 --- src/vs/workbench/api/browser/mainThreadMcp.ts | 6 ++-- .../workbench/contrib/mcp/common/mcpServer.ts | 31 ++++++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadMcp.ts b/src/vs/workbench/api/browser/mainThreadMcp.ts index 491cc5d2581..407a8d232b4 100644 --- a/src/vs/workbench/api/browser/mainThreadMcp.ts +++ b/src/vs/workbench/api/browser/mainThreadMcp.ts @@ -3,13 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from '../../../nls.js'; import { disposableTimeout } from '../../../base/common/async.js'; +import { CancellationError } from '../../../base/common/errors.js'; import { Emitter } from '../../../base/common/event.js'; import { Disposable, DisposableMap } from '../../../base/common/lifecycle.js'; +import { IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata } from '../../../base/common/oauth.js'; import { ISettableObservable, observableValue } from '../../../base/common/observable.js'; import Severity from '../../../base/common/severity.js'; import { URI, UriComponents } from '../../../base/common/uri.js'; +import * as nls from '../../../nls.js'; import { IDialogService, IPromptButton } from '../../../platform/dialogs/common/dialogs.js'; import { LogLevel } from '../../../platform/log/common/log.js'; import { IMcpMessageTransport, IMcpRegistry } from '../../contrib/mcp/common/mcpRegistryTypes.js'; @@ -23,8 +25,6 @@ import { ExtensionHostKind, extensionHostKindToString } from '../../services/ext import { IExtHostContext, extHostNamedCustomer } from '../../services/extensions/common/extHostCustomers.js'; import { Proxied } from '../../services/extensions/common/proxyIdentifier.js'; import { ExtHostContext, ExtHostMcpShape, MainContext, MainThreadMcpShape } from '../common/extHost.protocol.js'; -import { CancellationError } from '../../../base/common/errors.js'; -import { IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata } from '../../../base/common/oauth.js'; @extHostNamedCustomer(MainContext.MainThreadMcp) export class MainThreadMcp extends Disposable implements MainThreadMcpShape { diff --git a/src/vs/workbench/contrib/mcp/common/mcpServer.ts b/src/vs/workbench/contrib/mcp/common/mcpServer.ts index 43660f303fa..4a5da51d7b4 100644 --- a/src/vs/workbench/contrib/mcp/common/mcpServer.ts +++ b/src/vs/workbench/contrib/mcp/common/mcpServer.ts @@ -9,7 +9,7 @@ import * as json from '../../../../base/common/json.js'; import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; import { LRUCache } from '../../../../base/common/map.js'; import { mapValues } from '../../../../base/common/objects.js'; -import { autorun, autorunWithStore, derived, disposableObservableValue, IDerivedReader, IObservable, ITransaction, observableFromEvent, ObservablePromise, observableValue, transaction } from '../../../../base/common/observable.js'; +import { autorun, derived, disposableObservableValue, IDerivedReader, IObservable, ITransaction, observableFromEvent, ObservablePromise, observableValue, transaction } from '../../../../base/common/observable.js'; import { basename } from '../../../../base/common/resources.js'; import { URI } from '../../../../base/common/uri.js'; import { generateUuid } from '../../../../base/common/uuid.js'; @@ -19,6 +19,7 @@ import { IInstantiationService } from '../../../../platform/instantiation/common import { ILogger, ILoggerService } from '../../../../platform/log/common/log.js'; import { INotificationService, IPromptChoice, Severity } from '../../../../platform/notification/common/notification.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; +import { IRemoteAuthorityResolverService } from '../../../../platform/remote/common/remoteAuthorityResolver.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; @@ -312,6 +313,7 @@ export class McpServer extends Disposable implements IMcpServer { @INotificationService private readonly _notificationService: INotificationService, @IOpenerService private readonly _openerService: IOpenerService, @IMcpSamplingService private readonly _samplingService: IMcpSamplingService, + @IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, ) { super(); @@ -335,24 +337,37 @@ export class McpServer extends Disposable implements IMcpServer { () => workspacesService.getWorkspace().folders, ); - this._register(autorunWithStore(reader => { + const workspacesWithCanonicalURIs = derived(reader => { + const folders = workspaces.read(reader); + return new ObservablePromise((async () => { + let uris = folders.map(f => f.uri); + try { + uris = await Promise.all(uris.map(u => this._remoteAuthorityResolverService.getCanonicalURI(u))); + } catch (error) { + this._logger.error(`Failed to resolve workspace folder URIs: ${error}`); + } + return uris.map((uri, i): MCP.Root => ({ uri: uri.toString(), name: folders[i].name })); + })()); + }).recomputeInitiallyAndOnChange(this._store); + + this._register(autorun(reader => { const cnx = this._connection.read(reader)?.handler.read(reader); if (!cnx) { return; } - cnx.roots = workspaces.read(reader).map(wf => ({ - uri: wf.uri.toString(), - name: wf.name, - })); + const roots = workspacesWithCanonicalURIs.read(reader).promiseResult.read(reader); + if (roots?.data) { + cnx.roots = roots.data; + } })); // 2. Populate this.tools when we connect to a server. - this._register(autorunWithStore((reader, store) => { + this._register(autorun(reader => { const cnx = this._connection.read(reader); const handler = cnx?.handler.read(reader); if (handler) { - this.populateLiveData(handler, cnx?.definition.cacheNonce, store); + this.populateLiveData(handler, cnx?.definition.cacheNonce, reader.store); } else if (this._tools) { this.resetLiveData(); } From fbb72fa4f4eb6b3237d2db9b6bf7e2cab7ef7592 Mon Sep 17 00:00:00 2001 From: Aaron Munger <2019016+amunger@users.noreply.github.com> Date: Mon, 9 Jun 2025 15:28:35 -0700 Subject: [PATCH 147/236] fix disposable leaks while creating native REPL (#251044) --- .../browser/replInputHintContentWidget.ts | 13 +++++++++---- .../replNotebook/browser/repl.contribution.ts | 2 +- .../contrib/replNotebook/browser/replEditor.ts | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/interactive/browser/replInputHintContentWidget.ts b/src/vs/workbench/contrib/interactive/browser/replInputHintContentWidget.ts index dec54b24f4b..de429e98bcf 100644 --- a/src/vs/workbench/contrib/interactive/browser/replInputHintContentWidget.ts +++ b/src/vs/workbench/contrib/interactive/browser/replInputHintContentWidget.ts @@ -27,6 +27,7 @@ export class ReplInputHintContentWidget extends Disposable implements IContentWi private domNode: HTMLElement | undefined; private ariaLabel: string = ''; + private label: KeybindingLabel | undefined; constructor( private readonly editor: ICodeEditor, @@ -111,10 +112,13 @@ export class ReplInputHintContentWidget extends Disposable implements IContentWi hintElement.appendChild(before); - const label = new KeybindingLabel(hintElement, OS); - label.set(keybinding); - label.element.style.width = 'min-content'; - label.element.style.display = 'inline'; + if (this.label) { + this.label.dispose(); + } + this.label = this._register(new KeybindingLabel(hintElement, OS)); + this.label.set(keybinding); + this.label.element.style.width = 'min-content'; + this.label.element.style.display = 'inline'; hintElement.appendChild(after); this.domNode.append(hintElement); @@ -161,5 +165,6 @@ export class ReplInputHintContentWidget extends Disposable implements IContentWi override dispose(): void { super.dispose(); this.editor.removeContentWidget(this); + this.label?.dispose(); } } diff --git a/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts b/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts index 61e6351ad26..ec41740e8d7 100644 --- a/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts +++ b/src/vs/workbench/contrib/replNotebook/browser/repl.contribution.ts @@ -147,7 +147,7 @@ export class ReplDocumentContribution extends Disposable implements IWorkbenchCo // untitled notebooks are disposed when they get saved. we should not hold a reference // to such a disposed notebook and therefore dispose the reference as well - ref.object.notebook.onWillDispose(() => { + Event.once(ref.object.notebook.onWillDispose)(() => { ref.dispose(); }); const label = (options as INotebookEditorOptions)?.label ?? undefined; diff --git a/src/vs/workbench/contrib/replNotebook/browser/replEditor.ts b/src/vs/workbench/contrib/replNotebook/browser/replEditor.ts index b6ff66566c1..667b9c48d46 100644 --- a/src/vs/workbench/contrib/replNotebook/browser/replEditor.ts +++ b/src/vs/workbench/contrib/replNotebook/browser/replEditor.ts @@ -485,11 +485,11 @@ export class ReplEditor extends EditorPane implements IEditorPaneWithScrolling { } })); - this._codeEditorWidget.onDidChangeModelDecorations(() => { + this._widgetDisposableStore.add(this._codeEditorWidget.onDidChangeModelDecorations(() => { if (this.isVisible()) { this._updateInputHint(); } - }); + })); const cursorAtBoundaryContext = INTERACTIVE_INPUT_CURSOR_BOUNDARY.bindTo(this._contextKeyService); if (input.resource && input.historyService.has(input.resource)) { From 0147a67f7511ce17f6e81463d4de9404ba422275 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:01:13 -0700 Subject: [PATCH 148/236] Polish AI search toggle UX (#251045) --- .../preferences/browser/media/settingsEditor2.css | 11 ++++++++--- .../relauncher/browser/relauncher.contribution.ts | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index fe8258a1ce4..a4f800ab02f 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -60,19 +60,24 @@ top: 0; right: 0; height: 100%; - width: 43px; + width: 44px; } .settings-editor > .settings-header > .search-container.with-ai-toggle > .settings-clear-widget { - width: 62px; + width: 66px; } .settings-editor > .settings-header > .search-container > .settings-clear-widget .action-label { - padding: 2px; + padding: 3px; margin-left: 0px; box-sizing: content-box; } +.settings-editor > .settings-header > .search-container > .settings-clear-widget .action-label.monaco-custom-toggle { + /* To offset the border width. */ + padding: 2.3px; +} + .settings-editor > .settings-header > .settings-header-controls { display: flex; flex-wrap: wrap; diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index 674ff723e53..70fa6878812 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -30,7 +30,7 @@ interface IConfiguration extends IWindowsConfiguration { editor?: { accessibilitySupport?: 'on' | 'off' | 'auto' }; security?: { workspace?: { trust?: { enabled?: boolean } }; restrictUNCAccess?: boolean }; window: IWindowSettings; - workbench?: { enableExperiments?: boolean; settings?: { showSuggestions?: boolean } }; + workbench?: { enableExperiments?: boolean; settings?: { showAISearchToggle?: boolean } }; telemetry?: { feedback?: { enabled?: boolean } }; _extensionsGallery?: { enablePPE?: boolean }; accessibility?: { verbosity?: { debug?: boolean } }; @@ -73,7 +73,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private readonly accessibilityVerbosityDebug = new ChangeObserver('boolean'); private readonly useFileStorage = new ChangeObserver('boolean'); private readonly telemetryFeedbackEnabled = new ChangeObserver('boolean'); - private readonly showSuggestions = new ChangeObserver('boolean'); + private readonly showAISearchToggle = new ChangeObserver('boolean'); constructor( @IHostService private readonly hostService: IHostService, @@ -169,7 +169,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo processChanged(this.telemetryFeedbackEnabled.handleChange(config.telemetry?.feedback?.enabled)); // Settings editor suggestions - processChanged(this.showSuggestions.handleChange(config.workbench?.settings?.showSuggestions)); + processChanged(this.showAISearchToggle.handleChange(config.workbench?.settings?.showAISearchToggle)); if (askToRelaunch && changed && this.hostService.hasFocus) { this.doConfirm( From 433220e98a439b35185da25b89976115a274b014 Mon Sep 17 00:00:00 2001 From: Robo Date: Tue, 10 Jun 2025 12:36:07 +0900 Subject: [PATCH 149/236] fix: smoke tests for stable with editcontext enabled (#251055) --- test/automation/src/editor.ts | 3 +-- test/automation/src/editors.ts | 3 +-- test/automation/src/extensions.ts | 3 +-- test/automation/src/notebook.ts | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/test/automation/src/editor.ts b/test/automation/src/editor.ts index 6587b28edaf..0a7ccceb724 100644 --- a/test/automation/src/editor.ts +++ b/test/automation/src/editor.ts @@ -6,7 +6,6 @@ import { References } from './peek'; import { Commands } from './workbench'; import { Code } from './code'; -import { Quality } from './application'; const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box'; const RENAME_INPUT = `${RENAME_BOX} .rename-input`; @@ -107,7 +106,7 @@ export class Editor { } private _editContextSelector() { - return this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'; + return '.native-edit-context'; } async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise { diff --git a/test/automation/src/editors.ts b/test/automation/src/editors.ts index b2321e947de..03560a3c1c6 100644 --- a/test/automation/src/editors.ts +++ b/test/automation/src/editors.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Quality } from './application'; import { Code } from './code'; export class Editors { @@ -53,7 +52,7 @@ export class Editors { } async waitForActiveEditor(fileName: string, retryCount?: number): Promise { - const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`; + const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] .native-edit-context`; return this.code.waitForActiveElement(selector, retryCount); } diff --git a/test/automation/src/extensions.ts b/test/automation/src/extensions.ts index 06bd324465f..7e3c5b48afa 100644 --- a/test/automation/src/extensions.ts +++ b/test/automation/src/extensions.ts @@ -8,7 +8,6 @@ import { Code } from './code'; import { ncp } from 'ncp'; import { promisify } from 'util'; import { Commands } from './workbench'; -import { Quality } from './application'; import path = require('path'); import fs = require('fs'); @@ -21,7 +20,7 @@ export class Extensions extends Viewlet { async searchForExtension(id: string): Promise { await this.commands.runCommand('Extensions: Focus on Extensions View', { exactLabelMatch: true }); - await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`, `@id:${id}`); + await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor .native-edit-context`, `@id:${id}`); await this.code.waitForTextContent(`div.part.sidebar div.composite.title h2`, 'Extensions: Marketplace'); let retrials = 1; diff --git a/test/automation/src/notebook.ts b/test/automation/src/notebook.ts index 3ba9101a1de..6dbe995f4b6 100644 --- a/test/automation/src/notebook.ts +++ b/test/automation/src/notebook.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Quality } from './application'; import { Code } from './code'; import { QuickAccess } from './quickaccess'; import { QuickInput } from './quickinput'; @@ -47,7 +46,7 @@ export class Notebook { await this.code.waitForElement(editor); - const editContext = `${editor} ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`; + const editContext = `${editor} .native-edit-context`; await this.code.waitForActiveElement(editContext); await this.code.waitForTypeInEditor(editContext, text); From da3bdf1b148709b5e7b13194f57d261a0ee3fe6e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Jun 2025 07:48:22 +0200 Subject: [PATCH 150/236] notifications - add and use `withSeverityPrefix` (#251067) --- .../notification/common/notification.ts | 17 +++++++++++++++++ .../notifications/notificationAccessibleView.ts | 11 ++++------- .../notifications/notificationsCommands.ts | 12 +----------- .../parts/notifications/notificationsList.ts | 14 +++++++------- .../parts/notifications/notificationsToasts.ts | 13 +++++-------- .../notebook/browser/notebookAccessibleView.ts | 1 - 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index f1101520856..a2f59a71fab 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { localize } from '../../../nls.js'; import { IAction } from '../../../base/common/actions.js'; import { Event } from '../../../base/common/event.js'; import BaseSeverity from '../../../base/common/severity.js'; @@ -472,3 +473,19 @@ export class NoOpProgress implements INotificationProgress { total(value: number): void { } worked(value: number): void { } } + +export function withSeverityPrefix(label: string, severity: Severity): string { + + // Add severity prefix to match WCAG 4.1.3 Status + // Messages requirements. + + if (severity === Severity.Error) { + return localize('severityPrefix.error', "Error: {0}", label); + } + + if (severity === Severity.Warning) { + return localize('severityPrefix.warning', "Warning: {0}", label); + } + + return localize('severityPrefix.info', "Info: {0}", label); +} diff --git a/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts b/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts index 59bf3253259..62cd08fa022 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationAccessibleView.ts @@ -13,9 +13,10 @@ import { IAccessibilitySignalService, AccessibilitySignal } from '../../../../pl import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { IListService, WorkbenchList } from '../../../../platform/list/browser/listService.js'; -import { getNotificationFromContext, getSeverityPrefix } from './notificationsCommands.js'; +import { getNotificationFromContext } from './notificationsCommands.js'; import { NotificationFocusedContext } from '../../../common/contextkeys.js'; import { INotificationViewItem } from '../../../common/notifications.js'; +import { withSeverityPrefix } from '../../../../platform/notification/common/notification.js'; export class NotificationAccessibleView implements IAccessibleViewImplementation { readonly priority = 90; @@ -56,14 +57,10 @@ export class NotificationAccessibleView implements IAccessibleViewImplementation function getContentForNotification(): string | undefined { const notification = getNotificationFromContext(listService); const message = notification?.message.original.toString(); - if (!notification) { + if (!notification || !message) { return; } - // Add severity prefix to match WCAG 4.1.3 Status Messages requirements - const severityPrefix = getSeverityPrefix(notification.severity); - const messageWithSeverity = `${severityPrefix}${message}`; - - return notification.source ? localize('notification.accessibleViewSrc', '{0} Source: {1}', messageWithSeverity, notification.source) : localize('notification.accessibleView', '{0}', messageWithSeverity); + return withSeverityPrefix(notification.source ? localize('notification.accessibleViewSrc', '{0} Source: {1}', message, notification.source) : message, notification.severity); } const content = getContentForNotification(); if (!content) { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts index 59bc44f6a35..d3fff55ef7c 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts @@ -13,7 +13,7 @@ import { localize, localize2 } from '../../../../nls.js'; import { IListService, WorkbenchList } from '../../../../platform/list/browser/listService.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { NotificationFocusedContext, NotificationsCenterVisibleContext, NotificationsToastsVisibleContext } from '../../../common/contextkeys.js'; -import { INotificationService, INotificationSourceFilter, NotificationsFilter, Severity } from '../../../../platform/notification/common/notification.js'; +import { INotificationService, INotificationSourceFilter, NotificationsFilter } from '../../../../platform/notification/common/notification.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ActionRunner, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from '../../../../base/common/actions.js'; import { IQuickInputService, IQuickPickItem } from '../../../../platform/quickinput/common/quickInput.js'; @@ -88,16 +88,6 @@ export function getNotificationFromContext(listService: IListService, context?: return undefined; } -export function getSeverityPrefix(severity: Severity): string { - if (severity === Severity.Error) { - return localize('severityPrefix.error', "Error: "); - } else if (severity === Severity.Warning) { - return localize('severityPrefix.warning', "Warning: "); - } else { - return localize('severityPrefix.info', "Info: "); - } -} - export function registerNotificationCommands(center: INotificationsCenterController, toasts: INotificationsToastController, model: NotificationsModel): void { // Show Notifications Cneter diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index fb0dd7d4fab..5cefc315325 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -18,9 +18,10 @@ import { assertReturnsAllDefined } from '../../../../base/common/types.js'; import { NotificationFocusedContext } from '../../../common/contextkeys.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { AriaRole } from '../../../../base/browser/ui/aria/aria.js'; -import { getSeverityPrefix, NotificationActionRunner } from './notificationsCommands.js'; +import { NotificationActionRunner } from './notificationsCommands.js'; import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; +import { withSeverityPrefix } from '../../../../platform/notification/common/notification.js'; export interface INotificationsListOptions extends IListOptions { readonly widgetAriaLabel?: string; @@ -245,11 +246,13 @@ export class NotificationsList extends Disposable { } export class NotificationAccessibilityProvider implements IListAccessibilityProvider { + constructor( private readonly _options: INotificationsListOptions, @IKeybindingService private readonly _keybindingService: IKeybindingService, @IConfigurationService private readonly _configurationService: IConfigurationService ) { } + getAriaLabel(element: INotificationViewItem): string { let accessibleViewHint: string | undefined; const keybinding = this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel(); @@ -257,20 +260,17 @@ export class NotificationAccessibilityProvider implements IListAccessibilityProv accessibleViewHint = keybinding ? localize('notificationAccessibleViewHint', "Inspect the response in the accessible view with {0}", keybinding) : localize('notificationAccessibleViewHintNoKb', "Inspect the response in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding"); } - // Add severity prefix to match WCAG 4.1.3 Status Messages requirements - const severityPrefix = getSeverityPrefix(element.severity); - const messageWithSeverity = `${severityPrefix}${element.message.raw}`; - if (!element.source) { - return accessibleViewHint ? localize('notificationAriaLabelHint', "{0}, notification, {1}", messageWithSeverity, accessibleViewHint) : localize('notificationAriaLabel', "{0}, notification", messageWithSeverity); + return withSeverityPrefix(accessibleViewHint ? localize('notificationAriaLabelHint', "{0}, notification, {1}", element.message.raw, accessibleViewHint) : localize('notificationAriaLabel', "{0}, notification", element.message.raw), element.severity); } - return accessibleViewHint ? localize('notificationWithSourceAriaLabelHint', "{0}, source: {1}, notification, {2}", messageWithSeverity, element.source, accessibleViewHint) : localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", messageWithSeverity, element.source); + return withSeverityPrefix(accessibleViewHint ? localize('notificationWithSourceAriaLabelHint', "{0}, source: {1}, notification, {2}", element.message.raw, element.source, accessibleViewHint) : localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", element.message.raw, element.source), element.severity); } getWidgetAriaLabel(): string { return this._options.widgetAriaLabel ?? localize('notificationsList', "Notifications List"); } + getRole(): AriaRole { return 'dialog'; // https://github.com/microsoft/vscode/issues/82728 } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index 8bff6b06d5d..b74fdf56371 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -16,9 +16,9 @@ import { NOTIFICATIONS_TOAST_BORDER, NOTIFICATIONS_BACKGROUND } from '../../../c import { IThemeService, Themable } from '../../../../platform/theme/common/themeService.js'; import { widgetShadow } from '../../../../platform/theme/common/colorRegistry.js'; import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; -import { getSeverityPrefix, INotificationsToastController } from './notificationsCommands.js'; +import { INotificationsToastController } from './notificationsCommands.js'; import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { Severity, NotificationsFilter, NotificationPriority } from '../../../../platform/notification/common/notification.js'; +import { Severity, NotificationsFilter, NotificationPriority, withSeverityPrefix } from '../../../../platform/notification/common/notification.js'; import { ScrollbarVisibility } from '../../../../base/common/scrollable.js'; import { ILifecycleService, LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js'; import { IHostService } from '../../../services/host/browser/host.js'; @@ -200,14 +200,11 @@ export class NotificationsToasts extends Themable implements INotificationsToast const notificationList = this.instantiationService.createInstance(NotificationsList, notificationToast, { verticalScrollMode: ScrollbarVisibility.Hidden, widgetAriaLabel: (() => { - // Add severity prefix to match WCAG 4.1.3 Status Messages requirements - const severityPrefix = getSeverityPrefix(item.severity); - const messageWithSeverity = `${severityPrefix}${item.message.raw}`; - if (!item.source) { - return localize('notificationAriaLabel', "{0}, notification", messageWithSeverity); + return withSeverityPrefix(localize('notificationAriaLabel', "{0}, notification", item.message.raw), item.severity); } - return localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", messageWithSeverity, item.source); + + return withSeverityPrefix(localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", item.message.raw, item.source), item.severity); })() }); itemDisposables.add(notificationList); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookAccessibleView.ts b/src/vs/workbench/contrib/notebook/browser/notebookAccessibleView.ts index 56e6d347e4e..96ea911c866 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookAccessibleView.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookAccessibleView.ts @@ -24,7 +24,6 @@ export class NotebookAccessibleView implements IAccessibleViewImplementation { } } - export function getAccessibleOutputProvider(editorService: IEditorService) { const activePane = editorService.activeEditorPane; const notebookEditor = getNotebookEditorFromEditorPane(activePane); From 510bd45c20e029a5b4b96fdf6c25c617507db020 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Jun 2025 07:48:44 +0200 Subject: [PATCH 151/236] debt - reduce some explicit `any` (#251073) --- src/vs/base/node/nodeStreams.ts | 4 ++-- src/vs/base/node/ports.ts | 2 +- src/vs/editor/common/languageFeatureRegistry.ts | 4 ++-- src/vs/editor/common/services/textResourceConfiguration.ts | 2 +- .../common/services/textResourceConfigurationService.ts | 6 +++--- src/vs/editor/editor.worker.start.ts | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/base/node/nodeStreams.ts b/src/vs/base/node/nodeStreams.ts index 0dba130a07d..a7516e1e598 100644 --- a/src/vs/base/node/nodeStreams.ts +++ b/src/vs/base/node/nodeStreams.ts @@ -28,7 +28,7 @@ export class StreamSplitter extends Transform { } } - override _transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null, data?: any) => void): void { + override _transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null, data?: Buffer) => void): void { if (!this.buffer) { this.buffer = chunk; } else { @@ -52,7 +52,7 @@ export class StreamSplitter extends Transform { callback(); } - override _flush(callback: (error?: Error | null, data?: any) => void): void { + override _flush(callback: (error?: Error | null, data?: Buffer) => void): void { if (this.buffer) { this.push(this.buffer); } diff --git a/src/vs/base/node/ports.ts b/src/vs/base/node/ports.ts index b664a8a0f4e..a237f433ea0 100644 --- a/src/vs/base/node/ports.ts +++ b/src/vs/base/node/ports.ts @@ -64,7 +64,7 @@ function doFindFreePort(startPort: number, giveUpAfter: number, stride: number, } // Reference: https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/net/base/port_util.cc#56 -export const BROWSER_RESTRICTED_PORTS: any = { +export const BROWSER_RESTRICTED_PORTS: Record = { 1: true, // tcpmux 7: true, // echo 9: true, // discard diff --git a/src/vs/editor/common/languageFeatureRegistry.ts b/src/vs/editor/common/languageFeatureRegistry.ts index 6bf6f851720..3728cad3c41 100644 --- a/src/vs/editor/common/languageFeatureRegistry.ts +++ b/src/vs/editor/common/languageFeatureRegistry.ts @@ -139,7 +139,7 @@ export class LanguageFeatureRegistry { return result; } - private _orderedForEach(model: ITextModel, recursive: boolean, callback: (provider: Entry) => any): void { + private _orderedForEach(model: ITextModel, recursive: boolean, callback: (provider: Entry) => void): void { this._updateScores(model, recursive); @@ -191,7 +191,7 @@ export class LanguageFeatureRegistry { this._entries.sort(LanguageFeatureRegistry._compareByScoreAndTime); } - private static _compareByScoreAndTime(a: Entry, b: Entry): number { + private static _compareByScoreAndTime(a: Entry, b: Entry): number { if (a._score < b._score) { return 1; } else if (a._score > b._score) { diff --git a/src/vs/editor/common/services/textResourceConfiguration.ts b/src/vs/editor/common/services/textResourceConfiguration.ts index da2c0a8b653..70975287424 100644 --- a/src/vs/editor/common/services/textResourceConfiguration.ts +++ b/src/vs/editor/common/services/textResourceConfiguration.ts @@ -72,7 +72,7 @@ export interface ITextResourceConfigurationService { * @param configurationTarget Optional target into which the configuration has to be updated. * If not specified, target will be derived by checking where the configuration is defined. */ - updateValue(resource: URI | undefined, key: string, value: any, configurationTarget?: ConfigurationTarget): Promise; + updateValue(resource: URI | undefined, key: string, value: unknown, configurationTarget?: ConfigurationTarget): Promise; } diff --git a/src/vs/editor/common/services/textResourceConfigurationService.ts b/src/vs/editor/common/services/textResourceConfigurationService.ts index 85ef41882c4..6eda008b6ef 100644 --- a/src/vs/editor/common/services/textResourceConfigurationService.ts +++ b/src/vs/editor/common/services/textResourceConfigurationService.ts @@ -30,14 +30,14 @@ export class TextResourceConfigurationService extends Disposable implements ITex getValue(resource: URI | undefined, section?: string): T; getValue(resource: URI | undefined, at?: IPosition, section?: string): T; - getValue(resource: URI | undefined, arg2?: any, arg3?: any): T { + getValue(resource: URI | undefined, arg2?: unknown, arg3?: unknown): T { if (typeof arg3 === 'string') { return this._getValue(resource, Position.isIPosition(arg2) ? arg2 : null, arg3); } return this._getValue(resource, null, typeof arg2 === 'string' ? arg2 : undefined); } - updateValue(resource: URI | undefined, key: string, value: any, configurationTarget?: ConfigurationTarget): Promise { + updateValue(resource: URI | undefined, key: string, value: unknown, configurationTarget?: ConfigurationTarget): Promise { const language = resource ? this.getLanguage(resource, null) : null; const configurationValue = this.configurationService.inspect(key, { resource, overrideIdentifier: language }); if (configurationTarget === undefined) { @@ -47,7 +47,7 @@ export class TextResourceConfigurationService extends Disposable implements ITex return this.configurationService.updateValue(key, value, { resource, overrideIdentifier }, configurationTarget); } - private deriveConfigurationTarget(configurationValue: IConfigurationValue, language: string | null): ConfigurationTarget { + private deriveConfigurationTarget(configurationValue: IConfigurationValue, language: string | null): ConfigurationTarget { if (language) { if (configurationValue.memory?.override !== undefined) { return ConfigurationTarget.MEMORY; diff --git a/src/vs/editor/editor.worker.start.ts b/src/vs/editor/editor.worker.start.ts index 9906249af9d..a7304493087 100644 --- a/src/vs/editor/editor.worker.start.ts +++ b/src/vs/editor/editor.worker.start.ts @@ -20,7 +20,7 @@ export function start(client: TCli if (typeof prop !== 'string') { throw new Error(`Not supported`); } - return (...args: any[]) => { + return (...args: unknown[]) => { return editorWorkerHost.$fhr(prop, args); }; } From 94a9756f46480ccb4c32883506b636e165fdba1a Mon Sep 17 00:00:00 2001 From: Robo Date: Tue, 10 Jun 2025 15:47:30 +0900 Subject: [PATCH 152/236] Revert "fix: smoke tests for stable with editcontext enabled (#251055)" (#251075) This reverts commit 433220e98a439b35185da25b89976115a274b014. --- test/automation/src/editor.ts | 3 ++- test/automation/src/editors.ts | 3 ++- test/automation/src/extensions.ts | 3 ++- test/automation/src/notebook.ts | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/automation/src/editor.ts b/test/automation/src/editor.ts index 0a7ccceb724..6587b28edaf 100644 --- a/test/automation/src/editor.ts +++ b/test/automation/src/editor.ts @@ -6,6 +6,7 @@ import { References } from './peek'; import { Commands } from './workbench'; import { Code } from './code'; +import { Quality } from './application'; const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box'; const RENAME_INPUT = `${RENAME_BOX} .rename-input`; @@ -106,7 +107,7 @@ export class Editor { } private _editContextSelector() { - return '.native-edit-context'; + return this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'; } async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise { diff --git a/test/automation/src/editors.ts b/test/automation/src/editors.ts index 03560a3c1c6..b2321e947de 100644 --- a/test/automation/src/editors.ts +++ b/test/automation/src/editors.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Quality } from './application'; import { Code } from './code'; export class Editors { @@ -52,7 +53,7 @@ export class Editors { } async waitForActiveEditor(fileName: string, retryCount?: number): Promise { - const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] .native-edit-context`; + const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`; return this.code.waitForActiveElement(selector, retryCount); } diff --git a/test/automation/src/extensions.ts b/test/automation/src/extensions.ts index 7e3c5b48afa..06bd324465f 100644 --- a/test/automation/src/extensions.ts +++ b/test/automation/src/extensions.ts @@ -8,6 +8,7 @@ import { Code } from './code'; import { ncp } from 'ncp'; import { promisify } from 'util'; import { Commands } from './workbench'; +import { Quality } from './application'; import path = require('path'); import fs = require('fs'); @@ -20,7 +21,7 @@ export class Extensions extends Viewlet { async searchForExtension(id: string): Promise { await this.commands.runCommand('Extensions: Focus on Extensions View', { exactLabelMatch: true }); - await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor .native-edit-context`, `@id:${id}`); + await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`, `@id:${id}`); await this.code.waitForTextContent(`div.part.sidebar div.composite.title h2`, 'Extensions: Marketplace'); let retrials = 1; diff --git a/test/automation/src/notebook.ts b/test/automation/src/notebook.ts index 6dbe995f4b6..3ba9101a1de 100644 --- a/test/automation/src/notebook.ts +++ b/test/automation/src/notebook.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Quality } from './application'; import { Code } from './code'; import { QuickAccess } from './quickaccess'; import { QuickInput } from './quickinput'; @@ -46,7 +47,7 @@ export class Notebook { await this.code.waitForElement(editor); - const editContext = `${editor} .native-edit-context`; + const editContext = `${editor} ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`; await this.code.waitForActiveElement(editContext); await this.code.waitForTypeInEditor(editContext, text); From d24baf2b6e090440d79468ff911ecc66a91c0b54 Mon Sep 17 00:00:00 2001 From: Robo Date: Tue, 10 Jun 2025 15:47:49 +0900 Subject: [PATCH 153/236] fix: revert to NSAccessibilityStaticTextRole for list elements (#251057) * chore: update electron build * chore: bump distro --- .npmrc | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.npmrc b/.npmrc index c92d74a4227..3d79d10ff8f 100644 --- a/.npmrc +++ b/.npmrc @@ -1,6 +1,6 @@ disturl="https://electronjs.org/headers" target="35.5.1" -ms_build_id="11708675" +ms_build_id="11727614" runtime="electron" build_from_source="true" legacy-peer-deps="true" diff --git a/package.json b/package.json index 49da9b08d69..d78d007e580 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.102.0", - "distro": "1f9299d1fbccfb501bade57b42c8d343c1e4b5a5", + "distro": "3c2b3776c5752c7f7dd69d3f1a9b6079ae890a16", "author": { "name": "Microsoft Corporation" }, From a1e32e76e3381bed53c96647da92d52959072697 Mon Sep 17 00:00:00 2001 From: Aaron Munger <2019016+amunger@users.noreply.github.com> Date: Tue, 10 Jun 2025 00:10:01 -0700 Subject: [PATCH 154/236] ensure the editor model always has a valid selection value (#251032) --- .../api/common/extHostNotebookEditor.ts | 15 ++--- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../viewModel/cellSelectionCollection.ts | 31 +++------ .../test/browser/notebookSelection.test.ts | 63 ++++++++++++++++++- 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebookEditor.ts b/src/vs/workbench/api/common/extHostNotebookEditor.ts index a007ca50e2d..f864395dbe6 100644 --- a/src/vs/workbench/api/common/extHostNotebookEditor.ts +++ b/src/vs/workbench/api/common/extHostNotebookEditor.ts @@ -18,19 +18,16 @@ export class ExtHostNotebookEditor { private _visible: boolean = false; private _editor?: vscode.NotebookEditor; - private _selections: vscode.NotebookRange[] = [new NotebookRange(0, 0)]; constructor( readonly id: string, private readonly _proxy: MainThreadNotebookEditorsShape, readonly notebookData: ExtHostNotebookDocument, private _visibleRanges: vscode.NotebookRange[], - selections: vscode.NotebookRange[], + private _selections: vscode.NotebookRange[], private _viewColumn: vscode.ViewColumn | undefined, private readonly viewType: string - ) { - this._selections = this._validSelections(selections); - } + ) { } get apiEditor(): vscode.NotebookEditor { if (!this._editor) { @@ -52,7 +49,7 @@ export class ExtHostNotebookEditor { if (!Array.isArray(value) || !value.every(extHostTypes.NotebookRange.isNotebookRange)) { throw illegalArgument('selections'); } - that._selections = that._validSelections(value); + that._selections = value.length === 0 ? [new NotebookRange(0, 0)] : value; that._trySetSelections(that._selections); }, get visibleRanges() { @@ -97,7 +94,7 @@ export class ExtHostNotebookEditor { } _acceptSelections(selections: vscode.NotebookRange[]): void { - this._selections = this._validSelections(selections); + this._selections = selections; } private _trySetSelections(value: vscode.NotebookRange[]): void { @@ -107,8 +104,4 @@ export class ExtHostNotebookEditor { _acceptViewColumn(value: vscode.ViewColumn | undefined) { this._viewColumn = value; } - - private _validSelections(selections: vscode.NotebookRange[]) { - return selections.length === 0 ? [new NotebookRange(0, 0)] : selections; - } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 3a946890acf..e7b1965ac3e 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -496,7 +496,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } getSelections() { - return this.viewModel?.getSelections() ?? []; + return this.viewModel?.getSelections() ?? [{ start: 0, end: 0 }]; } setSelections(selections: ICellRange[]) { diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/cellSelectionCollection.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/cellSelectionCollection.ts index d66657a4701..2f56ee0758e 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/cellSelectionCollection.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/cellSelectionCollection.ts @@ -5,21 +5,7 @@ import { Emitter, Event } from '../../../../../base/common/event.js'; import { Disposable } from '../../../../../base/common/lifecycle.js'; -import { ICellRange } from '../../common/notebookRange.js'; - -function rangesEqual(a: ICellRange[], b: ICellRange[]) { - if (a.length !== b.length) { - return false; - } - - for (let i = 0; i < a.length; i++) { - if (a[i].start !== b[i].start || a[i].end !== b[i].end) { - return false; - } - } - - return true; -} +import { cellRangesEqual, ICellRange } from '../../common/notebookRange.js'; // Challenge is List View talks about `element`, which needs extra work to convert to ICellRange as we support Folding and Cell Move export class NotebookCellSelectionCollection extends Disposable { @@ -27,23 +13,26 @@ export class NotebookCellSelectionCollection extends Disposable { private readonly _onDidChangeSelection = this._register(new Emitter()); get onDidChangeSelection(): Event { return this._onDidChangeSelection.event; } - private _primary: ICellRange | null = null; + private _primary: ICellRange = { start: 0, end: 0 }; - private _selections: ICellRange[] = []; + private _selections: ICellRange[] = [{ start: 0, end: 0 }]; get selections(): ICellRange[] { return this._selections; } get focus(): ICellRange { - return this._primary ?? { start: 0, end: 0 }; + return this._primary; } setState(primary: ICellRange | null, selections: ICellRange[], forceEventEmit: boolean, source: 'view' | 'model') { - const changed = primary !== this._primary || !rangesEqual(this._selections, selections); + const validPrimary = primary ?? { start: 0, end: 0 }; + const validSelections = selections.length > 0 ? selections : [{ start: 0, end: 0 }]; - this._primary = primary; - this._selections = selections; + const changed = !cellRangesEqual([validPrimary], [this._primary]) || !cellRangesEqual(this._selections, validSelections); + + this._primary = validPrimary; + this._selections = validSelections; if (changed || forceEventEmit) { this._onDidChangeSelection.fire(source); } diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts index 05072b46b2e..ee55b5c5988 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookSelection.test.ts @@ -15,7 +15,7 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/tes import { DisposableStore } from '../../../../../base/common/lifecycle.js'; suite('NotebookSelection', () => { - ensureNoDisposablesAreLeakedInTestSuite(); + const store = ensureNoDisposablesAreLeakedInTestSuite(); test('focus is never empty', function () { const selectionCollection = new NotebookCellSelectionCollection(); @@ -25,6 +25,64 @@ suite('NotebookSelection', () => { assert.deepStrictEqual(selectionCollection.focus, { start: 0, end: 0 }); selectionCollection.dispose(); }); + + test('selection is never empty', function () { + const selectionCollection = new NotebookCellSelectionCollection(); + assert.deepStrictEqual(selectionCollection.selections, [{ start: 0, end: 0 }]); + + selectionCollection.setState(null, [], true, 'model'); + assert.deepStrictEqual(selectionCollection.selections, [{ start: 0, end: 0 }]); + selectionCollection.dispose(); + }); + + test('selections does not change when setting to empty', function () { + const selectionCollection = new NotebookCellSelectionCollection(); + let changed = false; + store.add(selectionCollection.onDidChangeSelection(() => { + changed = true; + })); + + selectionCollection.setState(null, [], false, 'model'); + assert.strictEqual(changed, false); + selectionCollection.setState({ start: 0, end: 0 }, [], false, 'model'); + assert.strictEqual(changed, false); + selectionCollection.setState({ start: 0, end: 0 }, [{ start: 0, end: 0 }], false, 'model'); + assert.strictEqual(changed, false); + selectionCollection.setState(null, [], false, 'model'); + assert.strictEqual(changed, false); + selectionCollection.dispose(); + }); + + test('event fires when selection or focus changes', function () { + const selectionCollection = new NotebookCellSelectionCollection(); + let eventCount = 0; + store.add(selectionCollection.onDidChangeSelection(() => { + eventCount++; + })); + + // Change focus + selectionCollection.setState({ start: 1, end: 1 }, [{ start: 1, end: 2 }], false, 'model'); + assert.strictEqual(eventCount, 1); + + // Change selections + selectionCollection.setState({ start: 1, end: 1 }, [{ start: 1, end: 2 }, { start: 2, end: 3 }], false, 'model'); + assert.strictEqual(eventCount, 2); + + // no change + selectionCollection.setState({ start: 1, end: 1 }, [{ start: 1, end: 2 }, { start: 2, end: 3 }], false, 'model'); + assert.strictEqual(eventCount, 2); + + // change to empty focus + selectionCollection.setState({ start: 0, end: 0 }, [{ start: 4, end: 5 }], false, 'model'); + assert.strictEqual(eventCount, 3); + + // change to empty selections + selectionCollection.setState({ start: 0, end: 0 }, [], false, 'model'); + assert.strictEqual(eventCount, 4); + + selectionCollection.dispose(); + }); + }); suite('NotebookCellList focus/selection', () => { @@ -312,6 +370,9 @@ suite('NotebookCellList focus/selection', () => { // viewModel.deleteCell(1, true, false); assert.deepStrictEqual(viewModel.getFocus(), { start: 0, end: 1 }); assert.deepStrictEqual(viewModel.getSelections(), [{ start: 0, end: 1 }]); + runDeleteAction(editor, viewModel.cellAt(0)!); + assert.deepStrictEqual(viewModel.getFocus(), { start: 0, end: 0 }); + assert.deepStrictEqual(viewModel.getSelections(), [{ start: 0, end: 0 }]); }); }); From 7e4d8e92bcd2246daa376a325a72fccf10087a11 Mon Sep 17 00:00:00 2001 From: Robo Date: Tue, 10 Jun 2025 16:44:09 +0900 Subject: [PATCH 155/236] (Reland) fix: smoke tests for stable with editcontext enabled (#251074) --- test/automation/src/code.ts | 12 +++++++++--- test/automation/src/debug.ts | 3 +-- test/automation/src/editor.ts | 3 +-- test/automation/src/editors.ts | 3 +-- test/automation/src/extensions.ts | 3 +-- test/automation/src/notebook.ts | 3 +-- test/automation/src/scm.ts | 3 +-- test/automation/src/settings.ts | 11 +++++------ test/smoke/src/areas/workbench/data-loss.test.ts | 8 +++++--- test/smoke/src/main.ts | 5 ++++- 10 files changed, 29 insertions(+), 25 deletions(-) diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index ae612626c9e..d3c697873a1 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -30,6 +30,7 @@ export interface LaunchOptions { readonly headless?: boolean; readonly browser?: 'chromium' | 'webkit' | 'firefox' | 'chromium-msedge' | 'chromium-chrome'; readonly quality: Quality; + version: { major: number; minor: number; patch: number }; } interface ICodeInstance { @@ -89,7 +90,7 @@ export async function launch(options: LaunchOptions): Promise { const { serverProcess, driver } = await measureAndLog(() => launchPlaywrightBrowser(options), 'launch playwright (browser)', options.logger); registerInstance(serverProcess, options.logger, 'server'); - return new Code(driver, options.logger, serverProcess, undefined, options.quality); + return new Code(driver, options.logger, serverProcess, undefined, options.quality, options.version); } // Electron smoke tests (playwright) @@ -97,7 +98,7 @@ export async function launch(options: LaunchOptions): Promise { const { electronProcess, driver } = await measureAndLog(() => launchPlaywrightElectron(options), 'launch playwright (electron)', options.logger); const { safeToKill } = registerInstance(electronProcess, options.logger, 'electron'); - return new Code(driver, options.logger, electronProcess, safeToKill, options.quality); + return new Code(driver, options.logger, electronProcess, safeToKill, options.quality, options.version); } } @@ -110,7 +111,8 @@ export class Code { readonly logger: Logger, private readonly mainProcess: cp.ChildProcess, private readonly safeToKill: Promise | undefined, - readonly quality: Quality + readonly quality: Quality, + readonly version: { major: number; minor: number; patch: number } ) { this.driver = new Proxy(driver, { get(target, prop) { @@ -131,6 +133,10 @@ export class Code { }); } + get editContextEnabled(): boolean { + return !(this.quality === Quality.Stable && this.version.major === 1 && this.version.minor < 101); + } + async startTracing(name: string): Promise { return await this.driver.startTracing(name); } diff --git a/test/automation/src/debug.ts b/test/automation/src/debug.ts index 43f974ebec9..2b8623bb013 100644 --- a/test/automation/src/debug.ts +++ b/test/automation/src/debug.ts @@ -9,7 +9,6 @@ import { Code, findElement } from './code'; import { Editors } from './editors'; import { Editor } from './editor'; import { IElement } from './driver'; -import { Quality } from './application'; const VIEWLET = 'div[id="workbench.view.debug"]'; const DEBUG_VIEW = `${VIEWLET}`; @@ -133,7 +132,7 @@ export class Debug extends Viewlet { async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise { await this.commands.runCommand('Debug: Focus on Debug Console View'); - const selector = this.code.quality === Quality.Stable ? REPL_FOCUSED_TEXTAREA : REPL_FOCUSED_NATIVE_EDIT_CONTEXT; + const selector = !this.code.editContextEnabled ? REPL_FOCUSED_TEXTAREA : REPL_FOCUSED_NATIVE_EDIT_CONTEXT; await this.code.waitForActiveElement(selector); await this.code.waitForSetValue(selector, text); diff --git a/test/automation/src/editor.ts b/test/automation/src/editor.ts index 6587b28edaf..37e152d3e66 100644 --- a/test/automation/src/editor.ts +++ b/test/automation/src/editor.ts @@ -6,7 +6,6 @@ import { References } from './peek'; import { Commands } from './workbench'; import { Code } from './code'; -import { Quality } from './application'; const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box'; const RENAME_INPUT = `${RENAME_BOX} .rename-input`; @@ -107,7 +106,7 @@ export class Editor { } private _editContextSelector() { - return this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'; + return !this.code.editContextEnabled ? 'textarea' : '.native-edit-context'; } async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise { diff --git a/test/automation/src/editors.ts b/test/automation/src/editors.ts index b2321e947de..0f2e54722d0 100644 --- a/test/automation/src/editors.ts +++ b/test/automation/src/editors.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Quality } from './application'; import { Code } from './code'; export class Editors { @@ -53,7 +52,7 @@ export class Editors { } async waitForActiveEditor(fileName: string, retryCount?: number): Promise { - const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`; + const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] ${!this.code.editContextEnabled ? 'textarea' : '.native-edit-context'}`; return this.code.waitForActiveElement(selector, retryCount); } diff --git a/test/automation/src/extensions.ts b/test/automation/src/extensions.ts index 06bd324465f..8c40cdff0de 100644 --- a/test/automation/src/extensions.ts +++ b/test/automation/src/extensions.ts @@ -8,7 +8,6 @@ import { Code } from './code'; import { ncp } from 'ncp'; import { promisify } from 'util'; import { Commands } from './workbench'; -import { Quality } from './application'; import path = require('path'); import fs = require('fs'); @@ -21,7 +20,7 @@ export class Extensions extends Viewlet { async searchForExtension(id: string): Promise { await this.commands.runCommand('Extensions: Focus on Extensions View', { exactLabelMatch: true }); - await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`, `@id:${id}`); + await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor ${!this.code.editContextEnabled ? 'textarea' : '.native-edit-context'}`, `@id:${id}`); await this.code.waitForTextContent(`div.part.sidebar div.composite.title h2`, 'Extensions: Marketplace'); let retrials = 1; diff --git a/test/automation/src/notebook.ts b/test/automation/src/notebook.ts index 3ba9101a1de..7596d1888a8 100644 --- a/test/automation/src/notebook.ts +++ b/test/automation/src/notebook.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Quality } from './application'; import { Code } from './code'; import { QuickAccess } from './quickaccess'; import { QuickInput } from './quickinput'; @@ -47,7 +46,7 @@ export class Notebook { await this.code.waitForElement(editor); - const editContext = `${editor} ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`; + const editContext = `${editor} ${!this.code.editContextEnabled ? 'textarea' : '.native-edit-context'}`; await this.code.waitForActiveElement(editContext); await this.code.waitForTypeInEditor(editContext, text); diff --git a/test/automation/src/scm.ts b/test/automation/src/scm.ts index 2277bcb2875..0fb54bd15d2 100644 --- a/test/automation/src/scm.ts +++ b/test/automation/src/scm.ts @@ -6,7 +6,6 @@ import { Viewlet } from './viewlet'; import { IElement } from './driver'; import { findElement, findElements, Code } from './code'; -import { Quality } from './application'; const VIEWLET = 'div[id="workbench.view.scm"]'; const SCM_INPUT_NATIVE_EDIT_CONTEXT = `${VIEWLET} .scm-editor .native-edit-context`; @@ -79,6 +78,6 @@ export class SCM extends Viewlet { } private _editContextSelector(): string { - return this.code.quality === Quality.Stable ? SCM_INPUT_TEXTAREA : SCM_INPUT_NATIVE_EDIT_CONTEXT; + return !this.code.editContextEnabled ? SCM_INPUT_TEXTAREA : SCM_INPUT_NATIVE_EDIT_CONTEXT; } } diff --git a/test/automation/src/settings.ts b/test/automation/src/settings.ts index f4a8afb3165..ab961478b37 100644 --- a/test/automation/src/settings.ts +++ b/test/automation/src/settings.ts @@ -7,7 +7,6 @@ import { Editor } from './editor'; import { Editors } from './editors'; import { Code } from './code'; import { QuickAccess } from './quickaccess'; -import { Quality } from './application'; const SEARCH_BOX_NATIVE_EDIT_CONTEXT = '.settings-editor .suggest-input-container .monaco-editor .native-edit-context'; const SEARCH_BOX_TEXTAREA = '.settings-editor .suggest-input-container .monaco-editor textarea'; @@ -26,7 +25,7 @@ export class SettingsEditor { await this.editors.selectTab('settings.json'); await this.code.sendKeybinding('right', () => - this.editor.waitForEditorSelection('settings.json', (s) => this._acceptEditorSelection(this.code.quality, s))); + this.editor.waitForEditorSelection('settings.json', (s) => this._acceptEditorSelection(this.code.editContextEnabled, s))); await this.editor.waitForTypeInEditor('settings.json', `"${setting}": ${value},`); await this.editors.saveOpenedFile(); } @@ -42,7 +41,7 @@ export class SettingsEditor { await this.editors.selectTab('settings.json'); await this.code.sendKeybinding('right', () => - this.editor.waitForEditorSelection('settings.json', (s) => this._acceptEditorSelection(this.code.quality, s))); + this.editor.waitForEditorSelection('settings.json', (s) => this._acceptEditorSelection(this.code.editContextEnabled, s))); await this.editor.waitForTypeInEditor('settings.json', settings.map(v => `"${v[0]}": ${v[1]},`).join('')); await this.editors.saveOpenedFile(); } @@ -85,11 +84,11 @@ export class SettingsEditor { } private _editContextSelector() { - return this.code.quality === Quality.Stable ? SEARCH_BOX_TEXTAREA : SEARCH_BOX_NATIVE_EDIT_CONTEXT; + return !this.code.editContextEnabled ? SEARCH_BOX_TEXTAREA : SEARCH_BOX_NATIVE_EDIT_CONTEXT; } - private _acceptEditorSelection(quality: Quality, s: { selectionStart: number; selectionEnd: number }): boolean { - if (quality === Quality.Stable) { + private _acceptEditorSelection(editContextEnabled: boolean, s: { selectionStart: number; selectionEnd: number }): boolean { + if (!editContextEnabled) { return true; } return s.selectionStart === 1 && s.selectionEnd === 1; diff --git a/test/smoke/src/areas/workbench/data-loss.test.ts b/test/smoke/src/areas/workbench/data-loss.test.ts index 9788813f225..123076e130e 100644 --- a/test/smoke/src/areas/workbench/data-loss.test.ts +++ b/test/smoke/src/areas/workbench/data-loss.test.ts @@ -7,7 +7,7 @@ import { join } from 'path'; import { Application, ApplicationOptions, Logger, Quality } from '../../../../automation'; import { createApp, timeout, installDiagnosticsHandler, installAppAfterHandler, getRandomUserDataDir, suiteLogsPath, suiteCrashPath } from '../../utils'; -export function setup(ensureStableCode: () => string | undefined, logger: Logger) { +export function setup(ensureStableCode: () => { stableCodePath: string | undefined; stableCodeVersion: { major: number; minor: number; patch: number } | undefined }, logger: Logger) { describe('Data Loss (insiders -> insiders)', function () { // Double the timeout since these tests involve 2 startups @@ -146,7 +146,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger installAppAfterHandler(() => insidersApp ?? stableApp, async () => stableApp?.stop()); it('verifies opened editors are restored', async function () { - const stableCodePath = ensureStableCode(); + const { stableCodePath, stableCodeVersion } = ensureStableCode(); if (!stableCodePath) { this.skip(); } @@ -170,6 +170,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger stableOptions.quality = Quality.Stable; stableOptions.logsPath = logsPath; stableOptions.crashesPath = crashesPath; + stableOptions.version = stableCodeVersion ?? { major: 0, minor: 0, patch: 0 }; stableApp = new Application(stableOptions); await stableApp.start(); @@ -210,7 +211,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger }); async function testHotExit(this: import('mocha').Context, title: string, restartDelay: number | undefined) { - const stableCodePath = ensureStableCode(); + const { stableCodePath, stableCodeVersion } = ensureStableCode(); if (!stableCodePath) { this.skip(); } @@ -225,6 +226,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger stableOptions.quality = Quality.Stable; stableOptions.logsPath = logsPath; stableOptions.crashesPath = crashesPath; + stableOptions.version = stableCodeVersion ?? { major: 0, minor: 0, patch: 0 }; stableApp = new Application(stableOptions); await stableApp.start(); diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index d8120ea0675..bdc5a3776e2 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -322,6 +322,8 @@ async function ensureStableCode(): Promise { // VSCode/Code.exe (Windows) | VSCode/code (Linux) stableCodePath = path.dirname(stableCodeExecutable); } + + opts['stable-version'] = parseVersion(stableVersion); } if (!fs.existsSync(stableCodePath)) { @@ -352,6 +354,7 @@ before(async function () { this.defaultOptions = { quality, + version: parseVersion(version ?? '0.0.0'), codePath: opts.build, workspacePath, userDataDir, @@ -396,7 +399,7 @@ after(async function () { }); describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { - if (!opts.web) { setupDataLossTests(() => opts['stable-build'] /* Do not change, deferred for a reason! */, logger); } + if (!opts.web) { setupDataLossTests(() => { return { stableCodePath: opts['stable-build'], stableCodeVersion: opts['stable-version'] } /* Do not change, deferred for a reason! */; }, logger); } setupPreferencesTests(logger); setupSearchTests(logger); if (!opts.web) { setupNotebookTests(logger); } From 5d582320051c2ebf4f14338c48b68a2379c747ca Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Jun 2025 10:29:45 +0200 Subject: [PATCH 156/236] add trace logging for word based completions (#251082) https://github.com/microsoft/vscode/issues/251013#issuecomment-2956606451 --- src/vs/editor/browser/services/editorWorkerService.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/browser/services/editorWorkerService.ts b/src/vs/editor/browser/services/editorWorkerService.ts index 76ed0450a63..77cc168f558 100644 --- a/src/vs/editor/browser/services/editorWorkerService.ts +++ b/src/vs/editor/browser/services/editorWorkerService.ts @@ -82,7 +82,7 @@ export abstract class EditorWorkerService extends Disposable implements IEditorW return links && { links }; } })); - this._register(languageFeaturesService.completionProvider.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService, this._languageConfigurationService))); + this._register(languageFeaturesService.completionProvider.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService, this._languageConfigurationService, this._logService))); } public override dispose(): void { @@ -240,7 +240,8 @@ class WordBasedCompletionItemProvider implements languages.CompletionItemProvide workerManager: WorkerManager, configurationService: ITextResourceConfigurationService, modelService: IModelService, - private readonly languageConfigurationService: ILanguageConfigurationService + private readonly languageConfigurationService: ILanguageConfigurationService, + private readonly logService: ILogService ) { this._workerManager = workerManager; this._configurationService = configurationService; @@ -286,6 +287,9 @@ class WordBasedCompletionItemProvider implements languages.CompletionItemProvide const replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn); const insert = replace.setEndPosition(position.lineNumber, position.column); + // Trace logging about the word and replace/insert ranges + this.logService.trace('[WordBasedCompletionItemProvider]', `word: "${word?.word || ''}", wordDef: "${wordDefRegExp}", replace: [${replace.toString()}], insert: [${insert.toString()}]`); + const client = await this._workerManager.withWorker(); const data = await client.textualSuggest(models, word?.word, wordDefRegExp); if (!data) { From 997f77944bc5602a10401308fce0b6824cf0d832 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 10 Jun 2025 10:33:30 +0200 Subject: [PATCH 157/236] fix #249149 (#250649) --- src/vs/platform/actions/common/actions.ts | 1 - src/vs/workbench/browser/actions.ts | 103 ------------------ .../parts/auxiliarybar/auxiliaryBarPart.ts | 35 +----- .../browser/parts/paneCompositePart.ts | 43 +++----- .../browser/parts/views/viewMenuActions.ts | 76 +++++++++++++ .../workbench/browser/parts/views/viewPane.ts | 6 +- .../browser/parts/views/viewPaneContainer.ts | 25 +---- 7 files changed, 102 insertions(+), 187 deletions(-) delete mode 100644 src/vs/workbench/browser/actions.ts create mode 100644 src/vs/workbench/browser/parts/views/viewMenuActions.ts diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 0c9f7069eb1..1a45b866b6c 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -210,7 +210,6 @@ export class MenuId { static readonly SidebarTitle = new MenuId('SidebarTitle'); static readonly PanelTitle = new MenuId('PanelTitle'); static readonly AuxiliaryBarTitle = new MenuId('AuxiliaryBarTitle'); - static readonly AuxiliaryBarHeader = new MenuId('AuxiliaryBarHeader'); static readonly TerminalInstanceContext = new MenuId('TerminalInstanceContext'); static readonly TerminalEditorInstanceContext = new MenuId('TerminalEditorInstanceContext'); static readonly TerminalNewDropdownContext = new MenuId('TerminalNewDropdownContext'); diff --git a/src/vs/workbench/browser/actions.ts b/src/vs/workbench/browser/actions.ts deleted file mode 100644 index 437ca7ff48b..00000000000 --- a/src/vs/workbench/browser/actions.ts +++ /dev/null @@ -1,103 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IAction } from '../../base/common/actions.js'; -import { Disposable, DisposableStore, IDisposable } from '../../base/common/lifecycle.js'; -import { Emitter, Event } from '../../base/common/event.js'; -import { MenuId, IMenuService, IMenu, SubmenuItemAction, IMenuActionOptions } from '../../platform/actions/common/actions.js'; -import { IContextKeyService } from '../../platform/contextkey/common/contextkey.js'; -import { getActionBarActions } from '../../platform/actions/browser/menuEntryActionViewItem.js'; - -class MenuActions extends Disposable { - - private readonly menu: IMenu; - - private _primaryActions: IAction[] = []; - get primaryActions() { return this._primaryActions; } - - private _secondaryActions: IAction[] = []; - get secondaryActions() { return this._secondaryActions; } - - private readonly _onDidChange = this._register(new Emitter()); - readonly onDidChange = this._onDidChange.event; - - private readonly disposables = this._register(new DisposableStore()); - - constructor( - menuId: MenuId, - private readonly options: IMenuActionOptions | undefined, - private readonly menuService: IMenuService, - private readonly contextKeyService: IContextKeyService - ) { - super(); - - this.menu = this._register(menuService.createMenu(menuId, contextKeyService)); - - this._register(this.menu.onDidChange(() => this.updateActions())); - this.updateActions(); - } - - private updateActions(): void { - this.disposables.clear(); - const newActions = getActionBarActions(this.menu.getActions(this.options)); - this._primaryActions = newActions.primary; - this._secondaryActions = newActions.secondary; - this.disposables.add(this.updateSubmenus([...this._primaryActions, ...this._secondaryActions], {})); - this._onDidChange.fire(); - } - - private updateSubmenus(actions: readonly IAction[], submenus: Record): IDisposable { - const disposables = new DisposableStore(); - - for (const action of actions) { - if (action instanceof SubmenuItemAction && !submenus[action.item.submenu.id]) { - const menu = submenus[action.item.submenu.id] = disposables.add(this.menuService.createMenu(action.item.submenu, this.contextKeyService)); - disposables.add(menu.onDidChange(() => this.updateActions())); - disposables.add(this.updateSubmenus(action.actions, submenus)); - } - } - - return disposables; - } -} - -export class CompositeMenuActions extends Disposable { - - private readonly menuActions: MenuActions; - - private _onDidChange = this._register(new Emitter()); - readonly onDidChange: Event = this._onDidChange.event; - - constructor( - readonly menuId: MenuId, - private readonly contextMenuId: MenuId | undefined, - private readonly options: IMenuActionOptions | undefined, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IMenuService private readonly menuService: IMenuService, - ) { - super(); - - this.menuActions = this._register(new MenuActions(menuId, this.options, menuService, contextKeyService)); - - this._register(this.menuActions.onDidChange(() => this._onDidChange.fire())); - } - - getPrimaryActions(): IAction[] { - return this.menuActions.primaryActions; - } - - getSecondaryActions(): IAction[] { - return this.menuActions.secondaryActions; - } - - getContextMenuActions(): IAction[] { - if (this.contextMenuId) { - const menu = this.menuService.getMenuActions(this.contextMenuId, this.contextKeyService, this.options); - return getActionBarActions(menu).secondary; - } - - return []; - } -} diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts index be4e9e74042..f62ba06d8b1 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts @@ -26,15 +26,11 @@ import { LayoutPriority } from '../../../../base/browser/ui/splitview/splitview. import { ToggleSidebarPositionAction } from '../../actions/layoutActions.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { AbstractPaneCompositePart, CompositeBarPosition } from '../paneCompositePart.js'; -import { ActionsOrientation, IActionViewItem, prepareActions } from '../../../../base/browser/ui/actionbar/actionbar.js'; +import { ActionsOrientation } from '../../../../base/browser/ui/actionbar/actionbar.js'; import { IPaneCompositeBarOptions } from '../paneCompositeBar.js'; import { IMenuService, MenuId } from '../../../../platform/actions/common/actions.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { getContextMenuActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js'; -import { $ } from '../../../../base/browser/dom.js'; -import { HiddenItemStrategy, WorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js'; -import { ActionViewItem, IActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js'; -import { CompositeMenuActions } from '../../actions.js'; import { IHoverService } from '../../../../platform/hover/browser/hover.js'; interface IAuxiliaryBarPartConfiguration { @@ -252,35 +248,6 @@ export class AuxiliaryBarPart extends AbstractPaneCompositePart { } } - protected override createHeaderArea() { - const headerArea = super.createHeaderArea(); - const globalHeaderContainer = $('.auxiliary-bar-global-header'); - - // Add auxillary header action - const menu = this.headerFooterCompositeBarDispoables.add(this.instantiationService.createInstance(CompositeMenuActions, MenuId.AuxiliaryBarHeader, undefined, undefined)); - - const toolBar = this.headerFooterCompositeBarDispoables.add(this.instantiationService.createInstance(WorkbenchToolBar, globalHeaderContainer, { - actionViewItemProvider: (action, options) => this.headerActionViewItemProvider(action, options), - orientation: ActionsOrientation.HORIZONTAL, - hiddenItemStrategy: HiddenItemStrategy.NoHide, - getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), - })); - - toolBar.setActions(prepareActions(menu.getPrimaryActions())); - this.headerFooterCompositeBarDispoables.add(menu.onDidChange(() => toolBar.setActions(prepareActions(menu.getPrimaryActions())))); - - headerArea.appendChild(globalHeaderContainer); - return headerArea; - } - - private headerActionViewItemProvider(action: IAction, options: IActionViewItemOptions): IActionViewItem | undefined { - if (action.id === ToggleAuxiliaryBarAction.ID) { - return this.instantiationService.createInstance(ActionViewItem, undefined, action, options); - } - - return undefined; - } - override toJSON(): object { return { type: Parts.AUXILIARYBAR_PART diff --git a/src/vs/workbench/browser/parts/paneCompositePart.ts b/src/vs/workbench/browser/parts/paneCompositePart.ts index f164e31785e..f309de40ab6 100644 --- a/src/vs/workbench/browser/parts/paneCompositePart.ts +++ b/src/vs/workbench/browser/parts/paneCompositePart.ts @@ -29,9 +29,8 @@ import { localize } from '../../../nls.js'; import { CompositeDragAndDropObserver, toggleDropEffect } from '../dnd.js'; import { EDITOR_DRAG_AND_DROP_BACKGROUND } from '../../common/theme.js'; import { IPartOptions } from '../part.js'; -import { CompositeMenuActions } from '../actions.js'; import { IMenuService, MenuId } from '../../../platform/actions/common/actions.js'; -import { ActionsOrientation, prepareActions } from '../../../base/browser/ui/actionbar/actionbar.js'; +import { ActionsOrientation } from '../../../base/browser/ui/actionbar/actionbar.js'; import { Gesture, EventType as GestureEventType } from '../../../base/browser/touch.js'; import { StandardMouseEvent } from '../../../base/browser/mouseEvent.js'; import { IAction, SubmenuAction } from '../../../base/common/actions.js'; @@ -39,7 +38,7 @@ import { Composite } from '../composite.js'; import { ViewsSubMenu } from './views/viewPaneContainer.js'; import { getActionBarActions } from '../../../platform/actions/browser/menuEntryActionViewItem.js'; import { IHoverService } from '../../../platform/hover/browser/hover.js'; -import { HiddenItemStrategy, WorkbenchToolBar } from '../../../platform/actions/browser/toolbar.js'; +import { HiddenItemStrategy, MenuWorkbenchToolBar } from '../../../platform/actions/browser/toolbar.js'; import { DeferredPromise } from '../../../base/common/async.js'; export enum CompositeBarPosition { @@ -128,8 +127,8 @@ export abstract class AbstractPaneCompositePart extends CompositePart | undefined = undefined; protected contentDimension: Dimension | undefined; @@ -190,15 +189,13 @@ export abstract class AbstractPaneCompositePart extends CompositePart this.onDidOpen(composite))); this._register(this.onDidPaneCompositeClose(this.onDidClose, this)); - this._register(this.globalActions.onDidChange(() => this.updateGlobalToolbarActions())); this._register(this.registry.onDidDeregister((viewletDescriptor: PaneCompositeDescriptor) => { @@ -357,17 +354,19 @@ export abstract class AbstractPaneCompositePart extends CompositePart this.actionViewItemProvider(action, options), - orientation: ActionsOrientation.HORIZONTAL, - getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), - anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(), - toggleMenuTitle: localize('moreActions', "More Actions..."), - hoverDelegate: this.toolbarHoverDelegate, - hiddenItemStrategy: HiddenItemStrategy.NoHide - })); - - this.updateGlobalToolbarActions(); + this.globalToolBar = this._register(this.instantiationService.createInstance(MenuWorkbenchToolBar, + globalTitleActionsContainer, + this.globalActionsMenuId, + { + actionViewItemProvider: (action, options) => this.actionViewItemProvider(action, options), + orientation: ActionsOrientation.HORIZONTAL, + getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), + anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(), + toggleMenuTitle: localize('moreActions', "More Actions..."), + hoverDelegate: this.toolbarHoverDelegate, + hiddenItemStrategy: HiddenItemStrategy.NoHide + } + )); return titleArea; } @@ -628,12 +627,6 @@ export abstract class AbstractPaneCompositePart extends CompositePart()); + readonly onDidChange = this._onDidChange.event; + + constructor( + readonly menuId: MenuId, + private readonly contextMenuId: MenuId | undefined, + private readonly options: IMenuActionOptions | undefined, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IMenuService private readonly menuService: IMenuService, + ) { + super(); + this.menu = this._register(menuService.createMenu(menuId, contextKeyService, { emitEventsForSubmenuChanges: true })); + this._register(this.menu.onDidChange(() => { + this.actions = undefined; + this._onDidChange.fire(); + })); + } + + private actions: PrimaryAndSecondaryActions | undefined; + private getActions(): PrimaryAndSecondaryActions { + if (!this.actions) { + this.actions = getActionBarActions(this.menu.getActions(this.options)); + } + return this.actions; + } + + getPrimaryActions(): IAction[] { + return this.getActions().primary; + } + + getSecondaryActions(): IAction[] { + return this.getActions().secondary; + } + + getContextMenuActions(): IAction[] { + if (this.contextMenuId) { + const menu = this.menuService.getMenuActions(this.contextMenuId, this.contextKeyService, this.options); + return getActionBarActions(menu).secondary; + } + return []; + } +} + +export class ViewContainerMenuActions extends ViewMenuActions { + constructor( + element: HTMLElement, + viewContainer: ViewContainer, + @IViewDescriptorService viewDescriptorService: IViewDescriptorService, + @IContextKeyService contextKeyService: IContextKeyService, + @IMenuService menuService: IMenuService, + ) { + const scopedContextKeyService = contextKeyService.createScoped(element); + scopedContextKeyService.createKey('viewContainer', viewContainer.id); + const viewContainerLocationKey = scopedContextKeyService.createKey('viewContainerLocation', ViewContainerLocationToString(viewDescriptorService.getViewContainerLocation(viewContainer)!)); + super(MenuId.ViewContainerTitle, MenuId.ViewContainerTitleContext, { shouldForwardArgs: true, renderShortTitle: true }, scopedContextKeyService, menuService); + this._register(scopedContextKeyService); + this._register(Event.filter(viewDescriptorService.onDidChangeContainerLocation, e => e.viewContainer === viewContainer)(() => viewContainerLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewContainerLocation(viewContainer)!)))); + } +} diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index c34db2ed2c7..b14236832cf 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -40,7 +40,6 @@ import { ScrollbarVisibility } from '../../../../base/common/scrollable.js'; import { URI } from '../../../../base/common/uri.js'; import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js'; import { Codicon } from '../../../../base/common/codicons.js'; -import { CompositeMenuActions } from '../../actions.js'; import { IDropdownMenuActionViewItemOptions } from '../../../../base/browser/ui/dropdown/dropdownActionViewItem.js'; import { WorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js'; import { FilterWidget, IFilterWidgetOptions } from './viewFilter.js'; @@ -55,6 +54,7 @@ import { IListStyles } from '../../../../base/browser/ui/list/listWidget.js'; import { PANEL_BACKGROUND, PANEL_SECTION_DRAG_AND_DROP_BACKGROUND, PANEL_STICKY_SCROLL_BACKGROUND, PANEL_STICKY_SCROLL_BORDER, PANEL_STICKY_SCROLL_SHADOW, SIDE_BAR_BACKGROUND, SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_STICKY_SCROLL_BACKGROUND, SIDE_BAR_STICKY_SCROLL_BORDER, SIDE_BAR_STICKY_SCROLL_SHADOW } from '../../../common/theme.js'; import { IAccessibleViewInformationService } from '../../../services/accessibility/common/accessibleViewInformationService.js'; import { renderLabelWithIcons } from '../../../../base/browser/ui/iconLabel/iconLabels.js'; +import { ViewMenuActions } from './viewMenuActions.js'; export enum ViewPaneShowActions { /** Show the actions when the view is hovered. This is the default behavior. */ @@ -340,7 +340,7 @@ export abstract class ViewPane extends Pane implements IView { return this._singleViewPaneContainerTitle; } - readonly menuActions: CompositeMenuActions; + readonly menuActions: ViewMenuActions; private progressBar!: ProgressBar; private progressIndicator!: IProgressIndicator; @@ -388,7 +388,7 @@ export abstract class ViewPane extends Pane implements IView { this._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === this.id))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!)))); const childInstantiationService = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService]))); - this.menuActions = this._register(childInstantiationService.createInstance(CompositeMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs, renderShortTitle: true })); + this.menuActions = this._register(childInstantiationService.createInstance(ViewMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs, renderShortTitle: true })); this._register(this.menuActions.onDidChange(() => this.updateActions())); } diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index bf89cf67fee..c87738f78b1 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -18,7 +18,7 @@ import { assertReturnsDefined } from '../../../../base/common/types.js'; import './media/paneviewlet.css'; import * as nls from '../../../../nls.js'; import { createActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js'; -import { Action2, IAction2Options, IMenuService, ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js'; +import { Action2, IAction2Options, ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; @@ -29,19 +29,19 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { activeContrastBorder, asCssVariable } from '../../../../platform/theme/common/colorRegistry.js'; import { IThemeService, Themable } from '../../../../platform/theme/common/themeService.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; -import { CompositeMenuActions } from '../../actions.js'; import { CompositeDragAndDropObserver, toggleDropEffect } from '../../dnd.js'; import { ViewPane } from './viewPane.js'; import { IViewletViewOptions } from './viewsViewlet.js'; import { Component } from '../../../common/component.js'; import { PANEL_SECTION_BORDER, PANEL_SECTION_DRAG_AND_DROP_BACKGROUND, PANEL_SECTION_HEADER_BACKGROUND, PANEL_SECTION_HEADER_BORDER, PANEL_SECTION_HEADER_FOREGROUND, SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, SIDE_BAR_SECTION_HEADER_BORDER, SIDE_BAR_SECTION_HEADER_FOREGROUND } from '../../../common/theme.js'; -import { IAddedViewDescriptorRef, ICustomViewDescriptor, IView, IViewContainerModel, IViewDescriptor, IViewDescriptorRef, IViewDescriptorService, IViewPaneContainer, ViewContainer, ViewContainerLocation, ViewContainerLocationToString, ViewVisibilityState } from '../../../common/views.js'; +import { IAddedViewDescriptorRef, ICustomViewDescriptor, IView, IViewContainerModel, IViewDescriptor, IViewDescriptorRef, IViewDescriptorService, IViewPaneContainer, ViewContainer, ViewContainerLocation, ViewVisibilityState } from '../../../common/views.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; import { FocusedViewContext } from '../../../common/contextkeys.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; import { isHorizontal, IWorkbenchLayoutService, LayoutSettings } from '../../../services/layout/browser/layoutService.js'; import { IBaseActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js'; import { ILogService } from '../../../../platform/log/common/log.js'; +import { ViewContainerMenuActions } from './viewMenuActions.js'; export const ViewsSubMenu = new MenuId('Views'); MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, { @@ -288,23 +288,6 @@ class ViewPaneDropOverlay extends Themable { } } -class ViewContainerMenuActions extends CompositeMenuActions { - constructor( - element: HTMLElement, - viewContainer: ViewContainer, - @IViewDescriptorService viewDescriptorService: IViewDescriptorService, - @IContextKeyService contextKeyService: IContextKeyService, - @IMenuService menuService: IMenuService, - ) { - const scopedContextKeyService = contextKeyService.createScoped(element); - scopedContextKeyService.createKey('viewContainer', viewContainer.id); - const viewContainerLocationKey = scopedContextKeyService.createKey('viewContainerLocation', ViewContainerLocationToString(viewDescriptorService.getViewContainerLocation(viewContainer)!)); - super(MenuId.ViewContainerTitle, MenuId.ViewContainerTitleContext, { shouldForwardArgs: true, renderShortTitle: true }, scopedContextKeyService, menuService); - this._register(scopedContextKeyService); - this._register(Event.filter(viewDescriptorService.onDidChangeContainerLocation, e => e.viewContainer === viewContainer)(() => viewContainerLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewContainerLocation(viewContainer)!)))); - } -} - export class ViewPaneContainer extends Component implements IViewPaneContainer { readonly viewContainer: ViewContainer; @@ -363,7 +346,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { } private _menuActions?: ViewContainerMenuActions; - get menuActions(): CompositeMenuActions | undefined { + get menuActions(): ViewContainerMenuActions | undefined { return this._menuActions; } From de39a3fee5804fbe5b5c17ccf99c27388a9638b7 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 10 Jun 2025 11:23:51 +0200 Subject: [PATCH 158/236] remove cyclic dep (#251086) --- .../contrib/extensions/browser/extensionsViewer.ts | 11 ++++++++++- .../contrib/extensions/browser/extensionsViews.ts | 10 ---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts index d05db317edc..b2a54e1f873 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts @@ -26,7 +26,6 @@ import { KeyCode } from '../../../../base/common/keyCodes.js'; import { IListStyles } from '../../../../base/browser/ui/list/listWidget.js'; import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js'; import { IStyleOverride } from '../../../../platform/theme/browser/defaultStyles.js'; -import { getAriaLabelForExtension } from './extensionsViews.js'; import { IViewDescriptorService, ViewContainerLocation } from '../../../common/views.js'; import { IWorkbenchLayoutService, Position } from '../../../services/layout/browser/layoutService.js'; import { areSameExtensions } from '../../../../platform/extensionManagement/common/extensionManagementUtil.js'; @@ -37,6 +36,16 @@ import { getLocationBasedViewColors } from '../../../browser/parts/views/viewPan import { DelayedPagedModel, IPagedModel } from '../../../../base/common/paging.js'; import { ExtensionIconWidget } from './extensionsWidgets.js'; +function getAriaLabelForExtension(extension: IExtension | null): string { + if (!extension) { + return ''; + } + const publisher = extension.publisherDomain?.verified ? localize('extension.arialabel.verifiedPublisher', "Verified Publisher {0}", extension.publisherDisplayName) : localize('extension.arialabel.publisher', "Publisher {0}", extension.publisherDisplayName); + const deprecated = extension?.deprecationInfo ? localize('extension.arialabel.deprecated', "Deprecated") : ''; + const rating = extension?.rating ? localize('extension.arialabel.rating', "Rated {0} out of 5 stars by {1} users", extension.rating.toFixed(2), extension.ratingCount) : ''; + return `${extension.displayName}, ${deprecated ? `${deprecated}, ` : ''}${extension.version}, ${publisher}, ${extension.description} ${rating ? `, ${rating}` : ''}`; +} + export class ExtensionsList extends Disposable { readonly list: WorkbenchPagedList; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 8894ec13185..5730221e7fa 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -1549,16 +1549,6 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView imple } -export function getAriaLabelForExtension(extension: IExtension | null): string { - if (!extension) { - return ''; - } - const publisher = extension.publisherDomain?.verified ? localize('extension.arialabel.verifiedPublisher', "Verified Publisher {0}", extension.publisherDisplayName) : localize('extension.arialabel.publisher', "Publisher {0}", extension.publisherDisplayName); - const deprecated = extension?.deprecationInfo ? localize('extension.arialabel.deprecated', "Deprecated") : ''; - const rating = extension?.rating ? localize('extension.arialabel.rating', "Rated {0} out of 5 stars by {1} users", extension.rating.toFixed(2), extension.ratingCount) : ''; - return `${extension.displayName}, ${deprecated ? `${deprecated}, ` : ''}${extension.version}, ${publisher}, ${extension.description} ${rating ? `, ${rating}` : ''}`; -} - export class PreferredExtensionsPagedModel implements IPagedModel { private readonly resolved = new Map(); From acd3bb010adf780d5dbfec998703cfeddd52c1e5 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 10 Jun 2025 11:40:23 +0200 Subject: [PATCH 159/236] Adding slash in front of uri path if untitled file (#251087) adding slash in front of uri path if untitled file --- .../contrib/bulkEdit/browser/preview/bulkEditPreview.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts index ad2d7ebb97e..a43ead4f7e6 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts @@ -25,6 +25,7 @@ import { Codicon } from '../../../../../base/common/codicons.js'; import { generateUuid } from '../../../../../base/common/uuid.js'; import { SnippetParser } from '../../../../../editor/contrib/snippet/browser/snippetParser.js'; import { MicrotaskDelay } from '../../../../../base/common/symbols.js'; +import { Schemas } from '../../../../../base/common/network.js'; export class CheckedStates { @@ -388,7 +389,8 @@ export class BulkEditPreviewProvider implements ITextModelContentProvider { } asPreviewUri(uri: URI): URI { - return URI.from({ scheme: BulkEditPreviewProvider.Schema, authority: this._instanceId, path: uri.path, query: uri.toString() }); + const path = uri.scheme === Schemas.untitled ? `/${uri.path}` : uri.path; + return URI.from({ scheme: BulkEditPreviewProvider.Schema, authority: this._instanceId, path, query: uri.toString() }); } private async _init() { From 99323241e950584f15b3e9fea9b37414ace86116 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 10 Jun 2025 14:07:43 +0200 Subject: [PATCH 160/236] Color Picker: fix incorrect ternary condition definition (#251090) incorrect ternary condition fix --- .../colorPicker/browser/defaultDocumentColorProvider.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/colorPicker/browser/defaultDocumentColorProvider.ts b/src/vs/editor/contrib/colorPicker/browser/defaultDocumentColorProvider.ts index 63a231f23ea..1359b5babf4 100644 --- a/src/vs/editor/contrib/colorPicker/browser/defaultDocumentColorProvider.ts +++ b/src/vs/editor/contrib/colorPicker/browser/defaultDocumentColorProvider.ts @@ -27,9 +27,9 @@ export class DefaultDocumentColorProvider implements DocumentColorProvider { const alpha = colorFromInfo.alpha; const color = new Color(new RGBA(Math.round(255 * colorFromInfo.red), Math.round(255 * colorFromInfo.green), Math.round(255 * colorFromInfo.blue), alpha)); - const rgb = alpha ? Color.Format.CSS.formatRGB(color) : Color.Format.CSS.formatRGBA(color); - const hsl = alpha ? Color.Format.CSS.formatHSL(color) : Color.Format.CSS.formatHSLA(color); - const hex = alpha ? Color.Format.CSS.formatHex(color) : Color.Format.CSS.formatHexA(color); + const rgb = alpha ? Color.Format.CSS.formatRGBA(color) : Color.Format.CSS.formatRGB(color); + const hsl = alpha ? Color.Format.CSS.formatHSLA(color) : Color.Format.CSS.formatHSL(color); + const hex = alpha ? Color.Format.CSS.formatHexA(color) : Color.Format.CSS.formatHex(color); const colorPresentations: IColorPresentation[] = []; colorPresentations.push({ label: rgb, textEdit: { range: range, text: rgb } }); From 3f25a2dc283a0c05101af22d6c990175b411064f Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 10 Jun 2025 14:08:30 +0200 Subject: [PATCH 161/236] Refactoring sticky scroll CSS file (#251094) refactoring sticky scroll css file --- .../stickyScroll/browser/stickyScroll.css | 107 +++++++++--------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css index 12480664119..0831d61bdbd 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css @@ -5,63 +5,7 @@ .monaco-editor .sticky-widget { overflow: hidden; -} - -.monaco-editor .sticky-widget-line-numbers { - float: left; - background-color: inherit; -} - -.monaco-editor .sticky-widget-lines-scrollable { - display: inline-block; - position: absolute; - overflow: hidden; - width: var(--vscode-editorStickyScroll-scrollableWidth); - background-color: inherit; -} - -.monaco-editor .sticky-widget-lines { - position: absolute; - background-color: inherit; -} - -.monaco-editor .sticky-line-number, .monaco-editor .sticky-line-content { - color: var(--vscode-editorLineNumber-foreground); - white-space: nowrap; - display: inline-block; - position: absolute; - background-color: inherit; -} - -.monaco-editor .sticky-line-number .codicon-folding-expanded, -.monaco-editor .sticky-line-number .codicon-folding-collapsed { - float: right; - transition: var(--vscode-editorStickyScroll-foldingOpacityTransition); - position: absolute; - margin-left: 2px; -} - -.monaco-editor .sticky-line-content { - width: var(--vscode-editorStickyScroll-scrollableWidth); - background-color: inherit; - white-space: nowrap; -} - -.monaco-editor .sticky-line-number-inner { - display: inline-block; - text-align: right; -} - -.monaco-editor .sticky-widget { border-bottom: 1px solid var(--vscode-editorStickyScroll-border); -} - -.monaco-editor .sticky-line-content:hover { - background-color: var(--vscode-editorStickyScrollHover-background); - cursor: pointer; -} - -.monaco-editor .sticky-widget { width: 100%; box-shadow: var(--vscode-editorStickyScroll-shadow) 0 4px 2px -2px; z-index: 4; @@ -72,3 +16,54 @@ .monaco-editor .sticky-widget.peek { background-color: var(--vscode-peekViewEditorStickyScroll-background); } + +.monaco-editor .sticky-widget .sticky-widget-line-numbers { + float: left; + background-color: inherit; +} + +.monaco-editor .sticky-widget .sticky-widget-lines-scrollable { + display: inline-block; + position: absolute; + overflow: hidden; + width: var(--vscode-editorStickyScroll-scrollableWidth); + background-color: inherit; +} + +.monaco-editor .sticky-widget .sticky-widget-lines { + position: absolute; + background-color: inherit; +} + +.monaco-editor .sticky-widget .sticky-line-number, +.monaco-editor .sticky-widget .sticky-line-content { + color: var(--vscode-editorLineNumber-foreground); + white-space: nowrap; + display: inline-block; + position: absolute; + background-color: inherit; +} + +.monaco-editor .sticky-widget .sticky-line-number .codicon-folding-expanded, +.monaco-editor .sticky-widget .sticky-line-number .codicon-folding-collapsed { + float: right; + transition: var(--vscode-editorStickyScroll-foldingOpacityTransition); + position: absolute; + margin-left: 2px; +} + +.monaco-editor .sticky-widget .sticky-line-content { + width: var(--vscode-editorStickyScroll-scrollableWidth); + background-color: inherit; + white-space: nowrap; +} + +.monaco-editor .sticky-widget .sticky-line-number-inner { + display: inline-block; + text-align: right; +} + +.monaco-editor .sticky-widget .sticky-line-content:hover { + background-color: var(--vscode-editorStickyScrollHover-background); + cursor: pointer; +} From 8349c9516b8c320ff5116e11ebefd9b254d0dcb0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 10 Jun 2025 16:16:10 +0200 Subject: [PATCH 162/236] Revert "file watcher - log extension host created watcher logic" (#251085) * Revert "file watcher - log extension host created watcher logic (#248507)" This reverts commit 3c3303a088380a2f25cd25178c97b8a14a07cee6. * . --- .../common/extHostFileSystemEventService.ts | 72 +++---------------- 1 file changed, 9 insertions(+), 63 deletions(-) diff --git a/src/vs/workbench/api/common/extHostFileSystemEventService.ts b/src/vs/workbench/api/common/extHostFileSystemEventService.ts index 3fbd84d3392..5fcd3c613d0 100644 --- a/src/vs/workbench/api/common/extHostFileSystemEventService.ts +++ b/src/vs/workbench/api/common/extHostFileSystemEventService.ts @@ -14,7 +14,7 @@ import { Disposable, WorkspaceEdit } from './extHostTypes.js'; import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js'; import { FileChangeFilter, FileOperation, IGlobPatterns } from '../../../platform/files/common/files.js'; import { CancellationToken } from '../../../base/common/cancellation.js'; -import { ILogService, LogLevel } from '../../../platform/log/common/log.js'; +import { ILogService } from '../../../platform/log/common/log.js'; import { IExtHostWorkspace } from './extHostWorkspace.js'; import { Lazy } from '../../../base/common/lazy.js'; import { ExtHostConfigProvider } from './extHostConfiguration.js'; @@ -29,9 +29,6 @@ export interface FileSystemWatcherCreateOptions { class FileSystemWatcher implements vscode.FileSystemWatcher { - private static IDS = 0; - - private readonly id = FileSystemWatcher.IDS++; private readonly session = Math.random(); private readonly _onDidCreate = new Emitter(); @@ -53,16 +50,7 @@ class FileSystemWatcher implements vscode.FileSystemWatcher { return Boolean(this._config & 0b100); } - constructor( - mainContext: IMainContext, - logService: ILogService, - configuration: ExtHostConfigProvider, - workspace: IExtHostWorkspace, - extension: IExtensionDescription, - dispatcher: Event, - globPattern: string | IRelativePatternDto, - options: FileSystemWatcherCreateOptions - ) { + constructor(mainContext: IMainContext, configuration: ExtHostConfigProvider, workspace: IExtHostWorkspace, extension: IExtensionDescription, dispatcher: Event, globPattern: string | IRelativePatternDto, options: FileSystemWatcherCreateOptions) { this._config = 0; if (options.ignoreCreateEvents) { this._config += 0b001; @@ -74,18 +62,6 @@ class FileSystemWatcher implements vscode.FileSystemWatcher { this._config += 0b100; } - const trace = logService.getLevel() === LogLevel.Trace; - if (trace) { - let patternLogMsg: string; - if (typeof globPattern === 'string') { - patternLogMsg = `'${globPattern}'`; - } else { - patternLogMsg = `base: '${globPattern.base}', pattern: '${globPattern.pattern}'`; - } - - logService.trace(`[File Watcher ('API') ${this.id}] createFileSystemWatcher(${patternLogMsg}, ${JSON.stringify(options)})`); - } - const parsedPattern = parse(globPattern); // 1.64.x behaviour change: given the new support to watch any folder @@ -105,64 +81,34 @@ class FileSystemWatcher implements vscode.FileSystemWatcher { const subscription = dispatcher(events => { if (typeof events.session === 'number' && events.session !== this.session) { - if (trace) { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(): returning early due to event correlation mismatch`); - } return; // ignore events from other file watchers that are in correlation mode } if (excludeUncorrelatedEvents && typeof events.session === 'undefined') { - if (trace) { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(): returning early due to event correlation mismatch`); - } return; // ignore events from other non-correlating file watcher when we are in correlation mode } if (!options.ignoreCreateEvents) { for (const created of events.created) { const uri = URI.revive(created); - if (parsedPattern(uri.fsPath)) { - if (!excludeOutOfWorkspaceEvents || workspace.getWorkspaceFolder(uri)) { - this._onDidCreate.fire(uri); - } else { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(created): ${uri.fsPath} did not match out-of-workspace rule`); - } - } else { - if (trace) { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(created): ${uri.fsPath} did not match pattern`); - } + if (parsedPattern(uri.fsPath) && (!excludeOutOfWorkspaceEvents || workspace.getWorkspaceFolder(uri))) { + this._onDidCreate.fire(uri); } } } if (!options.ignoreChangeEvents) { for (const changed of events.changed) { const uri = URI.revive(changed); - if (parsedPattern(uri.fsPath)) { - if (!excludeOutOfWorkspaceEvents || workspace.getWorkspaceFolder(uri)) { - this._onDidChange.fire(uri); - } else { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(changed): ${uri.fsPath} did not match out-of-workspace rule`); - } - } else { - if (trace) { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(changed): ${uri.fsPath} did not match pattern`); - } + if (parsedPattern(uri.fsPath) && (!excludeOutOfWorkspaceEvents || workspace.getWorkspaceFolder(uri))) { + this._onDidChange.fire(uri); } } } if (!options.ignoreDeleteEvents) { for (const deleted of events.deleted) { const uri = URI.revive(deleted); - if (parsedPattern(uri.fsPath)) { - if (!excludeOutOfWorkspaceEvents || workspace.getWorkspaceFolder(uri)) { - this._onDidDelete.fire(uri); - } else { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(deleted): ${uri.fsPath} did not match out-of-workspace rule`); - } - } else { - if (trace) { - logService.trace(`[File Watcher ('API') ${this.id}] dispatch(deleted): ${uri.fsPath} did not match pattern`); - } + if (parsedPattern(uri.fsPath) && (!excludeOutOfWorkspaceEvents || workspace.getWorkspaceFolder(uri))) { + this._onDidDelete.fire(uri); } } } @@ -339,7 +285,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ //--- file events createFileSystemWatcher(workspace: IExtHostWorkspace, configProvider: ExtHostConfigProvider, extension: IExtensionDescription, globPattern: vscode.GlobPattern, options: FileSystemWatcherCreateOptions): vscode.FileSystemWatcher { - return new FileSystemWatcher(this._mainContext, this._logService, configProvider, workspace, extension, this._onFileSystemEvent.event, typeConverter.GlobPattern.from(globPattern), options); + return new FileSystemWatcher(this._mainContext, configProvider, workspace, extension, this._onFileSystemEvent.event, typeConverter.GlobPattern.from(globPattern), options); } $onFileEvent(events: FileSystemEvents) { From daf796976b3a2aacf1b4b8559528935bd05376e5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 10 Jun 2025 16:40:41 +0200 Subject: [PATCH 163/236] chore - add some editing tests (#251104) --- .../test/browser/chatEditingService.test.ts | 127 +++++++++++++++++- 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts index cc3c6fcaef4..49b0907a665 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts @@ -26,7 +26,7 @@ import { NotebookTextModel } from '../../../notebook/common/model/notebookTextMo import { INotebookService } from '../../../notebook/common/notebookService.js'; import { ChatEditingService } from '../../browser/chatEditing/chatEditingServiceImpl.js'; import { ChatAgentService, IChatAgentData, IChatAgentImplementation, IChatAgentService } from '../../common/chatAgents.js'; -import { IChatEditingService } from '../../common/chatEditingService.js'; +import { ChatEditingSessionState, IChatEditingService, IChatEditingSession, ModifiedFileEntryState } from '../../common/chatEditingService.js'; import { IChatService } from '../../common/chatService.js'; import { ChatService } from '../../common/chatServiceImpl.js'; import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; @@ -36,6 +36,12 @@ import { ChatAgentLocation, ChatMode } from '../../common/constants.js'; import { ILanguageModelsService } from '../../common/languageModels.js'; import { NullLanguageModelsService } from '../common/languageModels.js'; import { MockChatVariablesService } from '../common/mockChatVariables.js'; +import { IEditorWorkerService } from '../../../../../editor/common/services/editorWorker.js'; +import { TestWorkerService } from '../../../inlineChat/test/browser/testWorkerService.js'; +import { EditOperation } from '../../../../../editor/common/core/editOperation.js'; +import { Position } from '../../../../../editor/common/core/position.js'; +import { ChatModel } from '../../common/chatModel.js'; +import { TextEdit } from '../../../../../editor/common/languages.js'; function getAgentData(id: string): IChatAgentData { return { @@ -68,6 +74,7 @@ suite('ChatEditingService', function () { collection.set(IChatSlashCommandService, new class extends mock() { }); collection.set(IChatTransferService, new SyncDescriptor(ChatTransferService)); collection.set(IChatEditingService, new SyncDescriptor(ChatEditingService)); + collection.set(IEditorWorkerService, new SyncDescriptor(TestWorkerService)); collection.set(IChatService, new SyncDescriptor(ChatService)); collection.set(ILanguageModelsService, new SyncDescriptor(NullLanguageModelsService)); collection.set(IMultiDiffSourceResolverService, new class extends mock() { @@ -106,7 +113,7 @@ suite('ChatEditingService', function () { store.add(textModelService.registerTextModelContentProvider('test', { async provideTextContent(resource) { - return modelService.createModel(resource.path.repeat(10), null, resource, false); + return store.add(modelService.createModel(resource.path.repeat(10), null, resource, false)); }, })); }); @@ -135,7 +142,6 @@ suite('ChatEditingService', function () { model.dispose(); }); - test('create session, file entry & isCurrentlyBeingModifiedBy', async function () { assert.ok(editingService); @@ -171,4 +177,119 @@ suite('ChatEditingService', function () { model.dispose(); }); + async function idleAfterEdit(session: IChatEditingSession, model: ChatModel, uri: URI, edits: TextEdit[]) { + const isStreaming = waitForState(session.state.map(s => s === ChatEditingSessionState.StreamingEdits), Boolean); + + const chatRequest = model.addRequest({ text: '', parts: [] }, { variables: [] }, 0); + assertType(chatRequest.response); + + chatRequest.response.updateContent({ kind: 'textEdit', uri, edits, done: true }); + + const entry = await waitForState(session.entries.map(value => value.find(a => isEqual(a.modifiedURI, uri)))); + + assert.ok(isEqual(entry.modifiedURI, uri)); + + chatRequest.response.complete(); + + await isStreaming; + + const isIdle = waitForState(session.state.map(s => s === ChatEditingSessionState.Idle), Boolean); + await isIdle; + + return entry; + } + + test('mirror typing outside -> accept', async function () { + assert.ok(editingService); + + const uri = URI.from({ scheme: 'test', path: 'abc\n' }); + + const model = store.add(chatService.startSession(ChatAgentLocation.Panel, CancellationToken.None)); + const session = await model.editingSessionObs?.promise; + assertType(session, 'session not created'); + + const entry = await idleAfterEdit(session, model, uri, [{ range: new Range(1, 1, 1, 1), text: 'FarBoo\n' }]); + const original = store.add(await textModelService.createModelReference(entry.originalURI)).object.textEditorModel; + const modified = store.add(await textModelService.createModelReference(entry.modifiedURI)).object.textEditorModel; + + assert.strictEqual(entry.state.get(), ModifiedFileEntryState.Modified); + + assert.strictEqual(original.getValue(), 'abc\n'.repeat(10)); + assert.strictEqual(modified.getValue(), 'FarBoo\n' + 'abc\n'.repeat(10)); + + modified.pushEditOperations(null, [EditOperation.insert(new Position(3, 1), 'USER_TYPE\n')], () => null); + + assert.ok(modified.getValue().includes('USER_TYPE')); + assert.ok(original.getValue().includes('USER_TYPE')); + + await entry.accept(); + assert.strictEqual(modified.getValue(), original.getValue()); + assert.strictEqual(entry.state.get(), ModifiedFileEntryState.Accepted); + + assert.ok(modified.getValue().includes('FarBoo')); + assert.ok(original.getValue().includes('FarBoo')); + }); + + test('mirror typing outside -> reject', async function () { + assert.ok(editingService); + + const uri = URI.from({ scheme: 'test', path: 'abc\n' }); + + const model = store.add(chatService.startSession(ChatAgentLocation.Panel, CancellationToken.None)); + const session = await model.editingSessionObs?.promise; + assertType(session, 'session not created'); + + const entry = await idleAfterEdit(session, model, uri, [{ range: new Range(1, 1, 1, 1), text: 'FarBoo\n' }]); + const original = store.add(await textModelService.createModelReference(entry.originalURI)).object.textEditorModel; + const modified = store.add(await textModelService.createModelReference(entry.modifiedURI)).object.textEditorModel; + + assert.strictEqual(entry.state.get(), ModifiedFileEntryState.Modified); + + assert.strictEqual(original.getValue(), 'abc\n'.repeat(10)); + assert.strictEqual(modified.getValue(), 'FarBoo\n' + 'abc\n'.repeat(10)); + + modified.pushEditOperations(null, [EditOperation.insert(new Position(3, 1), 'USER_TYPE\n')], () => null); + + assert.ok(modified.getValue().includes('USER_TYPE')); + assert.ok(original.getValue().includes('USER_TYPE')); + + await entry.reject(); + assert.strictEqual(modified.getValue(), original.getValue()); + assert.strictEqual(entry.state.get(), ModifiedFileEntryState.Rejected); + + assert.ok(!modified.getValue().includes('FarBoo')); + assert.ok(!original.getValue().includes('FarBoo')); + }); + + test('NO mirror typing inside -> accept', async function () { + assert.ok(editingService); + + const uri = URI.from({ scheme: 'test', path: 'abc\n' }); + + const model = store.add(chatService.startSession(ChatAgentLocation.Panel, CancellationToken.None)); + const session = await model.editingSessionObs?.promise; + assertType(session, 'session not created'); + + const entry = await idleAfterEdit(session, model, uri, [{ range: new Range(1, 1, 1, 1), text: 'FarBoo\n' }]); + const original = store.add(await textModelService.createModelReference(entry.originalURI)).object.textEditorModel; + const modified = store.add(await textModelService.createModelReference(entry.modifiedURI)).object.textEditorModel; + + assert.strictEqual(entry.state.get(), ModifiedFileEntryState.Modified); + + assert.strictEqual(original.getValue(), 'abc\n'.repeat(10)); + assert.strictEqual(modified.getValue(), 'FarBoo\n' + 'abc\n'.repeat(10)); + + modified.pushEditOperations(null, [EditOperation.replace(new Range(1, 2, 1, 7), 'ooBar')], () => null); + + assert.ok(modified.getValue().includes('FooBar')); + assert.ok(!original.getValue().includes('FooBar')); // typed in the AI edits, DO NOT transpose + + await entry.accept(); + assert.strictEqual(modified.getValue(), original.getValue()); + assert.strictEqual(entry.state.get(), ModifiedFileEntryState.Accepted); + + assert.ok(modified.getValue().includes('FooBar')); + assert.ok(original.getValue().includes('FooBar')); + }); + }); From 66eceaa63e365da51a506760f075dae30e88724e Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 10 Jun 2025 16:43:23 +0200 Subject: [PATCH 164/236] Fixes some cyclic runtime dependencies --- .../editor/common/core/text/abstractText.ts | 2 +- .../common/core/text/positionToOffset.ts | 122 ++------------- .../common/core/text/positionToOffsetImpl.ts | 142 ++++++++++++++++++ src/vs/editor/common/model.ts | 2 +- src/vs/editor/common/model/textModel.ts | 2 +- src/vs/editor/common/tokens/lineTokens.ts | 107 ++++++++++++- src/vs/editor/common/tokens/tokenArray.ts | 109 -------------- .../inlineEditsViews/inlineEditsCustomView.ts | 5 +- .../inlineEditsInsertionView.ts | 9 +- .../inlineEditsLineReplacementView.ts | 9 +- .../inlineEditsWordReplacementView.ts | 9 +- 11 files changed, 275 insertions(+), 243 deletions(-) create mode 100644 src/vs/editor/common/core/text/positionToOffsetImpl.ts delete mode 100644 src/vs/editor/common/tokens/tokenArray.ts diff --git a/src/vs/editor/common/core/text/abstractText.ts b/src/vs/editor/common/core/text/abstractText.ts index 274a05f2e0e..fe1d35213e6 100644 --- a/src/vs/editor/common/core/text/abstractText.ts +++ b/src/vs/editor/common/core/text/abstractText.ts @@ -6,7 +6,7 @@ import { assert } from '../../../../base/common/assert.js'; import { splitLines } from '../../../../base/common/strings.js'; import { Position } from '../position.js'; -import { PositionOffsetTransformer } from './positionToOffset.js'; +import { PositionOffsetTransformer } from './positionToOffsetImpl.js'; import { Range } from '../range.js'; import { LineRange } from '../ranges/lineRange.js'; import { TextLength } from '../text/textLength.js'; diff --git a/src/vs/editor/common/core/text/positionToOffset.ts b/src/vs/editor/common/core/text/positionToOffset.ts index ed0e5f879ba..97d6ee3bf7c 100644 --- a/src/vs/editor/common/core/text/positionToOffset.ts +++ b/src/vs/editor/common/core/text/positionToOffset.ts @@ -3,117 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { findLastIdxMonotonous } from '../../../../base/common/arraysFind.js'; import { StringEdit, StringReplacement } from '../edits/stringEdit.js'; -import { OffsetRange } from '../ranges/offsetRange.js'; -import { Position } from '../position.js'; -import { Range } from '../range.js'; -import { TextReplacement, TextEdit } from '../edits/textEdit.js'; -import { TextLength } from '../text/textLength.js'; +import { TextEdit, TextReplacement } from '../edits/textEdit.js'; +import { _setPositionOffsetTransformerDependencies } from './positionToOffsetImpl.js'; +import { TextLength } from './textLength.js'; -export abstract class PositionOffsetTransformerBase { - abstract getOffset(position: Position): number; +export { PositionOffsetTransformerBase, PositionOffsetTransformer } from './positionToOffsetImpl.js'; - getOffsetRange(range: Range): OffsetRange { - return new OffsetRange( - this.getOffset(range.getStartPosition()), - this.getOffset(range.getEndPosition()) - ); - } - - abstract getPosition(offset: number): Position; - - getRange(offsetRange: OffsetRange): Range { - return Range.fromPositions( - this.getPosition(offsetRange.start), - this.getPosition(offsetRange.endExclusive) - ); - } - - getStringEdit(edit: TextEdit): StringEdit { - const edits = edit.replacements.map(e => this.getStringReplacement(e)); - return new StringEdit(edits); - } - - getStringReplacement(edit: TextReplacement): StringReplacement { - return new StringReplacement(this.getOffsetRange(edit.range), edit.text); - } - - getSingleTextEdit(edit: StringReplacement): TextReplacement { - return new TextReplacement(this.getRange(edit.replaceRange), edit.newText); - } - - getTextEdit(edit: StringEdit): TextEdit { - const edits = edit.replacements.map(e => this.getSingleTextEdit(e)); - return new TextEdit(edits); - } -} - -export class PositionOffsetTransformer extends PositionOffsetTransformerBase { - private readonly lineStartOffsetByLineIdx: number[]; - private readonly lineEndOffsetByLineIdx: number[]; - - constructor(public readonly text: string) { - super(); - - this.lineStartOffsetByLineIdx = []; - this.lineEndOffsetByLineIdx = []; - - this.lineStartOffsetByLineIdx.push(0); - for (let i = 0; i < text.length; i++) { - if (text.charAt(i) === '\n') { - this.lineStartOffsetByLineIdx.push(i + 1); - if (i > 0 && text.charAt(i - 1) === '\r') { - this.lineEndOffsetByLineIdx.push(i - 1); - } else { - this.lineEndOffsetByLineIdx.push(i); - } - } - } - this.lineEndOffsetByLineIdx.push(text.length); - } - - override getOffset(position: Position): number { - const valPos = this._validatePosition(position); - return this.lineStartOffsetByLineIdx[valPos.lineNumber - 1] + valPos.column - 1; - } - - private _validatePosition(position: Position): Position { - if (position.lineNumber < 1) { - return new Position(1, 1); - } - const lineCount = this.textLength.lineCount + 1; - if (position.lineNumber > lineCount) { - const lineLength = this.getLineLength(lineCount); - return new Position(lineCount, lineLength + 1); - } - if (position.column < 1) { - return new Position(position.lineNumber, 1); - } - const lineLength = this.getLineLength(position.lineNumber); - if (position.column - 1 > lineLength) { - return new Position(position.lineNumber, lineLength + 1); - } - return position; - } - - override getPosition(offset: number): Position { - const idx = findLastIdxMonotonous(this.lineStartOffsetByLineIdx, i => i <= offset); - const lineNumber = idx + 1; - const column = offset - this.lineStartOffsetByLineIdx[idx] + 1; - return new Position(lineNumber, column); - } - - getTextLength(offsetRange: OffsetRange): TextLength { - return TextLength.ofRange(this.getRange(offsetRange)); - } - - get textLength(): TextLength { - const lineIdx = this.lineStartOffsetByLineIdx.length - 1; - return new TextLength(lineIdx, this.text.length - this.lineStartOffsetByLineIdx[lineIdx]); - } - - getLineLength(lineNumber: number): number { - return this.lineEndOffsetByLineIdx[lineNumber - 1] - this.lineStartOffsetByLineIdx[lineNumber - 1]; - } -} +_setPositionOffsetTransformerDependencies({ + StringEdit: StringEdit, + StringReplacement: StringReplacement, + TextReplacement: TextReplacement, + TextEdit: TextEdit, + TextLength: TextLength, +}); diff --git a/src/vs/editor/common/core/text/positionToOffsetImpl.ts b/src/vs/editor/common/core/text/positionToOffsetImpl.ts new file mode 100644 index 00000000000..deb847b1322 --- /dev/null +++ b/src/vs/editor/common/core/text/positionToOffsetImpl.ts @@ -0,0 +1,142 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { findLastIdxMonotonous } from '../../../../base/common/arraysFind.js'; +import { StringEdit, StringReplacement } from '../edits/stringEdit.js'; +import { OffsetRange } from '../ranges/offsetRange.js'; +import { Position } from '../position.js'; +import { Range } from '../range.js'; +import type { TextReplacement, TextEdit } from '../edits/textEdit.js'; +import type { TextLength } from '../text/textLength.js'; + +export abstract class PositionOffsetTransformerBase { + abstract getOffset(position: Position): number; + + getOffsetRange(range: Range): OffsetRange { + return new OffsetRange( + this.getOffset(range.getStartPosition()), + this.getOffset(range.getEndPosition()) + ); + } + + abstract getPosition(offset: number): Position; + + getRange(offsetRange: OffsetRange): Range { + return Range.fromPositions( + this.getPosition(offsetRange.start), + this.getPosition(offsetRange.endExclusive) + ); + } + + getStringEdit(edit: TextEdit): StringEdit { + const edits = edit.replacements.map(e => this.getStringReplacement(e)); + return new Deps.deps.StringEdit(edits); + } + + getStringReplacement(edit: TextReplacement): StringReplacement { + return new Deps.deps.StringReplacement(this.getOffsetRange(edit.range), edit.text); + } + + getSingleTextEdit(edit: StringReplacement): TextReplacement { + return new Deps.deps.TextReplacement(this.getRange(edit.replaceRange), edit.newText); + } + + getTextEdit(edit: StringEdit): TextEdit { + const edits = edit.replacements.map(e => this.getSingleTextEdit(e)); + return new Deps.deps.TextEdit(edits); + } +} + +interface IDeps { + StringEdit: typeof StringEdit; + StringReplacement: typeof StringReplacement; + TextReplacement: typeof TextReplacement; + TextEdit: typeof TextEdit; + TextLength: typeof TextLength; +} + +class Deps { + static _deps: IDeps | undefined = undefined; + static get deps(): IDeps { + if (!this._deps) { + throw new Error('Dependencies not set. Call _setDependencies first.'); + } + return this._deps; + } +} + +/** This is to break circular module dependencies. */ +export function _setPositionOffsetTransformerDependencies(deps: IDeps): void { + Deps._deps = deps; +} + +export class PositionOffsetTransformer extends PositionOffsetTransformerBase { + private readonly lineStartOffsetByLineIdx: number[]; + private readonly lineEndOffsetByLineIdx: number[]; + + constructor(public readonly text: string) { + super(); + + this.lineStartOffsetByLineIdx = []; + this.lineEndOffsetByLineIdx = []; + + this.lineStartOffsetByLineIdx.push(0); + for (let i = 0; i < text.length; i++) { + if (text.charAt(i) === '\n') { + this.lineStartOffsetByLineIdx.push(i + 1); + if (i > 0 && text.charAt(i - 1) === '\r') { + this.lineEndOffsetByLineIdx.push(i - 1); + } else { + this.lineEndOffsetByLineIdx.push(i); + } + } + } + this.lineEndOffsetByLineIdx.push(text.length); + } + + override getOffset(position: Position): number { + const valPos = this._validatePosition(position); + return this.lineStartOffsetByLineIdx[valPos.lineNumber - 1] + valPos.column - 1; + } + + private _validatePosition(position: Position): Position { + if (position.lineNumber < 1) { + return new Position(1, 1); + } + const lineCount = this.textLength.lineCount + 1; + if (position.lineNumber > lineCount) { + const lineLength = this.getLineLength(lineCount); + return new Position(lineCount, lineLength + 1); + } + if (position.column < 1) { + return new Position(position.lineNumber, 1); + } + const lineLength = this.getLineLength(position.lineNumber); + if (position.column - 1 > lineLength) { + return new Position(position.lineNumber, lineLength + 1); + } + return position; + } + + override getPosition(offset: number): Position { + const idx = findLastIdxMonotonous(this.lineStartOffsetByLineIdx, i => i <= offset); + const lineNumber = idx + 1; + const column = offset - this.lineStartOffsetByLineIdx[idx] + 1; + return new Position(lineNumber, column); + } + + getTextLength(offsetRange: OffsetRange): TextLength { + return Deps.deps.TextLength.ofRange(this.getRange(offsetRange)); + } + + get textLength(): TextLength { + const lineIdx = this.lineStartOffsetByLineIdx.length - 1; + return new Deps.deps.TextLength(lineIdx, this.text.length - this.lineStartOffsetByLineIdx[lineIdx]); + } + + getLineLength(lineNumber: number): number { + return this.lineEndOffsetByLineIdx[lineNumber - 1] - this.lineStartOffsetByLineIdx[lineNumber - 1]; + } +} diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index ad56a01c508..e0cdf27692b 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -23,7 +23,7 @@ import { IModelContentChange, IModelContentChangedEvent, IModelDecorationsChange import { IGuidesTextModelPart } from './textModelGuides.js'; import { ITokenizationTextModelPart } from './tokenizationTextModelPart.js'; import { UndoRedoGroup } from '../../platform/undoRedo/common/undoRedo.js'; -import { TokenArray } from './tokens/tokenArray.js'; +import { TokenArray } from './tokens/lineTokens.js'; import { IEditorModel } from './editorCommon.js'; import { TextModelEditReason } from './textModelEditReason.js'; diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 9497bc5a304..ddcc455dde6 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -46,7 +46,7 @@ import { ITokenizationTextModelPart } from '../tokenizationTextModelPart.js'; import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js'; import { IColorTheme } from '../../../platform/theme/common/themeService.js'; import { IUndoRedoService, ResourceEditStackSnapshot, UndoRedoGroup } from '../../../platform/undoRedo/common/undoRedo.js'; -import { TokenArray } from '../tokens/tokenArray.js'; +import { TokenArray } from '../tokens/lineTokens.js'; import { SetWithKey } from '../../../base/common/collections.js'; import { TextModelEditReason } from '../textModelEditReason.js'; diff --git a/src/vs/editor/common/tokens/lineTokens.ts b/src/vs/editor/common/tokens/lineTokens.ts index 5beed680735..ef2ec6cd642 100644 --- a/src/vs/editor/common/tokens/lineTokens.ts +++ b/src/vs/editor/common/tokens/lineTokens.ts @@ -4,11 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { ILanguageIdCodec } from '../languages.js'; -import { FontStyle, ColorId, StandardTokenType, MetadataConsts, TokenMetadata, ITokenPresentation } from '../encodedTokenAttributes.js'; +import { FontStyle, ColorId, StandardTokenType, MetadataConsts, ITokenPresentation, TokenMetadata } from '../encodedTokenAttributes.js'; import { IPosition } from '../core/position.js'; import { ITextModel } from '../model.js'; import { OffsetRange } from '../core/ranges/offsetRange.js'; -import { TokenArray, TokenArrayBuilder } from './tokenArray.js'; import { onUnexpectedError } from '../../../base/common/errors.js'; @@ -422,3 +421,107 @@ export function getStandardTokenTypeAtPosition(model: ITextModel, position: IPos const tokenType = lineTokens.getStandardTokenType(tokenIndex); return tokenType; } + + + +/** + * This class represents a sequence of tokens. + * Conceptually, each token has a length and a metadata number. + * A token array might be used to annotate a string with metadata. + * Use {@link TokenArrayBuilder} to efficiently create a token array. + * + * TODO: Make this class more efficient (e.g. by using a Int32Array). +*/ +export class TokenArray { + public static fromLineTokens(lineTokens: LineTokens): TokenArray { + const tokenInfo: TokenInfo[] = []; + for (let i = 0; i < lineTokens.getCount(); i++) { + tokenInfo.push(new TokenInfo(lineTokens.getEndOffset(i) - lineTokens.getStartOffset(i), lineTokens.getMetadata(i))); + } + return TokenArray.create(tokenInfo); + } + + public static create(tokenInfo: TokenInfo[]): TokenArray { + return new TokenArray(tokenInfo); + } + + private constructor( + private readonly _tokenInfo: TokenInfo[] + ) { } + + public toLineTokens(lineContent: string, decoder: ILanguageIdCodec): LineTokens { + return LineTokens.createFromTextAndMetadata(this.map((r, t) => ({ text: r.substring(lineContent), metadata: t.metadata })), decoder); + } + + public forEach(cb: (range: OffsetRange, tokenInfo: TokenInfo) => void): void { + let lengthSum = 0; + for (const tokenInfo of this._tokenInfo) { + const range = new OffsetRange(lengthSum, lengthSum + tokenInfo.length); + cb(range, tokenInfo); + lengthSum += tokenInfo.length; + } + } + + public map(cb: (range: OffsetRange, tokenInfo: TokenInfo) => T): T[] { + const result: T[] = []; + let lengthSum = 0; + for (const tokenInfo of this._tokenInfo) { + const range = new OffsetRange(lengthSum, lengthSum + tokenInfo.length); + result.push(cb(range, tokenInfo)); + lengthSum += tokenInfo.length; + } + return result; + } + + public slice(range: OffsetRange): TokenArray { + const result: TokenInfo[] = []; + let lengthSum = 0; + for (const tokenInfo of this._tokenInfo) { + const tokenStart = lengthSum; + const tokenEndEx = tokenStart + tokenInfo.length; + if (tokenEndEx > range.start) { + if (tokenStart >= range.endExclusive) { + break; + } + + const deltaBefore = Math.max(0, range.start - tokenStart); + const deltaAfter = Math.max(0, tokenEndEx - range.endExclusive); + + result.push(new TokenInfo(tokenInfo.length - deltaBefore - deltaAfter, tokenInfo.metadata)); + } + + lengthSum += tokenInfo.length; + } + return TokenArray.create(result); + } + + public append(other: TokenArray): TokenArray { + const result: TokenInfo[] = this._tokenInfo.concat(other._tokenInfo); + return TokenArray.create(result); + } +} + +export type ITokenMetadata = number; + +export class TokenInfo { + constructor( + public readonly length: number, + public readonly metadata: ITokenMetadata + ) { } +} +/** + * TODO: Make this class more efficient (e.g. by using a Int32Array). +*/ + +export class TokenArrayBuilder { + private readonly _tokens: TokenInfo[] = []; + + public add(length: number, metadata: ITokenMetadata): void { + this._tokens.push(new TokenInfo(length, metadata)); + } + + public build(): TokenArray { + return TokenArray.create(this._tokens); + } +} + diff --git a/src/vs/editor/common/tokens/tokenArray.ts b/src/vs/editor/common/tokens/tokenArray.ts deleted file mode 100644 index 93f19a8ec97..00000000000 --- a/src/vs/editor/common/tokens/tokenArray.ts +++ /dev/null @@ -1,109 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { OffsetRange } from '../core/ranges/offsetRange.js'; -import { ILanguageIdCodec } from '../languages.js'; -import { LineTokens } from './lineTokens.js'; - -/** - * This class represents a sequence of tokens. - * Conceptually, each token has a length and a metadata number. - * A token array might be used to annotate a string with metadata. - * Use {@link TokenArrayBuilder} to efficiently create a token array. - * - * TODO: Make this class more efficient (e.g. by using a Int32Array). -*/ -export class TokenArray { - public static fromLineTokens(lineTokens: LineTokens): TokenArray { - const tokenInfo: TokenInfo[] = []; - for (let i = 0; i < lineTokens.getCount(); i++) { - tokenInfo.push(new TokenInfo(lineTokens.getEndOffset(i) - lineTokens.getStartOffset(i), lineTokens.getMetadata(i))); - } - return TokenArray.create(tokenInfo); - } - - public static create(tokenInfo: TokenInfo[]): TokenArray { - return new TokenArray(tokenInfo); - } - - private constructor( - private readonly _tokenInfo: TokenInfo[], - ) { } - - public toLineTokens(lineContent: string, decoder: ILanguageIdCodec): LineTokens { - return LineTokens.createFromTextAndMetadata(this.map((r, t) => ({ text: r.substring(lineContent), metadata: t.metadata })), decoder); - } - - public forEach(cb: (range: OffsetRange, tokenInfo: TokenInfo) => void): void { - let lengthSum = 0; - for (const tokenInfo of this._tokenInfo) { - const range = new OffsetRange(lengthSum, lengthSum + tokenInfo.length); - cb(range, tokenInfo); - lengthSum += tokenInfo.length; - } - } - - public map(cb: (range: OffsetRange, tokenInfo: TokenInfo) => T): T[] { - const result: T[] = []; - let lengthSum = 0; - for (const tokenInfo of this._tokenInfo) { - const range = new OffsetRange(lengthSum, lengthSum + tokenInfo.length); - result.push(cb(range, tokenInfo)); - lengthSum += tokenInfo.length; - } - return result; - } - - public slice(range: OffsetRange): TokenArray { - const result: TokenInfo[] = []; - let lengthSum = 0; - for (const tokenInfo of this._tokenInfo) { - const tokenStart = lengthSum; - const tokenEndEx = tokenStart + tokenInfo.length; - if (tokenEndEx > range.start) { - if (tokenStart >= range.endExclusive) { - break; - } - - const deltaBefore = Math.max(0, range.start - tokenStart); - const deltaAfter = Math.max(0, tokenEndEx - range.endExclusive); - - result.push(new TokenInfo(tokenInfo.length - deltaBefore - deltaAfter, tokenInfo.metadata)); - } - - lengthSum += tokenInfo.length; - } - return TokenArray.create(result); - } - - public append(other: TokenArray): TokenArray { - const result: TokenInfo[] = this._tokenInfo.concat(other._tokenInfo); - return TokenArray.create(result); - } -} - -export type TokenMetadata = number; - -export class TokenInfo { - constructor( - public readonly length: number, - public readonly metadata: TokenMetadata, - ) { } -} - -/** - * TODO: Make this class more efficient (e.g. by using a Int32Array). -*/ -export class TokenArrayBuilder { - private readonly _tokens: TokenInfo[] = []; - - public add(length: number, metadata: TokenMetadata): void { - this._tokens.push(new TokenInfo(length, metadata)); - } - - public build(): TokenArray { - return TokenArray.create(this._tokens); - } -} diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts index 9a58349ef2f..01ca906fb37 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts @@ -12,14 +12,13 @@ import { asCssVariable } from '../../../../../../../platform/theme/common/colorU import { IThemeService } from '../../../../../../../platform/theme/common/themeService.js'; import { ICodeEditor } from '../../../../../../browser/editorBrowser.js'; import { ObservableCodeEditor, observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; -import { Rect } from '../../../../../../common/core/2d/rect.js'; import { LineSource, renderLines, RenderOptions } from '../../../../../../browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; import { EditorOption } from '../../../../../../common/config/editorOptions.js'; +import { Rect } from '../../../../../../common/core/2d/rect.js'; import { LineRange } from '../../../../../../common/core/ranges/lineRange.js'; import { InlineCompletionDisplayLocation } from '../../../../../../common/languages.js'; import { ILanguageService } from '../../../../../../common/languages/language.js'; -import { LineTokens } from '../../../../../../common/tokens/lineTokens.js'; -import { TokenArray } from '../../../../../../common/tokens/tokenArray.js'; +import { LineTokens, TokenArray } from '../../../../../../common/tokens/lineTokens.js'; import { IInlineEditsView, InlineEditTabAction } from '../inlineEditsViewInterface.js'; import { getEditorBlendedColor, inlineEditIndicatorPrimaryBackground, inlineEditIndicatorSecondaryBackground, inlineEditIndicatorsuccessfulBackground } from '../theme.js'; import { maxContentWidthInRange, rectToProps } from '../utils/utils.js'; diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts index fb3eec679d3..2a681756bf4 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts @@ -12,16 +12,15 @@ import { editorBackground } from '../../../../../../../platform/theme/common/col import { asCssVariable } from '../../../../../../../platform/theme/common/colorUtils.js'; import { ICodeEditor } from '../../../../../../browser/editorBrowser.js'; import { ObservableCodeEditor, observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; -import { Rect } from '../../../../../../common/core/2d/rect.js'; import { LineSource, renderLines, RenderOptions } from '../../../../../../browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; import { EditorOption } from '../../../../../../common/config/editorOptions.js'; -import { LineRange } from '../../../../../../common/core/ranges/lineRange.js'; -import { OffsetRange } from '../../../../../../common/core/ranges/offsetRange.js'; +import { Rect } from '../../../../../../common/core/2d/rect.js'; import { Position } from '../../../../../../common/core/position.js'; import { Range } from '../../../../../../common/core/range.js'; +import { LineRange } from '../../../../../../common/core/ranges/lineRange.js'; +import { OffsetRange } from '../../../../../../common/core/ranges/offsetRange.js'; import { ILanguageService } from '../../../../../../common/languages/language.js'; -import { LineTokens } from '../../../../../../common/tokens/lineTokens.js'; -import { TokenArray } from '../../../../../../common/tokens/tokenArray.js'; +import { LineTokens, TokenArray } from '../../../../../../common/tokens/lineTokens.js'; import { InlineDecoration, InlineDecorationType } from '../../../../../../common/viewModel.js'; import { GhostText, GhostTextPart } from '../../../model/ghostText.js'; import { GhostTextView } from '../../ghostText/ghostTextView.js'; diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts index 27447f6a1ac..e014a42f695 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts @@ -14,17 +14,16 @@ import { IThemeService } from '../../../../../../../platform/theme/common/themeS import { IEditorMouseEvent, IViewZoneChangeAccessor } from '../../../../../../browser/editorBrowser.js'; import { EditorMouseEvent } from '../../../../../../browser/editorDom.js'; import { ObservableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; -import { Point } from '../../../../../../common/core/2d/point.js'; -import { Rect } from '../../../../../../common/core/2d/rect.js'; import { LineSource, renderLines, RenderOptions } from '../../../../../../browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; import { EditorOption } from '../../../../../../common/config/editorOptions.js'; +import { Point } from '../../../../../../common/core/2d/point.js'; +import { Rect } from '../../../../../../common/core/2d/rect.js'; +import { Range } from '../../../../../../common/core/range.js'; import { LineRange } from '../../../../../../common/core/ranges/lineRange.js'; import { OffsetRange } from '../../../../../../common/core/ranges/offsetRange.js'; -import { Range } from '../../../../../../common/core/range.js'; import { ILanguageService } from '../../../../../../common/languages/language.js'; import { IModelDecorationOptions, TrackedRangeStickiness } from '../../../../../../common/model.js'; -import { LineTokens } from '../../../../../../common/tokens/lineTokens.js'; -import { TokenArray } from '../../../../../../common/tokens/tokenArray.js'; +import { LineTokens, TokenArray } from '../../../../../../common/tokens/lineTokens.js'; import { InlineDecoration, InlineDecorationType } from '../../../../../../common/viewModel.js'; import { IInlineEditsView, InlineEditTabAction } from '../inlineEditsViewInterface.js'; import { getEditorBlendedColor, getModifiedBorderColor, getOriginalBorderColor, modifiedChangedLineBackgroundColor, originalBackgroundColor } from '../theme.js'; diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts index 09e0f708ed4..93d45294f36 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts @@ -11,16 +11,15 @@ import { constObservable, derived, IObservable, observableValue } from '../../.. import { editorBackground, editorHoverForeground } from '../../../../../../../platform/theme/common/colorRegistry.js'; import { asCssVariable } from '../../../../../../../platform/theme/common/colorUtils.js'; import { ObservableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; -import { Point } from '../../../../../../common/core/2d/point.js'; -import { Rect } from '../../../../../../common/core/2d/rect.js'; import { LineSource, renderLines, RenderOptions } from '../../../../../../browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; import { EditorOption } from '../../../../../../common/config/editorOptions.js'; +import { Point } from '../../../../../../common/core/2d/point.js'; +import { Rect } from '../../../../../../common/core/2d/rect.js'; import { StringReplacement } from '../../../../../../common/core/edits/stringEdit.js'; -import { OffsetRange } from '../../../../../../common/core/ranges/offsetRange.js'; import { TextReplacement } from '../../../../../../common/core/edits/textEdit.js'; +import { OffsetRange } from '../../../../../../common/core/ranges/offsetRange.js'; import { ILanguageService } from '../../../../../../common/languages/language.js'; -import { LineTokens } from '../../../../../../common/tokens/lineTokens.js'; -import { TokenArray } from '../../../../../../common/tokens/tokenArray.js'; +import { LineTokens, TokenArray } from '../../../../../../common/tokens/lineTokens.js'; import { IInlineEditsView, InlineEditTabAction } from '../inlineEditsViewInterface.js'; import { getModifiedBorderColor, getOriginalBorderColor, modifiedChangedTextOverlayColor, originalChangedTextOverlayColor } from '../theme.js'; import { getEditorValidOverlayRect, mapOutFalsy, rectToProps } from '../utils/utils.js'; From b35b527c41e387c42039f17a45a9f619198fd70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E8=89=AF?= <1204183885@qq.com> Date: Tue, 10 Jun 2025 22:53:02 +0800 Subject: [PATCH 165/236] Fix #250737, Match count result overflow in Notebook findWidget (#250738) --- .../contrib/notebook/browser/contrib/find/notebookFindWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts index bb0c49f4bba..546efce7200 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts @@ -364,7 +364,7 @@ class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEdi return; } - this._matchesCount.style.width = MAX_MATCHES_COUNT_WIDTH + 'px'; + this._matchesCount.style.minWidth = MAX_MATCHES_COUNT_WIDTH + 'px'; this._matchesCount.title = ''; // remove previous content From d123e6167a9be837d79f3cdcc2b7277eb48e856a Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 10 Jun 2025 17:07:08 +0200 Subject: [PATCH 166/236] fix cyclic dependency chatAction <-> chatEditorInput. fyi @roblourens --- .../chat/browser/actions/chatActions.ts | 48 +----------------- .../contrib/chat/browser/chatEditorInput.ts | 50 ++++++++++++++++++- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index e8c46616b85..d96be5941b6 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -59,7 +59,7 @@ import { CopilotUsageExtensionFeatureId } from '../../common/languageModelStats. import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; import { ChatViewId, IChatWidget, IChatWidgetService, showChatView, showCopilotView } from '../chat.js'; import { IChatEditorOptions } from '../chatEditor.js'; -import { ChatEditorInput } from '../chatEditorInput.js'; +import { ChatEditorInput, shouldShowClearEditingSessionConfirmation, showClearEditingSessionConfirmation } from '../chatEditorInput.js'; import { ChatViewPane } from '../chatViewPane.js'; import { convertBufferToScreenshotVariable } from '../contrib/screenshot.js'; import { clearChatEditor } from './chatClear.js'; @@ -990,52 +990,6 @@ export interface IClearEditingSessionConfirmationOptions { messageOverride?: string; } -export async function showClearEditingSessionConfirmation(editingSession: IChatEditingSession, dialogService: IDialogService, options?: IClearEditingSessionConfirmationOptions): Promise { - const defaultPhrase = localize('chat.startEditing.confirmation.pending.message.default', "Starting a new chat will end your current edit session."); - const defaultTitle = localize('chat.startEditing.confirmation.title', "Start new chat?"); - const phrase = options?.messageOverride ?? defaultPhrase; - const title = options?.titleOverride ?? defaultTitle; - - const currentEdits = editingSession.entries.get(); - const undecidedEdits = currentEdits.filter((edit) => edit.state.get() === ModifiedFileEntryState.Modified); - - const { result } = await dialogService.prompt({ - title, - message: phrase + ' ' + localize('chat.startEditing.confirmation.pending.message.2', "Do you want to keep pending edits to {0} files?", undecidedEdits.length), - type: 'info', - cancelButton: true, - buttons: [ - { - label: localize('chat.startEditing.confirmation.acceptEdits', "Keep & Continue"), - run: async () => { - await editingSession.accept(); - return true; - } - }, - { - label: localize('chat.startEditing.confirmation.discardEdits', "Undo & Continue"), - run: async () => { - await editingSession.reject(); - return true; - } - } - ], - }); - - return Boolean(result); -} - -export function shouldShowClearEditingSessionConfirmation(editingSession: IChatEditingSession): boolean { - const currentEdits = editingSession.entries.get(); - const currentEditCount = currentEdits.length; - - if (currentEditCount) { - const undecidedEdits = currentEdits.filter((edit) => edit.state.get() === ModifiedFileEntryState.Modified); - return !!undecidedEdits.length; - } - - return false; -} // --- Chat Submenus in various Components diff --git a/src/vs/workbench/contrib/chat/browser/chatEditorInput.ts b/src/vs/workbench/contrib/chat/browser/chatEditorInput.ts index 6dad621002c..e4ff9246db0 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditorInput.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditorInput.ts @@ -20,7 +20,8 @@ import { IChatModel } from '../common/chatModel.js'; import { IChatService } from '../common/chatService.js'; import { ChatAgentLocation } from '../common/constants.js'; import { ConfirmResult, IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; -import { shouldShowClearEditingSessionConfirmation, showClearEditingSessionConfirmation } from './actions/chatActions.js'; +import { IChatEditingSession, ModifiedFileEntryState } from '../common/chatEditingService.js'; +import { IClearEditingSessionConfirmationOptions } from './actions/chatActions.js'; const ChatEditorIcon = registerIcon('chat-editor-label-icon', Codicon.commentDiscussion, nls.localize('chatEditorLabelIcon', 'Icon of the chat editor label.')); @@ -231,3 +232,50 @@ export class ChatEditorInputSerializer implements IEditorSerializer { } } } + +export async function showClearEditingSessionConfirmation(editingSession: IChatEditingSession, dialogService: IDialogService, options?: IClearEditingSessionConfirmationOptions): Promise { + const defaultPhrase = nls.localize('chat.startEditing.confirmation.pending.message.default1', "Starting a new chat will end your current edit session."); + const defaultTitle = nls.localize('chat.startEditing.confirmation.title', "Start new chat?"); + const phrase = options?.messageOverride ?? defaultPhrase; + const title = options?.titleOverride ?? defaultTitle; + + const currentEdits = editingSession.entries.get(); + const undecidedEdits = currentEdits.filter((edit) => edit.state.get() === ModifiedFileEntryState.Modified); + + const { result } = await dialogService.prompt({ + title, + message: phrase + ' ' + nls.localize('chat.startEditing.confirmation.pending.message.2', "Do you want to keep pending edits to {0} files?", undecidedEdits.length), + type: 'info', + cancelButton: true, + buttons: [ + { + label: nls.localize('chat.startEditing.confirmation.acceptEdits', "Keep & Continue"), + run: async () => { + await editingSession.accept(); + return true; + } + }, + { + label: nls.localize('chat.startEditing.confirmation.discardEdits', "Undo & Continue"), + run: async () => { + await editingSession.reject(); + return true; + } + } + ], + }); + + return Boolean(result); +} + +export function shouldShowClearEditingSessionConfirmation(editingSession: IChatEditingSession): boolean { + const currentEdits = editingSession.entries.get(); + const currentEditCount = currentEdits.length; + + if (currentEditCount) { + const undecidedEdits = currentEdits.filter((edit) => edit.state.get() === ModifiedFileEntryState.Modified); + return !!undecidedEdits.length; + } + + return false; +} From 2e2ca2d8570891f63e1ca6bac2914a6b3ca1e0e3 Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 10 Jun 2025 17:32:26 +0200 Subject: [PATCH 167/236] fix cyclic dependency with `ChatInputPart#INPUT_SCHEME` fyi @roblourens --- src/vs/base/common/network.ts | 3 +++ .../api/browser/mainThreadChatAgents2.ts | 4 ++-- .../chatEdinputInputContentProvider.ts | 4 ++-- .../contrib/chat/browser/chatInputPart.ts | 4 ++-- .../chat/browser/chatPasteProviders.ts | 13 ++++++------ .../browser/contrib/chatInputCompletions.ts | 21 +++++++++---------- .../chat/notebook.chat.contribution.ts | 4 ++-- 7 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 193f687da24..f640014499e 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -84,6 +84,9 @@ export namespace Schemas { /** Scheme used for the chat input editor. */ export const vscodeChatSesssion = 'vscode-chat-editor'; + /** Scheme used for the chat input part */ + export const vscodeChatInput = 'chatSessionInput'; + /** * Scheme used internally for webviews that aren't linked to a resource (i.e. not custom editors) */ diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index a43107d7502..557a2376556 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -12,6 +12,7 @@ import { revive } from '../../../base/common/marshalling.js'; import { escapeRegExpCharacters } from '../../../base/common/strings.js'; import { ThemeIcon } from '../../../base/common/themables.js'; import { URI, UriComponents } from '../../../base/common/uri.js'; +import { Schemas } from '../../../base/common/network.js'; import { Position } from '../../../editor/common/core/position.js'; import { Range } from '../../../editor/common/core/range.js'; import { getWordAtText } from '../../../editor/common/core/wordHelper.js'; @@ -23,7 +24,6 @@ import { IInstantiationService } from '../../../platform/instantiation/common/in import { ILogService } from '../../../platform/log/common/log.js'; import { IUriIdentityService } from '../../../platform/uriIdentity/common/uriIdentity.js'; import { IChatWidgetService } from '../../contrib/chat/browser/chat.js'; -import { ChatInputPart } from '../../contrib/chat/browser/chatInputPart.js'; import { AddDynamicVariableAction, IAddDynamicVariableContext } from '../../contrib/chat/browser/contrib/chatDynamicVariables.js'; import { IChatAgentHistoryEntry, IChatAgentImplementation, IChatAgentRequest, IChatAgentService } from '../../contrib/chat/common/chatAgents.js'; import { IChatEditingService, IChatRelatedFileProviderMetadata } from '../../contrib/chat/common/chatEditingService.js'; @@ -313,7 +313,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA }; this._agentIdsToCompletionProviders.set(id, this._chatAgentService.registerAgentCompletionProvider(id, provide)); - this._agentCompletionProviders.set(handle, this._languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._agentCompletionProviders.set(handle, this._languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'chatAgentCompletions:' + handle, triggerCharacters, provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken) => { diff --git a/src/vs/workbench/contrib/chat/browser/chatEdinputInputContentProvider.ts b/src/vs/workbench/contrib/chat/browser/chatEdinputInputContentProvider.ts index cbc084b3b82..d114f65a86f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEdinputInputContentProvider.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEdinputInputContentProvider.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from '../../../../base/common/lifecycle.js'; +import { Schemas } from '../../../../base/common/network.js'; import { URI } from '../../../../base/common/uri.js'; import { ILanguageService } from '../../../../editor/common/languages/language.js'; import { ITextModel } from '../../../../editor/common/model.js'; import { IModelService } from '../../../../editor/common/services/model.js'; import { ITextModelContentProvider, ITextModelService } from '../../../../editor/common/services/resolverService.js'; -import { ChatInputPart } from './chatInputPart.js'; export class ChatInputBoxContentProvider extends Disposable implements ITextModelContentProvider { @@ -19,7 +19,7 @@ export class ChatInputBoxContentProvider extends Disposable implements ITextMode @ILanguageService private readonly languageService: ILanguageService ) { super(); - this._register(textModelService.registerTextModelContentProvider(ChatInputPart.INPUT_SCHEME, this)); + this._register(textModelService.registerTextModelContentProvider(Schemas.vscodeChatInput, this)); } async provideTextContent(resource: URI): Promise { diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 3cbca481b93..c495c5cb178 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -27,6 +27,7 @@ import { isMacintosh } from '../../../../base/common/platform.js'; import { isEqual } from '../../../../base/common/resources.js'; import { assertType } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; +import { Schemas } from '../../../../base/common/network.js'; import { IEditorConstructionOptions } from '../../../../editor/browser/config/editorConfiguration.js'; import { EditorExtensionsRegistry } from '../../../../editor/browser/editorExtensions.js'; import { CodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/codeEditorWidget.js'; @@ -137,7 +138,6 @@ export interface IWorkingSetEntry { const GlobalLastChatModeKey = 'chat.lastChatMode'; export class ChatInputPart extends Disposable implements IHistoryNavigationWidget { - static readonly INPUT_SCHEME = 'chatSessionInput'; private static _counter = 0; private _onDidLoadInputState: Emitter; @@ -427,7 +427,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this._onDidChangeCurrentChatMode = this._register(new Emitter()); this.onDidChangeCurrentChatMode = this._onDidChangeCurrentChatMode.event; this._currentMode = ChatMode2.Ask; - this.inputUri = URI.parse(`${ChatInputPart.INPUT_SCHEME}:input-${ChatInputPart._counter++}`); + this.inputUri = URI.parse(`${Schemas.vscodeChatInput}:input-${ChatInputPart._counter++}`); this._chatEditsActionsDisposables = this._register(new DisposableStore()); this._chatEditsDisposables = this._register(new DisposableStore()); this._attemptedWorkingSetEntriesCount = 0; diff --git a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts index eef54ec9891..c06fc723962 100644 --- a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts +++ b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts @@ -9,6 +9,7 @@ import { HierarchicalKind } from '../../../../base/common/hierarchicalKind.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { revive } from '../../../../base/common/marshalling.js'; import { Mimes } from '../../../../base/common/mime.js'; +import { Schemas } from '../../../../base/common/network.js'; import { basename, joinPath } from '../../../../base/common/resources.js'; import { URI, UriComponents } from '../../../../base/common/uri.js'; import { IRange } from '../../../../editor/common/core/range.js'; @@ -25,7 +26,6 @@ import { IExtensionService, isProposedApiEnabled } from '../../../services/exten import { IChatRequestPasteVariableEntry, IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; import { IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js'; import { IChatWidgetService } from './chat.js'; -import { ChatInputPart } from './chatInputPart.js'; import { ChatDynamicVariableModel } from './contrib/chatDynamicVariables.js'; import { cleanupOldImages, createFileForMedia, resizeImage } from './imageUtils.js'; @@ -180,7 +180,7 @@ export class CopyTextProvider implements DocumentPasteEditProvider { public readonly pasteMimeTypes = []; async prepareDocumentPaste(model: ITextModel, ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise { - if (model.uri.scheme === ChatInputPart.INPUT_SCHEME) { + if (model.uri.scheme === Schemas.vscodeChatInput) { return; } @@ -304,7 +304,7 @@ export class PasteTextProvider implements DocumentPasteEditProvider { ) { } async provideDocumentPasteEdits(model: ITextModel, ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, _context: DocumentPasteContext, token: CancellationToken): Promise { - if (model.uri.scheme !== ChatInputPart.INPUT_SCHEME) { + if (model.uri.scheme !== Schemas.vscodeChatInput) { return; } const text = dataTransfer.get(Mimes.text); @@ -442,9 +442,10 @@ export class ChatPasteProvidersFeature extends Disposable { @ILogService logService: ILogService, ) { super(); - this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, pattern: '*', hasAccessToAllModels: true }, instaService.createInstance(CopyAttachmentsProvider))); - this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, pattern: '*', hasAccessToAllModels: true }, new PasteImageProvider(chatWidgetService, extensionService, fileService, environmentService, logService))); - this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, pattern: '*', hasAccessToAllModels: true }, new PasteTextProvider(chatWidgetService, modelService))); + this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: Schemas.vscodeChatInput, pattern: '*', hasAccessToAllModels: true }, instaService.createInstance(CopyAttachmentsProvider))); + this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: Schemas.vscodeChatInput, pattern: '*', hasAccessToAllModels: true }, new PasteImageProvider(chatWidgetService, extensionService, fileService, environmentService, logService))); + this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: Schemas.vscodeChatInput, pattern: '*', hasAccessToAllModels: true }, new PasteTextProvider(chatWidgetService, modelService))); + this._register(languageFeaturesService.documentPasteEditProvider.register('*', new CopyTextProvider())); this._register(languageFeaturesService.documentPasteEditProvider.register('*', new CopyTextProvider())); } } diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts index f3dec9be600..13067fe7199 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts @@ -56,7 +56,6 @@ import { ToolSet } from '../../common/languageModelToolsService.js'; import { IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; import { ChatSubmitAction } from '../actions/chatExecuteActions.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; -import { ChatInputPart } from '../chatInputPart.js'; import { ChatDynamicVariableModel } from './chatDynamicVariables.js'; class SlashCommandCompletions extends Disposable { @@ -69,7 +68,7 @@ class SlashCommandCompletions extends Disposable { ) { super(); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'globalSlashCommands', triggerCharacters: ['/'], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { @@ -116,7 +115,7 @@ class SlashCommandCompletions extends Disposable { }; } })); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'globalSlashCommandsAt', triggerCharacters: [chatAgentLeader], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { @@ -157,7 +156,7 @@ class SlashCommandCompletions extends Disposable { }; } })); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'promptSlashCommands', triggerCharacters: ['/'], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { @@ -205,7 +204,7 @@ class SlashCommandCompletions extends Disposable { } })); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'mcpPromptSlashCommands', triggerCharacters: ['/'], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { @@ -307,9 +306,9 @@ class AgentCompletions extends Disposable { }; } }; - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, subCommandProvider)); + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, subCommandProvider)); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'chatAgentAndSubcommand', triggerCharacters: [chatAgentLeader], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken) => { @@ -399,7 +398,7 @@ class AgentCompletions extends Disposable { } })); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'chatAgentAndSubcommand', triggerCharacters: [chatSubcommandLeader], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken) => { @@ -457,7 +456,7 @@ class AgentCompletions extends Disposable { } })); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'installChatExtensions', triggerCharacters: [chatAgentLeader], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken) => { @@ -842,7 +841,7 @@ class BuiltinDynamicCompletions extends Disposable { } private registerVariableCompletions(debugName: string, provider: (details: IVariableCompletionsDetails, token: CancellationToken) => ProviderResult, wordPattern: RegExp = BuiltinDynamicCompletions.VariableNameDef) { - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: `chatVarCompletions-${debugName}`, triggerCharacters: [chatVariableLeader], provideCompletionItems: async (model: ITextModel, position: Position, context: CompletionContext, token: CancellationToken) => { @@ -1095,7 +1094,7 @@ class ToolCompletions extends Disposable { ) { super(); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'chatVariables', triggerCharacters: [chatVariableLeader], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { diff --git a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts index b1f977c9b33..b229cac0b9c 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts @@ -6,6 +6,7 @@ import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { codiconsLibrary } from '../../../../../../base/common/codiconsLibrary.js'; import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { Schemas } from '../../../../../../base/common/network.js'; import { Position } from '../../../../../../editor/common/core/position.js'; import { Range } from '../../../../../../editor/common/core/range.js'; import { IWordAtPosition } from '../../../../../../editor/common/core/wordHelper.js'; @@ -20,7 +21,6 @@ import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../. import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../../../common/contributions.js'; import { IEditorService } from '../../../../../services/editor/common/editorService.js'; import { IChatWidget, IChatWidgetService, showChatView } from '../../../../chat/browser/chat.js'; -import { ChatInputPart } from '../../../../chat/browser/chatInputPart.js'; import { ChatDynamicVariableModel } from '../../../../chat/browser/contrib/chatDynamicVariables.js'; import { computeCompletionRanges } from '../../../../chat/browser/contrib/chatInputCompletions.js'; import { IChatAgentService } from '../../../../chat/common/chatAgents.js'; @@ -70,7 +70,7 @@ class NotebookChatContribution extends Disposable implements IWorkbenchContribut updateNotebookAgentStatus(); this._register(chatAgentService.onDidChangeAgents(updateNotebookAgentStatus)); - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + this._register(this.languageFeaturesService.completionProvider.register({ scheme: Schemas.vscodeChatInput, hasAccessToAllModels: true }, { _debugDisplayName: 'chatKernelDynamicCompletions', triggerCharacters: [chatVariableLeader], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken) => { From 6b415e1b0bc72d41c569e0491081ac45d2276cd3 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 10 Jun 2025 17:32:33 +0200 Subject: [PATCH 168/236] Add color variable to define the color of sticky scroll within the gutter (#251108) adding variable for defining the color of the editor sticky scroll in the gutter --- build/lib/stylelint/vscode-known-variables.json | 2 ++ .../editor/contrib/peekView/browser/peekView.ts | 1 + .../stickyScroll/browser/stickyScroll.css | 17 ++++++++++------- .../theme/common/colors/editorColors.ts | 4 ++++ 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index c2725753ec2..cb44a1a2199 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -320,6 +320,7 @@ "--vscode-editorPane-background", "--vscode-editorRuler-foreground", "--vscode-editorStickyScroll-background", + "--vscode-editorStickyScrollGutter-background", "--vscode-editorStickyScroll-border", "--vscode-editorStickyScroll-shadow", "--vscode-editorStickyScrollHover-background", @@ -562,6 +563,7 @@ "--vscode-peekViewEditor-matchHighlightBorder", "--vscode-peekViewEditorGutter-background", "--vscode-peekViewEditorStickyScroll-background", + "--vscode-peekViewEditorStickyScrollGutter-background", "--vscode-peekViewResult-background", "--vscode-peekViewResult-fileForeground", "--vscode-peekViewResult-lineForeground", diff --git a/src/vs/editor/contrib/peekView/browser/peekView.ts b/src/vs/editor/contrib/peekView/browser/peekView.ts index ce8921b550f..fe9cffb401e 100644 --- a/src/vs/editor/contrib/peekView/browser/peekView.ts +++ b/src/vs/editor/contrib/peekView/browser/peekView.ts @@ -289,6 +289,7 @@ export const peekViewResultsSelectionForeground = registerColor('peekViewResult. export const peekViewEditorBackground = registerColor('peekViewEditor.background', { dark: '#001F33', light: '#F2F8FC', hcDark: Color.black, hcLight: Color.white }, nls.localize('peekViewEditorBackground', 'Background color of the peek view editor.')); export const peekViewEditorGutterBackground = registerColor('peekViewEditorGutter.background', peekViewEditorBackground, nls.localize('peekViewEditorGutterBackground', 'Background color of the gutter in the peek view editor.')); export const peekViewEditorStickyScrollBackground = registerColor('peekViewEditorStickyScroll.background', peekViewEditorBackground, nls.localize('peekViewEditorStickScrollBackground', 'Background color of sticky scroll in the peek view editor.')); +export const peekViewEditorStickyScrollGutterBackground = registerColor('peekViewEditorStickyScrollGutter.background', peekViewEditorBackground, nls.localize('peekViewEditorStickyScrollGutterBackground', 'Background color of the gutter part of sticky scroll in the peek view editor.')); export const peekViewResultsMatchHighlight = registerColor('peekViewResult.matchHighlightBackground', { dark: '#ea5c004d', light: '#ea5c004d', hcDark: null, hcLight: null }, nls.localize('peekViewResultsMatchHighlight', 'Match highlight color in the peek view result list.')); export const peekViewEditorMatchHighlight = registerColor('peekViewEditor.matchHighlightBackground', { dark: '#ff8f0099', light: '#f5d802de', hcDark: null, hcLight: null }, nls.localize('peekViewEditorMatchHighlight', 'Match highlight color in the peek view editor.')); diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css index 0831d61bdbd..44f4b3377d9 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css @@ -9,17 +9,16 @@ width: 100%; box-shadow: var(--vscode-editorStickyScroll-shadow) 0 4px 2px -2px; z-index: 4; - background-color: var(--vscode-editorStickyScroll-background); right: initial !important; } -.monaco-editor .sticky-widget.peek { - background-color: var(--vscode-peekViewEditorStickyScroll-background); -} - .monaco-editor .sticky-widget .sticky-widget-line-numbers { float: left; - background-color: inherit; + background-color: var(--vscode-editorStickyScrollGutter-background); +} + +.monaco-editor .sticky-widget.peek .sticky-widget-line-numbers { + background-color: var(--vscode-peekViewEditorStickyScrollGutter-background); } .monaco-editor .sticky-widget .sticky-widget-lines-scrollable { @@ -27,7 +26,11 @@ position: absolute; overflow: hidden; width: var(--vscode-editorStickyScroll-scrollableWidth); - background-color: inherit; + background-color: var(--vscode-editorStickyScroll-background); +} + +.monaco-editor .sticky-widget.peek .sticky-widget-lines-scrollable { + background-color: var(--vscode-peekViewEditorStickyScroll-background); } .monaco-editor .sticky-widget .sticky-widget-lines { diff --git a/src/vs/platform/theme/common/colors/editorColors.ts b/src/vs/platform/theme/common/colors/editorColors.ts index 662fc637dc8..b4064b3cb2d 100644 --- a/src/vs/platform/theme/common/colors/editorColors.ts +++ b/src/vs/platform/theme/common/colors/editorColors.ts @@ -29,6 +29,10 @@ export const editorStickyScrollBackground = registerColor('editorStickyScroll.ba editorBackground, nls.localize('editorStickyScrollBackground', "Background color of sticky scroll in the editor")); +export const editorStickyScrollGutterBackground = registerColor('editorStickyScrollGutter.background', + editorBackground, + nls.localize('editorStickyScrollGutterBackground', "Background color of the gutter part of sticky scroll in the editor")); + export const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background', { dark: '#2A2D2E', light: '#F0F0F0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) }, nls.localize('editorStickyScrollHoverBackground', "Background color of sticky scroll on hover in the editor")); From 47fb40495e8c443f3e9e8e075d7d58193127acfa Mon Sep 17 00:00:00 2001 From: Benjamin Christopher Simmonds <44439583+benibenj@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:00:19 +0200 Subject: [PATCH 169/236] Allow menu bar to get more space when there is no window title (#251113) --- .../parts/titlebar/media/titlebarpart.css | 18 ++++++++++--- .../browser/parts/titlebar/titlebarPart.ts | 27 ++++++++++++------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index e1a7a7e2f70..0246cd2ad10 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -71,14 +71,14 @@ align-items: center; } -.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-left { +.monaco-workbench .part.titlebar > .titlebar-container.has-center > .titlebar-left { order: 0; width: 20%; flex-grow: 2; justify-content: flex-start; } -.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center { +.monaco-workbench .part.titlebar > .titlebar-container.has-center > .titlebar-center { order: 1; width: 60%; max-width: fit-content; @@ -88,7 +88,7 @@ justify-content: center; } -.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right { +.monaco-workbench .part.titlebar > .titlebar-container.has-center > .titlebar-right { order: 2; width: 20%; min-width: min-content; @@ -96,7 +96,19 @@ justify-content: flex-end; } +.monaco-workbench .part.titlebar > .titlebar-container:not(.has-center) > .titlebar-left { + flex: 1 1 0%; + min-width: 0; +} +.monaco-workbench .part.titlebar > .titlebar-container:not(.has-center) > .titlebar-center { + display: none; +} + +.monaco-workbench .part.titlebar > .titlebar-container:not(.has-center) > .titlebar-right { + flex: 0 0 auto; + padding-left: 16px; /* ensure there is some space between title and controls */ +} /* Window title text */ .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title { diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 3a2a578e111..94899243d90 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -568,6 +568,8 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { this.updateLayout(this.lastLayoutDimensions); // layout menubar and other renderings in the titlebar } })); + } else { + reset(this.title); } } @@ -849,17 +851,22 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { private updateLayout(dimension: Dimension): void { this.lastLayoutDimensions = dimension; - if (hasCustomTitlebar(this.configurationService, this.titleBarStyle)) { - const zoomFactor = getZoomFactor(getWindow(this.element)); - - this.element.style.setProperty('--zoom-factor', zoomFactor.toString()); - this.rootContainer.classList.toggle('counter-zoom', this.preventZoom); - - if (this.customMenubar.value) { - const menubarDimension = new Dimension(0, dimension.height); - this.customMenubar.value.layout(menubarDimension); - } + if (!hasCustomTitlebar(this.configurationService, this.titleBarStyle)) { + return; } + + const zoomFactor = getZoomFactor(getWindow(this.element)); + + this.element.style.setProperty('--zoom-factor', zoomFactor.toString()); + this.rootContainer.classList.toggle('counter-zoom', this.preventZoom); + + if (this.customMenubar.value) { + const menubarDimension = new Dimension(0, dimension.height); + this.customMenubar.value.layout(menubarDimension); + } + + const hasCenter = this.isCommandCenterVisible || this.title.innerText !== ''; + this.rootContainer.classList.toggle('has-center', hasCenter); } focus(): void { From f5c3e1cf2a8a7a789f4a66d0aa22050d4fb326d9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 10 Jun 2025 11:04:30 -0700 Subject: [PATCH 170/236] Allow unregistering registerSchemaContribution (#233733) This makes `registerSchemaContribution` return a disposable which unregisters the contribution --- .../standalone/browser/standaloneServices.ts | 4 +- .../common/abstractKeybindingService.ts | 4 +- .../platform/keybinding/common/keybinding.ts | 3 +- .../common/abstractKeybindingService.test.ts | 6 +-- .../test/common/mockKeybindingService.ts | 5 ++- .../keybinding/browser/keybindingService.ts | 41 +++++++++++++------ 6 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index f61c5f40b51..8018e740261 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -591,8 +591,8 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { return ''; } - public registerSchemaContribution(contribution: KeybindingsSchemaContribution): void { - // noop + public registerSchemaContribution(contribution: KeybindingsSchemaContribution): IDisposable { + return Disposable.None; } /** diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index ee26e7b40b9..7678f6c893f 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -11,7 +11,7 @@ import { Emitter, Event } from '../../../base/common/event.js'; import { IME } from '../../../base/common/ime.js'; import { KeyCode } from '../../../base/common/keyCodes.js'; import { Keybinding, ResolvedChord, ResolvedKeybinding, SingleModifierChord } from '../../../base/common/keybindings.js'; -import { Disposable } from '../../../base/common/lifecycle.js'; +import { Disposable, IDisposable } from '../../../base/common/lifecycle.js'; import * as nls from '../../../nls.js'; import { ICommandService } from '../../commands/common/commands.js'; @@ -89,7 +89,7 @@ export abstract class AbstractKeybindingService extends Disposable implements IK public abstract resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[]; public abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding; public abstract resolveUserBinding(userBinding: string): ResolvedKeybinding[]; - public abstract registerSchemaContribution(contribution: KeybindingsSchemaContribution): void; + public abstract registerSchemaContribution(contribution: KeybindingsSchemaContribution): IDisposable; public abstract _dumpDebugInfo(): string; public abstract _dumpDebugInfoJSON(): string; diff --git a/src/vs/platform/keybinding/common/keybinding.ts b/src/vs/platform/keybinding/common/keybinding.ts index 5dadf9b8e10..72f0d6c9640 100644 --- a/src/vs/platform/keybinding/common/keybinding.ts +++ b/src/vs/platform/keybinding/common/keybinding.ts @@ -7,6 +7,7 @@ import { Event } from '../../../base/common/event.js'; import { IJSONSchema } from '../../../base/common/jsonSchema.js'; import { KeyCode } from '../../../base/common/keyCodes.js'; import { ResolvedKeybinding, Keybinding } from '../../../base/common/keybindings.js'; +import { IDisposable } from '../../../base/common/lifecycle.js'; import { IContextKeyService, IContextKeyServiceTarget } from '../../contextkey/common/contextkey.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; import { ResolutionResult } from './keybindingResolver.js'; @@ -101,7 +102,7 @@ export interface IKeybindingService { */ mightProducePrintableCharacter(event: IKeyboardEvent): boolean; - registerSchemaContribution(contribution: KeybindingsSchemaContribution): void; + registerSchemaContribution(contribution: KeybindingsSchemaContribution): IDisposable; toggleLogging(): boolean; diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index 075a5f5494c..b8ac90774ed 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -5,7 +5,7 @@ import assert from 'assert'; import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import { createSimpleKeybinding, ResolvedKeybinding, KeyCodeChord, Keybinding } from '../../../../base/common/keybindings.js'; -import { Disposable } from '../../../../base/common/lifecycle.js'; +import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js'; import { OS } from '../../../../base/common/platform.js'; import Severity from '../../../../base/common/severity.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; @@ -93,8 +93,8 @@ suite('AbstractKeybindingService', () => { return ''; } - public registerSchemaContribution() { - // noop + public registerSchemaContribution(): IDisposable { + return Disposable.None; } public enableKeybindingHoldMode() { diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index 477ccb95290..b6263c56417 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from '../../../../base/common/event.js'; -import { ResolvedKeybinding, KeyCodeChord, Keybinding } from '../../../../base/common/keybindings.js'; +import { KeyCodeChord, Keybinding, ResolvedKeybinding } from '../../../../base/common/keybindings.js'; +import { Disposable } from '../../../../base/common/lifecycle.js'; import { OS } from '../../../../base/common/platform.js'; import { ContextKeyExpression, ContextKeyValue, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IScopedContextKeyService } from '../../../contextkey/common/contextkey.js'; import { IKeybindingService, IKeyboardEvent } from '../../common/keybinding.js'; @@ -168,6 +169,6 @@ export class MockKeybindingService implements IKeybindingService { } public registerSchemaContribution() { - // noop + return Disposable.None; } } diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index bb41a6d5705..c5a78e509f1 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -10,6 +10,7 @@ import * as browser from '../../../../base/browser/browser.js'; import { BrowserFeatures, KeyboardSupport } from '../../../../base/browser/canIUse.js'; import * as dom from '../../../../base/browser/dom.js'; import { printKeyboardEvent, printStandardKeyboardEvent, StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js'; +import { mainWindow } from '../../../../base/browser/window.js'; import { DeferredPromise, RunOnceScheduler } from '../../../../base/common/async.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { parse } from '../../../../base/common/json.js'; @@ -18,13 +19,13 @@ import { UserSettingsLabelProvider } from '../../../../base/common/keybindingLab import { KeybindingParser } from '../../../../base/common/keybindingParser.js'; import { Keybinding, KeyCodeChord, ResolvedKeybinding, ScanCodeChord } from '../../../../base/common/keybindings.js'; import { IMMUTABLE_CODE_TO_KEY_CODE, KeyCode, KeyCodeUtils, KeyMod, ScanCode, ScanCodeUtils } from '../../../../base/common/keyCodes.js'; -import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; import * as objects from '../../../../base/common/objects.js'; import { isMacintosh, OperatingSystem, OS } from '../../../../base/common/platform.js'; import { dirname } from '../../../../base/common/resources.js'; -import { mainWindow } from '../../../../base/browser/window.js'; // platform +import { ILocalizedString, isLocalizedString } from '../../../../platform/action/common/action.js'; import { MenuRegistry } from '../../../../platform/actions/common/actions.js'; import { CommandsRegistry, ICommandService } from '../../../../platform/commands/common/commands.js'; import { ContextKeyExpr, ContextKeyExpression, IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; @@ -44,17 +45,17 @@ import { INotificationService } from '../../../../platform/notification/common/n import { Registry } from '../../../../platform/registry/common/platform.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js'; -import { ILocalizedString, isLocalizedString } from '../../../../platform/action/common/action.js'; // workbench +import { remove } from '../../../../base/common/arrays.js'; import { commandsExtensionPoint } from '../../actions/common/menusExtensionPoint.js'; import { IExtensionService } from '../../extensions/common/extensions.js'; import { ExtensionMessageCollector, ExtensionsRegistry } from '../../extensions/common/extensionsRegistry.js'; import { IHostService } from '../../host/browser/host.js'; +import { IUserDataProfileService } from '../../userDataProfile/common/userDataProfile.js'; +import { IUserKeybindingItem, KeybindingIO, OutputBuilder } from '../common/keybindingIO.js'; import { IKeyboard, INavigatorWithKeyboard } from './navigatorKeyboard.js'; import { getAllUnboundCommands } from './unboundCommands.js'; -import { IUserKeybindingItem, KeybindingIO, OutputBuilder } from '../common/keybindingIO.js'; -import { IUserDataProfileService } from '../../userDataProfile/common/userDataProfile.js'; interface ContributedKeyBinding { command: string; @@ -184,7 +185,10 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { private userKeybindings: UserKeybindings; private isComposingGlobalContextKey: IContextKey; private _keybindingHoldMode: DeferredPromise | null; - private readonly _contributions: KeybindingsSchemaContribution[] = []; + private readonly _contributions: Array<{ + readonly listener?: IDisposable; + readonly contribution: KeybindingsSchemaContribution; + }> = []; private readonly kbsJsonSchema: KeybindingsJsonSchema; constructor( @@ -266,6 +270,13 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { })); } + public override dispose(): void { + this._contributions.forEach(c => c.listener?.dispose()); + this._contributions.length = 0; + + super.dispose(); + } + private _registerKeyListeners(window: Window): IDisposable { const disposables = new DisposableStore(); @@ -300,16 +311,22 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { return disposables; } - public registerSchemaContribution(contribution: KeybindingsSchemaContribution): void { - this._contributions.push(contribution); - if (contribution.onDidChange) { - this._register(contribution.onDidChange(() => this.updateKeybindingsJsonSchema())); - } + public registerSchemaContribution(contribution: KeybindingsSchemaContribution): IDisposable { + const listener = contribution.onDidChange?.(() => this.updateKeybindingsJsonSchema()); + const entry = { listener, contribution }; + this._contributions.push(entry); + this.updateKeybindingsJsonSchema(); + + return toDisposable(() => { + listener?.dispose(); + remove(this._contributions, entry); + this.updateKeybindingsJsonSchema(); + }); } private updateKeybindingsJsonSchema() { - this.kbsJsonSchema.updateSchema(this._contributions.flatMap(x => x.getSchemaAdditions())); + this.kbsJsonSchema.updateSchema(this._contributions.flatMap(x => x.contribution.getSchemaAdditions())); } private _printKeybinding(keybinding: Keybinding): string { From fd5d3994017687ce3ac0b5f66d90d9abad2c79a8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 10 Jun 2025 11:05:29 -0700 Subject: [PATCH 171/236] Remove cycling dep in editor gpu code --- src/vs/editor/browser/gpu/atlas/textureAtlas.ts | 4 +++- src/vs/editor/browser/gpu/raster/glyphRasterizer.ts | 7 ++++--- src/vs/editor/browser/gpu/viewGpuContext.ts | 5 ++--- .../browser/viewParts/viewLinesGpu/viewLinesGpu.ts | 4 ++-- src/vs/editor/contrib/gpu/browser/gpuActions.ts | 2 +- .../editor/test/browser/gpu/atlas/textureAtlas.test.ts | 9 +++++---- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/browser/gpu/atlas/textureAtlas.ts b/src/vs/editor/browser/gpu/atlas/textureAtlas.ts index a4e5865c011..252a44596ef 100644 --- a/src/vs/editor/browser/gpu/atlas/textureAtlas.ts +++ b/src/vs/editor/browser/gpu/atlas/textureAtlas.ts @@ -12,6 +12,7 @@ import { NKeyMap } from '../../../../base/common/map.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { IThemeService } from '../../../../platform/theme/common/themeService.js'; import { MetadataConsts } from '../../../common/encodedTokenAttributes.js'; +import type { DecorationStyleCache } from '../css/decorationStyleCache.js'; import { GlyphRasterizer } from '../raster/glyphRasterizer.js'; import type { IGlyphRasterizer } from '../raster/raster.js'; import { IdleTaskQueue, type ITaskQueue } from '../taskQueue.js'; @@ -59,6 +60,7 @@ export class TextureAtlas extends Disposable { /** The maximum texture size supported by the GPU. */ private readonly _maxTextureSize: number, options: ITextureAtlasOptions | undefined, + private readonly _decorationStyleCache: DecorationStyleCache, @IThemeService private readonly _themeService: IThemeService, @IInstantiationService private readonly _instantiationService: IInstantiationService ) { @@ -88,7 +90,7 @@ export class TextureAtlas extends Disposable { // IMPORTANT: The first glyph on the first page must be an empty glyph such that zeroed out // cells end up rendering nothing // TODO: This currently means the first slab is for 0x0 glyphs and is wasted - const nullRasterizer = new GlyphRasterizer(1, '', 1); + const nullRasterizer = new GlyphRasterizer(1, '', 1, this._decorationStyleCache); firstPage.getGlyph(nullRasterizer, '', 0, 0); nullRasterizer.dispose(); } diff --git a/src/vs/editor/browser/gpu/raster/glyphRasterizer.ts b/src/vs/editor/browser/gpu/raster/glyphRasterizer.ts index d06871cc24d..cc41c8dcaa4 100644 --- a/src/vs/editor/browser/gpu/raster/glyphRasterizer.ts +++ b/src/vs/editor/browser/gpu/raster/glyphRasterizer.ts @@ -8,8 +8,8 @@ import { Disposable } from '../../../../base/common/lifecycle.js'; import { isMacintosh } from '../../../../base/common/platform.js'; import { StringBuilder } from '../../../common/core/stringBuilder.js'; import { FontStyle, TokenMetadata } from '../../../common/encodedTokenAttributes.js'; +import type { DecorationStyleCache } from '../css/decorationStyleCache.js'; import { ensureNonNullable } from '../gpuUtils.js'; -import { ViewGpuContext } from '../viewGpuContext.js'; import { type IBoundingBox, type IGlyphRasterizer, type IRasterizedGlyph } from './raster.js'; let nextId = 0; @@ -50,7 +50,8 @@ export class GlyphRasterizer extends Disposable implements IGlyphRasterizer { constructor( readonly fontSize: number, readonly fontFamily: string, - readonly devicePixelRatio: number + readonly devicePixelRatio: number, + private readonly _decorationStyleCache: DecorationStyleCache, ) { super(); @@ -119,7 +120,7 @@ export class GlyphRasterizer extends Disposable implements IGlyphRasterizer { const bgId = TokenMetadata.getBackground(tokenMetadata); const bg = colorMap[bgId]; - const decorationStyleSet = ViewGpuContext.decorationStyleCache.getStyleSet(decorationStyleSetId); + const decorationStyleSet = this._decorationStyleCache.getStyleSet(decorationStyleSetId); // When SPAA is used, the background color must be present to get the right glyph if (this._antiAliasing === 'subpixel') { diff --git a/src/vs/editor/browser/gpu/viewGpuContext.ts b/src/vs/editor/browser/gpu/viewGpuContext.ts index 181c468f12c..953e7c23f7a 100644 --- a/src/vs/editor/browser/gpu/viewGpuContext.ts +++ b/src/vs/editor/browser/gpu/viewGpuContext.ts @@ -24,13 +24,12 @@ import { Event } from '../../../base/common/event.js'; import { EditorOption, type IEditorOptions } from '../../common/config/editorOptions.js'; import { InlineDecorationType } from '../../common/viewModel.js'; import { DecorationStyleCache } from './css/decorationStyleCache.js'; -import { ViewportRenderStrategy } from './renderStrategy/viewportRenderStrategy.js'; export class ViewGpuContext extends Disposable { /** * The hard cap for line columns rendered by the GPU renderer. */ - readonly maxGpuCols = ViewportRenderStrategy.maxSupportedColumns; + readonly maxGpuCols = 2000; readonly canvas: FastDomNode; readonly ctx: GPUCanvasContext; @@ -111,7 +110,7 @@ export class ViewGpuContext extends Disposable { }).then(ref => { ViewGpuContext.deviceSync = ref.object; if (!ViewGpuContext._atlas) { - ViewGpuContext._atlas = this._instantiationService.createInstance(TextureAtlas, ref.object.limits.maxTextureDimension2D, undefined); + ViewGpuContext._atlas = this._instantiationService.createInstance(TextureAtlas, ref.object.limits.maxTextureDimension2D, undefined, ViewGpuContext.decorationStyleCache); } return ref.object; }); diff --git a/src/vs/editor/browser/viewParts/viewLinesGpu/viewLinesGpu.ts b/src/vs/editor/browser/viewParts/viewLinesGpu/viewLinesGpu.ts index dd0666b3e3b..dca6206ec1f 100644 --- a/src/vs/editor/browser/viewParts/viewLinesGpu/viewLinesGpu.ts +++ b/src/vs/editor/browser/viewParts/viewLinesGpu/viewLinesGpu.ts @@ -196,7 +196,7 @@ export class ViewLinesGpu extends ViewPart implements IViewLines { const fontFamily = this._context.configuration.options.get(EditorOption.fontFamily); const fontSize = this._context.configuration.options.get(EditorOption.fontSize); - this._glyphRasterizer.value = this._register(new GlyphRasterizer(fontSize, fontFamily, this._viewGpuContext.devicePixelRatio.get())); + this._glyphRasterizer.value = this._register(new GlyphRasterizer(fontSize, fontFamily, this._viewGpuContext.devicePixelRatio.get(), ViewGpuContext.decorationStyleCache)); this._register(runOnChange(this._viewGpuContext.devicePixelRatio, () => { this._refreshGlyphRasterizer(); })); @@ -454,7 +454,7 @@ export class ViewLinesGpu extends ViewPart implements IViewLines { glyphRasterizer.fontSize !== fontSize || glyphRasterizer.devicePixelRatio !== devicePixelRatio ) { - this._glyphRasterizer.value = new GlyphRasterizer(fontSize, fontFamily, devicePixelRatio); + this._glyphRasterizer.value = new GlyphRasterizer(fontSize, fontFamily, devicePixelRatio, ViewGpuContext.decorationStyleCache); } } diff --git a/src/vs/editor/contrib/gpu/browser/gpuActions.ts b/src/vs/editor/contrib/gpu/browser/gpuActions.ts index a1a3afe9a5b..a323d67b1fc 100644 --- a/src/vs/editor/contrib/gpu/browser/gpuActions.ts +++ b/src/vs/editor/contrib/gpu/browser/gpuActions.ts @@ -105,7 +105,7 @@ class DebugEditorGpuRendererAction extends EditorAction { const atlas = ViewGpuContext.atlas; const fontFamily = configurationService.getValue('editor.fontFamily'); const fontSize = configurationService.getValue('editor.fontSize'); - const rasterizer = new GlyphRasterizer(fontSize, fontFamily, getActiveWindow().devicePixelRatio); + const rasterizer = new GlyphRasterizer(fontSize, fontFamily, getActiveWindow().devicePixelRatio, ViewGpuContext.decorationStyleCache); let chars = await quickInputService.input({ prompt: 'Enter a character to draw (prefix with 0x for code point))' }); diff --git a/src/vs/editor/test/browser/gpu/atlas/textureAtlas.test.ts b/src/vs/editor/test/browser/gpu/atlas/textureAtlas.test.ts index 2b0e55aab2c..41682b417f1 100644 --- a/src/vs/editor/test/browser/gpu/atlas/textureAtlas.test.ts +++ b/src/vs/editor/test/browser/gpu/atlas/textureAtlas.test.ts @@ -12,6 +12,7 @@ import { TextureAtlas } from '../../../../browser/gpu/atlas/textureAtlas.js'; import { createCodeEditorServices } from '../../testCodeEditor.js'; import { assertIsValidGlyph } from './testUtil.js'; import { TextureAtlasSlabAllocator } from '../../../../browser/gpu/atlas/textureAtlasSlabAllocator.js'; +import { DecorationStyleCache } from '../../../../browser/gpu/css/decorationStyleCache.js'; const blackInt = 0x000000FF; const nullCharMetadata = 0x0; @@ -79,7 +80,7 @@ suite('TextureAtlas', () => { setup(() => { instantiationService = createCodeEditorServices(store); - atlas = store.add(instantiationService.createInstance(TextureAtlas, 2, undefined)); + atlas = store.add(instantiationService.createInstance(TextureAtlas, 2, undefined, new DecorationStyleCache())); glyphRasterizer = new TestGlyphRasterizer(); glyphRasterizer.nextGlyphDimensions = [1, 1]; glyphRasterizer.nextGlyphColor = [0, 0, 0, 0xFF]; @@ -90,7 +91,7 @@ suite('TextureAtlas', () => { }); test('get multiple glyphs', () => { - atlas = store.add(instantiationService.createInstance(TextureAtlas, 32, undefined)); + atlas = store.add(instantiationService.createInstance(TextureAtlas, 32, undefined, new DecorationStyleCache())); for (let i = 0; i < 10; i++) { assertIsValidGlyph(atlas.getGlyph(glyphRasterizer, ...getUniqueGlyphId()), atlas); } @@ -119,14 +120,14 @@ suite('TextureAtlas', () => { glyphRasterizer.nextGlyphDimensions = [2, 2]; atlas = store.add(instantiationService.createInstance(TextureAtlas, 32, { allocatorType: (canvas, textureIndex) => new TextureAtlasSlabAllocator(canvas, textureIndex, { slabW: 1, slabH: 1 }) - })); + }, new DecorationStyleCache())); assertIsValidGlyph(atlas.getGlyph(glyphRasterizer, ...getUniqueGlyphId()), atlas); }); test('adding a non-first glyph larger than the standard slab size, causing an overflow to a new page', () => { atlas = store.add(instantiationService.createInstance(TextureAtlas, 2, { allocatorType: (canvas, textureIndex) => new TextureAtlasSlabAllocator(canvas, textureIndex, { slabW: 1, slabH: 1 }) - })); + }, new DecorationStyleCache())); assertIsValidGlyph(atlas.getGlyph(glyphRasterizer, ...getUniqueGlyphId()), atlas); strictEqual(atlas.pages.length, 1); glyphRasterizer.nextGlyphDimensions = [2, 2]; From efce3c699ed0a904315c7df732ba2dc58901ddbb Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Jun 2025 11:07:42 -0700 Subject: [PATCH 172/236] cycle --- .../contrib/mcp/browser/mcpCommands.ts | 20 +++----------- .../mcp/browser/mcpResourceQuickAccess.ts | 2 +- .../mcp/browser/openPanelChatAndGetWidget.ts | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 src/vs/workbench/contrib/mcp/browser/openPanelChatAndGetWidget.ts diff --git a/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts b/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts index 9598b0307e3..01a3ca06f6d 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts @@ -5,7 +5,6 @@ import { h } from '../../../../base/browser/dom.js'; import { assertNever } from '../../../../base/common/assert.js'; -import { raceTimeout } from '../../../../base/common/async.js'; import { Codicon } from '../../../../base/common/codicons.js'; import { groupBy } from '../../../../base/common/collections.js'; import { Event } from '../../../../base/common/event.js'; @@ -34,9 +33,9 @@ import { ActiveEditorContext, ResourceContextKey } from '../../../common/context import { IWorkbenchContribution } from '../../../common/contributions.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; -import { ChatViewId, IChatWidget, IChatWidgetService } from '../../chat/browser/chat.js'; +import { IChatWidgetService } from '../../chat/browser/chat.js'; import { ChatContextKeys } from '../../chat/common/chatContextKeys.js'; -import { ChatAgentLocation, ChatMode } from '../../chat/common/constants.js'; +import { ChatMode } from '../../chat/common/constants.js'; import { ILanguageModelsService } from '../../chat/common/languageModels.js'; import { extensionsFilterSubMenu, IExtensionsWorkbenchService } from '../../extensions/common/extensions.js'; import { TEXT_FILE_EDITOR_ID } from '../../files/common/files.js'; @@ -47,6 +46,7 @@ import { IMcpSamplingService, IMcpServer, IMcpServerStartOpts, IMcpService, IMcp import { McpAddConfigurationCommand } from './mcpCommandsAddConfiguration.js'; import { McpResourceQuickAccess, McpResourceQuickPick } from './mcpResourceQuickAccess.js'; import { McpUrlHandler } from './mcpUrlHandler.js'; +import { openPanelChatAndGetWidget } from './openPanelChatAndGetWidget.js'; // acroynms do not get localized const category: ILocalizedString = { @@ -745,18 +745,4 @@ export class McpStartPromptingServerCommand extends Action2 { } } -export async function openPanelChatAndGetWidget(viewsService: IViewsService, chatService: IChatWidgetService): Promise { - await viewsService.openView(ChatViewId, true); - const widgets = chatService.getWidgetsByLocations(ChatAgentLocation.Panel); - if (widgets.length) { - return widgets[0]; - } - const eventPromise = Event.toPromise(Event.filter(chatService.onDidAddWidget, e => e.location === ChatAgentLocation.Panel)); - - return await raceTimeout( - eventPromise, - 10_000, // should be enough time for chat to initialize... - () => eventPromise.cancel(), - ); -} diff --git a/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts b/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts index 55bb13b8526..84f38319c57 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.ts @@ -26,7 +26,7 @@ import { resolveImageEditorAttachContext } from '../../chat/browser/chatAttachme import { IChatRequestVariableEntry } from '../../chat/common/chatVariableEntries.js'; import { IMcpResource, IMcpResourceTemplate, IMcpServer, IMcpService, isMcpResourceTemplate, McpCapability, McpConnectionState, McpResourceURI } from '../common/mcpTypes.js'; import { IUriTemplateVariable } from '../common/uriTemplate.js'; -import { openPanelChatAndGetWidget } from './mcpCommands.js'; +import { openPanelChatAndGetWidget } from './openPanelChatAndGetWidget.js'; export class McpResourcePickHelper { public static sep(server: IMcpServer): IQuickPickSeparator { diff --git a/src/vs/workbench/contrib/mcp/browser/openPanelChatAndGetWidget.ts b/src/vs/workbench/contrib/mcp/browser/openPanelChatAndGetWidget.ts new file mode 100644 index 00000000000..96b7562386e --- /dev/null +++ b/src/vs/workbench/contrib/mcp/browser/openPanelChatAndGetWidget.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { raceTimeout } from '../../../../base/common/async.js'; +import { Event } from '../../../../base/common/event.js'; +import { IViewsService } from '../../../services/views/common/viewsService.js'; +import { IChatWidgetService, IChatWidget, ChatViewId } from '../../chat/browser/chat.js'; +import { ChatAgentLocation } from '../../chat/common/constants.js'; + + +export async function openPanelChatAndGetWidget(viewsService: IViewsService, chatService: IChatWidgetService): Promise { + await viewsService.openView(ChatViewId, true); + const widgets = chatService.getWidgetsByLocations(ChatAgentLocation.Panel); + if (widgets.length) { + return widgets[0]; + } + + const eventPromise = Event.toPromise(Event.filter(chatService.onDidAddWidget, e => e.location === ChatAgentLocation.Panel)); + + return await raceTimeout( + eventPromise, + 10000, // should be enough time for chat to initialize... + () => eventPromise.cancel() + ); +} From 23f0f365ffe7a0b0771587b06eae1fcc18cf10ac Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 10 Jun 2025 12:17:47 -0700 Subject: [PATCH 173/236] support resource completions for `Git Bash` (#251120) --- .../api/common/extHostTerminalService.ts | 6 +- .../api/common/extHostTypeConverters.ts | 9 +-- .../browser/terminalCompletionService.ts | 34 +++++---- .../suggest/browser/terminalGitBashHelpers.ts | 42 +++++++++++ .../browser/terminalCompletionService.test.ts | 75 ++++++++++++++++++- 5 files changed, 142 insertions(+), 24 deletions(-) create mode 100644 src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index ab06ab814df..7f218f1e162 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -18,7 +18,7 @@ import { serializeEnvironmentDescriptionMap, serializeEnvironmentVariableCollect import { CancellationTokenSource } from '../../../base/common/cancellation.js'; import { generateUuid } from '../../../base/common/uuid.js'; import { IEnvironmentVariableCollectionDescription, IEnvironmentVariableMutator, ISerializableEnvironmentVariableCollection } from '../../../platform/terminal/common/environmentVariable.js'; -import { ICreateContributedTerminalProfileOptions, IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalLocation, IProcessProperty, ProcessPropertyType, IProcessPropertyMap, TerminalShellType } from '../../../platform/terminal/common/terminal.js'; +import { ICreateContributedTerminalProfileOptions, IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalLocation, IProcessProperty, ProcessPropertyType, IProcessPropertyMap, TerminalShellType, WindowsShellType } from '../../../platform/terminal/common/terminal.js'; import { TerminalDataBufferer } from '../../../platform/terminal/common/terminalDataBuffering.js'; import { ThemeColor } from '../../../base/common/themables.js'; import { Promises } from '../../../base/common/async.js'; @@ -27,6 +27,7 @@ import { TerminalCompletionList, TerminalQuickFix, ViewColumn } from './extHostT import { IExtHostCommands } from './extHostCommands.js'; import { MarshalledId } from '../../../base/common/marshallingIds.js'; import { ISerializedTerminalInstanceContext } from '../../contrib/terminal/common/terminal.js'; +import { isWindows } from '../../../base/common/platform.js'; export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable { @@ -781,7 +782,8 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I if (completions === null || completions === undefined) { return undefined; } - return TerminalCompletionList.from(completions); + const pathSeparator = !isWindows || this.activeTerminal.state?.shell === WindowsShellType.GitBash ? '/' : '\\'; + return TerminalCompletionList.from(completions, pathSeparator); } public $acceptTerminalShellType(id: number, shellType: TerminalShellType | undefined): void { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index be99e78a443..97768fd239b 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -16,7 +16,6 @@ import { parse, revive } from '../../../base/common/marshalling.js'; import { MarshalledId } from '../../../base/common/marshallingIds.js'; import { Mimes } from '../../../base/common/mime.js'; import { cloneAndChange } from '../../../base/common/objects.js'; -import { isWindows } from '../../../base/common/platform.js'; import { IPrefixTreeNode, WellDefinedPrefixTree } from '../../../base/common/prefixTree.js'; import { basename } from '../../../base/common/resources.js'; import { ThemeIcon } from '../../../base/common/themables.js'; @@ -3188,7 +3187,7 @@ export namespace TerminalCompletionItemDto { } export namespace TerminalCompletionList { - export function from(completions: vscode.TerminalCompletionList | vscode.TerminalCompletionItem[]): extHostProtocol.TerminalCompletionListDto { + export function from(completions: vscode.TerminalCompletionList | vscode.TerminalCompletionItem[], pathSeparator: string): extHostProtocol.TerminalCompletionListDto { if (Array.isArray(completions)) { return { items: completions.map(i => TerminalCompletionItemDto.from(i)), @@ -3196,16 +3195,16 @@ export namespace TerminalCompletionList { } return { items: completions.items.map(i => TerminalCompletionItemDto.from(i)), - resourceRequestConfig: completions.resourceRequestConfig ? TerminalResourceRequestConfig.from(completions.resourceRequestConfig) : undefined, + resourceRequestConfig: completions.resourceRequestConfig ? TerminalResourceRequestConfig.from(completions.resourceRequestConfig, pathSeparator) : undefined, }; } } export namespace TerminalResourceRequestConfig { - export function from(resourceRequestConfig: vscode.TerminalResourceRequestConfig): extHostProtocol.TerminalResourceRequestConfigDto { + export function from(resourceRequestConfig: vscode.TerminalResourceRequestConfig, pathSeparator: string): extHostProtocol.TerminalResourceRequestConfigDto { return { ...resourceRequestConfig, - pathSeparator: isWindows ? '\\' : '/', + pathSeparator, cwd: resourceRequestConfig.cwd ? URI.revive(resourceRequestConfig.cwd) : undefined, }; } diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts index b54bcd1af4d..6c580e5ebc3 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts @@ -11,12 +11,13 @@ import { IConfigurationService } from '../../../../../platform/configuration/com import { IFileService } from '../../../../../platform/files/common/files.js'; import { createDecorator } from '../../../../../platform/instantiation/common/instantiation.js'; import { TerminalCapability, type ITerminalCapabilityStore } from '../../../../../platform/terminal/common/capabilities/capabilities.js'; -import { GeneralShellType, TerminalShellType } from '../../../../../platform/terminal/common/terminal.js'; +import { GeneralShellType, TerminalShellType, WindowsShellType } from '../../../../../platform/terminal/common/terminal.js'; import { TerminalSuggestSettingId } from '../common/terminalSuggestConfiguration.js'; import { TerminalCompletionItemKind, type ITerminalCompletion } from './terminalCompletionItem.js'; import { env as processEnv } from '../../../../../base/common/process.js'; import type { IProcessEnvironment } from '../../../../../base/common/platform.js'; import { timeout } from '../../../../../base/common/async.js'; +import { gitBashPathToWindows } from './terminalGitBashHelpers.js'; export const ITerminalCompletionService = createDecorator('terminalCompletionService'); @@ -190,7 +191,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo return completionItems; } if (completions.resourceRequestConfig) { - const resourceCompletions = await this.resolveResources(completions.resourceRequestConfig, promptValue, cursorPosition, provider.id, capabilities); + const resourceCompletions = await this.resolveResources(completions.resourceRequestConfig, promptValue, cursorPosition, provider.id, capabilities, shellType); if (resourceCompletions) { completionItems.push(...resourceCompletions); } @@ -202,7 +203,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo return results.filter(result => !!result).flat(); } - async resolveResources(resourceRequestConfig: TerminalResourceRequestConfig, promptValue: string, cursorPosition: number, provider: string, capabilities: ITerminalCapabilityStore): Promise { + async resolveResources(resourceRequestConfig: TerminalResourceRequestConfig, promptValue: string, cursorPosition: number, provider: string, capabilities: ITerminalCapabilityStore, shellType?: TerminalShellType): Promise { const useWindowsStylePath = resourceRequestConfig.pathSeparator === '\\'; if (useWindowsStylePath) { // for tests, make sure the right path separator is used @@ -280,7 +281,11 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo break; } case 'absolute': { - lastWordFolderResource = URI.file(lastWordFolder.replaceAll('\\ ', ' ')); + if (shellType === WindowsShellType.GitBash) { + lastWordFolderResource = URI.file(gitBashPathToWindows(lastWordFolder, this._processEnv.SystemDrive)); + } else { + lastWordFolderResource = URI.file(lastWordFolder.replaceAll('\\ ', ' ')); + } break; } case 'relative': { @@ -349,7 +354,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo label, provider, kind: TerminalCompletionItemKind.Folder, - detail: getFriendlyPath(lastWordFolderResource, resourceRequestConfig.pathSeparator, TerminalCompletionItemKind.Folder), + detail: getFriendlyPath(lastWordFolderResource, resourceRequestConfig.pathSeparator, TerminalCompletionItemKind.Folder, shellType), replacementIndex: cursorPosition - lastWord.length, replacementLength: lastWord.length }); @@ -394,7 +399,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo label, provider, kind, - detail: getFriendlyPath(child.resource, resourceRequestConfig.pathSeparator, kind), + detail: getFriendlyPath(child.resource, resourceRequestConfig.pathSeparator, kind, shellType), replacementIndex: cursorPosition - lastWord.length, replacementLength: lastWord.length }); @@ -420,8 +425,8 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo } const useRelative = config === 'relative'; const kind = TerminalCompletionItemKind.Folder; - const label = useRelative ? basename(child.resource.fsPath) : getFriendlyPath(child.resource, resourceRequestConfig.pathSeparator, kind); - const detail = useRelative ? `CDPATH ${getFriendlyPath(child.resource, resourceRequestConfig.pathSeparator, kind)}` : `CDPATH`; + const label = useRelative ? basename(child.resource.fsPath) : getFriendlyPath(child.resource, resourceRequestConfig.pathSeparator, kind, shellType); + const detail = useRelative ? `CDPATH ${getFriendlyPath(child.resource, resourceRequestConfig.pathSeparator, kind, shellType)}` : `CDPATH`; resourceCompletions.push({ label, provider, @@ -453,7 +458,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo label, provider, kind: TerminalCompletionItemKind.Folder, - detail: getFriendlyPath(parentDir, resourceRequestConfig.pathSeparator, TerminalCompletionItemKind.Folder), + detail: getFriendlyPath(parentDir, resourceRequestConfig.pathSeparator, TerminalCompletionItemKind.Folder, shellType), replacementIndex: cursorPosition - lastWord.length, replacementLength: lastWord.length }); @@ -478,7 +483,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo label: '~', provider, kind: TerminalCompletionItemKind.Folder, - detail: typeof homeResource === 'string' ? homeResource : getFriendlyPath(homeResource, resourceRequestConfig.pathSeparator, TerminalCompletionItemKind.Folder), + detail: typeof homeResource === 'string' ? homeResource : getFriendlyPath(homeResource, resourceRequestConfig.pathSeparator, TerminalCompletionItemKind.Folder, shellType), replacementIndex: cursorPosition - lastWord.length, replacementLength: lastWord.length }); @@ -500,14 +505,15 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo } } -function getFriendlyPath(uri: URI, pathSeparator: string, kind: TerminalCompletionItemKind): string { +function getFriendlyPath(uri: URI, pathSeparator: string, kind: TerminalCompletionItemKind, shellType?: TerminalShellType): string { let path = uri.fsPath; + const sep = shellType === WindowsShellType.GitBash ? '\\' : pathSeparator; // Ensure folders end with the path separator to differentiate presentation from files - if (kind === TerminalCompletionItemKind.Folder && !path.endsWith(pathSeparator)) { - path += pathSeparator; + if (kind === TerminalCompletionItemKind.Folder && !path.endsWith(sep)) { + path += sep; } // Ensure drive is capitalized on Windows - if (pathSeparator === '\\' && path.match(/^[a-zA-Z]:\\/)) { + if (sep === '\\' && path.match(/^[a-zA-Z]:\\/)) { path = `${path[0].toUpperCase()}:${path.slice(2)}`; } return path; diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts new file mode 100644 index 00000000000..fb7c6b6fab7 --- /dev/null +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Converts a Git Bash absolute path to a Windows absolute path. + * Examples: + * "/" => "C:\\" + * "/c/" => "C:\\" + * "/c/Users/foo" => "C:\\Users\\foo" + * "/d/bar" => "D:\\bar" + */ +export function gitBashPathToWindows(path: string, driveLetter?: string): string { + // Dynamically determine the system drive (default to 'C:' if not set) + const systemDrive = (driveLetter || 'C:').toUpperCase(); + // Handle root "/" + if (path === '/') { + return `${systemDrive}\\`; + } + const match = path.match(/^\/([a-zA-Z])(\/.*)?$/); + if (match) { + const drive = match[1].toUpperCase(); + const rest = match[2] ? match[2].replace(/\//g, '\\') : '\\'; + return `${drive}:${rest}`; + } + // Fallback: just replace slashes + return path.replace(/\//g, '\\'); +} + +/** + * + * @param path A Windows-style absolute path (e.g., "C:\Users\foo"). + * Converts it to a Git Bash-style absolute path (e.g., "/c/Users/foo"). + * @returns The Git Bash-style absolute path. + */ +export function windowsToGitBashPath(path: string): string { + // Convert Windows path (e.g. C:\Users\foo) to Git Bash path (e.g. /c/Users/foo) + return path + .replace(/^[a-zA-Z]:\\/, match => `/${match[0].toLowerCase()}/`) + .replace(/\\/g, '/'); +} diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts index 9a046f452a3..6b458c5de6e 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts @@ -18,6 +18,8 @@ import { ShellEnvDetectionCapability } from '../../../../../../platform/terminal import { TerminalCapability } from '../../../../../../platform/terminal/common/capabilities/capabilities.js'; import { ITerminalCompletion, TerminalCompletionItemKind } from '../../browser/terminalCompletionItem.js'; import { count } from '../../../../../../base/common/strings.js'; +import { WindowsShellType } from '../../../../../../platform/terminal/common/terminal.js'; +import { gitBashPathToWindows, windowsToGitBashPath } from '../../browser/terminalGitBashHelpers.js'; const pathSeparator = isWindows ? '\\' : '/'; @@ -35,7 +37,8 @@ interface IAssertionCommandLineConfig { /** * Assert the set of completions exist exactly, including their order. */ -function assertCompletions(actual: ITerminalCompletion[] | undefined, expected: IAssertionTerminalCompletion[], expectedConfig: IAssertionCommandLineConfig) { +function assertCompletions(actual: ITerminalCompletion[] | undefined, expected: IAssertionTerminalCompletion[], expectedConfig: IAssertionCommandLineConfig, pathSep?: string) { + const sep = pathSep ?? pathSeparator; assert.deepStrictEqual( actual?.map(e => ({ label: e.label, @@ -44,8 +47,8 @@ function assertCompletions(actual: ITerminalCompletion[] | undefined, expected: replacementIndex: e.replacementIndex, replacementLength: e.replacementLength, })), expected.map(e => ({ - label: e.label.replaceAll('/', pathSeparator), - detail: e.detail ? e.detail.replaceAll('/', pathSeparator) : '', + label: e.label.replaceAll('/', sep), + detail: e.detail ? e.detail.replaceAll('/', sep) : '', kind: e.kind ?? TerminalCompletionItemKind.Folder, replacementIndex: expectedConfig.replacementIndex, replacementLength: expectedConfig.replacementLength, @@ -608,4 +611,70 @@ suite('TerminalCompletionService', () => { ], { replacementIndex: 3, replacementLength: 0 }); }); }); + + if (isWindows) { + suite('gitbash', () => { + test('should convert Git Bash absolute path to Windows absolute path', () => { + assert.strictEqual(gitBashPathToWindows('/'), 'C:\\'); + assert.strictEqual(gitBashPathToWindows('/c/'), 'C:\\'); + assert.strictEqual(gitBashPathToWindows('/c/Users/foo'), 'C:\\Users\\foo'); + assert.strictEqual(gitBashPathToWindows('/d/bar'), 'D:\\bar'); + }); + + test('should convert Windows absolute path to Git Bash absolute path', () => { + assert.strictEqual(windowsToGitBashPath('C:\\'), '/c/'); + assert.strictEqual(windowsToGitBashPath('C:\\Users\\foo'), '/c/Users/foo'); + assert.strictEqual(windowsToGitBashPath('D:\\bar'), '/d/bar'); + assert.strictEqual(windowsToGitBashPath('E:\\some\\path'), '/e/some/path'); + }); + test('resolveResources with cwd as Windows path (relative)', async () => { + const resourceRequestConfig: TerminalResourceRequestConfig = { + cwd: URI.file('C:\\Users\\foo'), + foldersRequested: true, + filesRequested: true, + pathSeparator: '/' + }; + validResources = [ + URI.file('C:\\Users\\foo'), + URI.file('C:\\Users\\foo\\bar'), + URI.file('C:\\Users\\foo\\baz.txt') + ]; + childResources = [ + { resource: URI.file('C:\\Users\\foo\\bar'), isDirectory: true }, + { resource: URI.file('C:\\Users\\foo\\baz.txt'), isFile: true } + ]; + const result = await terminalCompletionService.resolveResources(resourceRequestConfig, './', 2, provider, capabilities, WindowsShellType.GitBash); + assertCompletions(result, [ + { label: './', detail: 'C:\\Users\\foo\\' }, + { label: './bar/', detail: 'C:\\Users\\foo\\bar\\' }, + { label: './baz.txt', detail: 'C:\\Users\\foo\\baz.txt', kind: TerminalCompletionItemKind.File }, + { label: './../', detail: 'C:\\Users\\' } + ], { replacementIndex: 0, replacementLength: 2 }, '/'); + }); + + test('resolveResources with cwd as Windows path (absolute)', async () => { + const resourceRequestConfig: TerminalResourceRequestConfig = { + cwd: URI.file('C:\\Users\\foo'), + foldersRequested: true, + filesRequested: true, + pathSeparator: '/' + }; + validResources = [ + URI.file('C:\\Users\\foo'), + URI.file('C:\\Users\\foo\\bar'), + URI.file('C:\\Users\\foo\\baz.txt') + ]; + childResources = [ + { resource: URI.file('C:\\Users\\foo\\bar'), isDirectory: true }, + { resource: URI.file('C:\\Users\\foo\\baz.txt'), isFile: true } + ]; + const result = await terminalCompletionService.resolveResources(resourceRequestConfig, '/c/Users/foo/', 13, provider, capabilities, WindowsShellType.GitBash); + assertCompletions(result, [ + { label: '/c/Users/foo/', detail: 'C:\\Users\\foo\\' }, + { label: '/c/Users/foo/bar/', detail: 'C:\\Users\\foo\\bar\\' }, + { label: '/c/Users/foo/baz.txt', detail: 'C:\\Users\\foo\\baz.txt', kind: TerminalCompletionItemKind.File }, + ], { replacementIndex: 0, replacementLength: 13 }, '/'); + }); + }); + } }); From 9641957a601a594c48b0522abffee444c2218d69 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 10 Jun 2025 12:18:45 -0700 Subject: [PATCH 174/236] add multi-command support for terminal suggest (#250910) --- .../terminal-suggest/src/fig/figInterface.ts | 12 ++-- .../src/helpers/completionItem.ts | 6 +- .../src/terminalSuggestMain.ts | 55 ++++++++++++------- .../src/test/terminalSuggestMain.test.ts | 6 +- .../terminal-suggest/src/test/tokens.test.ts | 49 +++++++++++++++++ extensions/terminal-suggest/src/tokens.ts | 29 ++++++++-- 6 files changed, 119 insertions(+), 38 deletions(-) diff --git a/extensions/terminal-suggest/src/fig/figInterface.ts b/extensions/terminal-suggest/src/fig/figInterface.ts index cb764e4ed62..46f634c7304 100644 --- a/extensions/terminal-suggest/src/fig/figInterface.ts +++ b/extensions/terminal-suggest/src/fig/figInterface.ts @@ -31,12 +31,11 @@ export async function getFigSuggestions( specs: Fig.Spec[], terminalContext: { commandLine: string; cursorPosition: number }, availableCommands: ICompletionResource[], - prefix: string, + currentCommandAndArgString: string, tokenType: TokenType, shellIntegrationCwd: vscode.Uri | undefined, env: Record, name: string, - precedingText: string, executeExternals: IFigExecuteExternals, token?: vscode.CancellationToken, ): Promise { @@ -46,6 +45,7 @@ export async function getFigSuggestions( hasCurrentArg: false, items: [], }; + const currentCommand = currentCommandAndArgString.split(' ')[0]; for (const spec of specs) { const specLabels = getFigSuggestionLabel(spec); @@ -66,7 +66,7 @@ export async function getFigSuggestions( const description = getFixSuggestionDescription(spec); result.items.push(createCompletionItem( terminalContext.cursorPosition, - prefix, + currentCommandAndArgString, { label: { label: specLabel, description }, kind: vscode.TerminalCompletionItemKind.Method @@ -83,8 +83,8 @@ export async function getFigSuggestions( : availableCommands.filter(command => specLabel === (command.definitionCommand ?? (typeof command.label === 'string' ? command.label : command.label.label)))); if ( !(osIsWindows() - ? commandAndAliases.some(e => precedingText.startsWith(`${removeAnyFileExtension((typeof e.label === 'string' ? e.label : e.label.label))} `)) - : commandAndAliases.some(e => precedingText.startsWith(`${typeof e.label === 'string' ? e.label : e.label.label} `))) + ? commandAndAliases.some(e => currentCommand.startsWith(removeAnyFileExtension((typeof e.label === 'string' ? e.label : e.label.label)))) + : commandAndAliases.some(e => currentCommand.startsWith(typeof e.label === 'string' ? e.label : e.label.label))) ) { continue; } @@ -93,7 +93,7 @@ export async function getFigSuggestions( if (!actualSpec) { continue; } - const completionItemResult = await getFigSpecSuggestions(actualSpec, terminalContext, prefix, shellIntegrationCwd, env, name, executeExternals, token); + const completionItemResult = await getFigSpecSuggestions(actualSpec, terminalContext, currentCommandAndArgString, shellIntegrationCwd, env, name, executeExternals, token); result.hasCurrentArg ||= !!completionItemResult?.hasCurrentArg; if (completionItemResult) { result.filesRequested ||= completionItemResult.filesRequested; diff --git a/extensions/terminal-suggest/src/helpers/completionItem.ts b/extensions/terminal-suggest/src/helpers/completionItem.ts index 236e3e0cc5c..7cb174223c1 100644 --- a/extensions/terminal-suggest/src/helpers/completionItem.ts +++ b/extensions/terminal-suggest/src/helpers/completionItem.ts @@ -6,9 +6,9 @@ import * as vscode from 'vscode'; import type { ICompletionResource } from '../types'; -export function createCompletionItem(cursorPosition: number, prefix: string, commandResource: ICompletionResource, detail?: string, documentation?: string | vscode.MarkdownString, kind?: vscode.TerminalCompletionItemKind): vscode.TerminalCompletionItem { - const endsWithSpace = prefix.endsWith(' '); - const lastWord = endsWithSpace ? '' : prefix.split(' ').at(-1) ?? ''; +export function createCompletionItem(cursorPosition: number, currentCommandString: string, commandResource: ICompletionResource, detail?: string, documentation?: string | vscode.MarkdownString, kind?: vscode.TerminalCompletionItemKind): vscode.TerminalCompletionItem { + const endsWithSpace = currentCommandString.endsWith(' '); + const lastWord = endsWithSpace ? '' : currentCommandString.split(' ').at(-1) ?? ''; return { label: commandResource.label, detail: detail ?? commandResource.detail ?? '', diff --git a/extensions/terminal-suggest/src/terminalSuggestMain.ts b/extensions/terminal-suggest/src/terminalSuggestMain.ts index 736a064ed21..ead819b23b8 100644 --- a/extensions/terminal-suggest/src/terminalSuggestMain.ts +++ b/extensions/terminal-suggest/src/terminalSuggestMain.ts @@ -20,7 +20,7 @@ import { getBashGlobals } from './shell/bash'; import { getFishGlobals } from './shell/fish'; import { getPwshGlobals } from './shell/pwsh'; import { getZshGlobals } from './shell/zsh'; -import { getTokenType, TokenType } from './tokens'; +import { getTokenType, TokenType, shellTypeResetChars, defaultShellTypeResetChars } from './tokens'; import type { ICompletionResource } from './types'; import { createCompletionItem } from './helpers/completionItem'; import { getFigSuggestions } from './fig/figInterface'; @@ -113,7 +113,7 @@ export async function activate(context: vscode.ExtensionContext) { } // Order is important here, add shell globals first so they are prioritized over path commands const commands = [...shellGlobals, ...commandsInPath.completionResources]; - const prefix = getPrefix(terminalContext.commandLine, terminalContext.cursorPosition); + const currentCommandString = getCurrentCommandAndArgs(terminalContext.commandLine, terminalContext.cursorPosition, terminalShellType); const pathSeparator = isWindows ? '\\' : '/'; const tokenType = getTokenType(terminalContext, terminalShellType); const result = await Promise.race([ @@ -121,7 +121,7 @@ export async function activate(context: vscode.ExtensionContext) { availableSpecs, terminalContext, commands, - prefix, + currentCommandString, tokenType, terminal.shellIntegration?.cwd, getEnvAsRecord(currentTerminalEnv), @@ -152,12 +152,14 @@ export async function activate(context: vscode.ExtensionContext) { } /** - * Adjusts the current working directory based on a given prefix if it is a folder. - * @param prefix - The folder path prefix. + * Adjusts the current working directory based on a given current command string if it is a folder. + * @param currentCommandString - The current command string, which might contain a folder path prefix. * @param currentCwd - The current working directory. * @returns The new working directory. */ -export async function resolveCwdFromPrefix(prefix: string, currentCwd?: vscode.Uri): Promise { +export async function resolveCwdFromCurrentCommandString(currentCommandString: string, currentCwd?: vscode.Uri): Promise { + const prefix = currentCommandString.split(/\s+/).pop()?.trim() ?? ''; + if (!currentCwd) { return; } @@ -195,7 +197,10 @@ export async function resolveCwdFromPrefix(prefix: string, currentCwd?: vscode.U return undefined; } -function getPrefix(commandLine: string, cursorPosition: number): string { +// Retrurns the string that represents the current command and its arguments up to the cursor position. +// Uses shell specific separators to determine the current command and its arguments. +export function getCurrentCommandAndArgs(commandLine: string, cursorPosition: number, shellType: TerminalShellType | undefined): string { + // Return an empty string if the command line is empty after trimming if (commandLine.trim() === '') { return ''; @@ -209,11 +214,21 @@ function getPrefix(commandLine: string, cursorPosition: number): string { // Extract the part of the line up to the cursor position const beforeCursor = commandLine.slice(0, cursorPosition); - // Find the last sequence of non-whitespace characters before the cursor - const match = beforeCursor.match(/(\S+)\s*$/); + const resetChars = shellType ? shellTypeResetChars.get(shellType) ?? defaultShellTypeResetChars : defaultShellTypeResetChars; + // Find the last reset character before the cursor + let lastResetIndex = -1; + for (const char of resetChars) { + const idx = beforeCursor.lastIndexOf(char); + if (idx > lastResetIndex) { + lastResetIndex = idx; + } + } - // Return the match if found, otherwise undefined - return match ? match[0] : ''; + // The start of the current command string is after the last reset char (plus one for the char itself) + const currentCommandStart = lastResetIndex + 1; + const currentCommandString = beforeCursor.slice(currentCommandStart).replace(/^\s+/, ''); + + return currentCommandString; } export function asArray(x: T | T[]): T[]; @@ -226,7 +241,7 @@ export async function getCompletionItemsFromSpecs( specs: Fig.Spec[], terminalContext: vscode.TerminalCompletionContext, availableCommands: ICompletionResource[], - prefix: string, + currentCommandString: string, tokenType: TokenType, shellIntegrationCwd: vscode.Uri | undefined, env: Record, @@ -240,17 +255,16 @@ export async function getCompletionItemsFromSpecs( let hasCurrentArg = false; let fileExtensions: string[] | undefined; - let precedingText = terminalContext.commandLine.slice(0, terminalContext.cursorPosition + 1); if (isWindows) { - const spaceIndex = precedingText.indexOf(' '); - const commandEndIndex = spaceIndex === -1 ? precedingText.length : spaceIndex; - const lastDotIndex = precedingText.lastIndexOf('.', commandEndIndex); + const spaceIndex = currentCommandString.indexOf(' '); + const commandEndIndex = spaceIndex === -1 ? currentCommandString.length : spaceIndex; + const lastDotIndex = currentCommandString.lastIndexOf('.', commandEndIndex); if (lastDotIndex > 0) { // Don't treat dotfiles as extensions - precedingText = precedingText.substring(0, lastDotIndex) + precedingText.substring(spaceIndex); + currentCommandString = currentCommandString.substring(0, lastDotIndex) + currentCommandString.substring(spaceIndex); } } - const result = await getFigSuggestions(specs, terminalContext, availableCommands, prefix, tokenType, shellIntegrationCwd, env, name, precedingText, executeExternals ?? { executeCommand, executeCommandTimeout }, token); + const result = await getFigSuggestions(specs, terminalContext, availableCommands, currentCommandString, tokenType, shellIntegrationCwd, env, name, executeExternals ?? { executeCommand, executeCommandTimeout }, token); if (result) { hasCurrentArg ||= result.hasCurrentArg; filesRequested ||= result.filesRequested; @@ -269,7 +283,7 @@ export async function getCompletionItemsFromSpecs( if (!labels.has(commandTextLabel)) { items.push(createCompletionItem( terminalContext.cursorPosition, - prefix, + currentCommandString, command, command.detail, command.documentation, @@ -300,7 +314,7 @@ export async function getCompletionItemsFromSpecs( let cwd: vscode.Uri | undefined; if (shellIntegrationCwd && (filesRequested || foldersRequested)) { - cwd = await resolveCwdFromPrefix(prefix, shellIntegrationCwd); + cwd = await resolveCwdFromCurrentCommandString(currentCommandString, shellIntegrationCwd); } return { items, filesRequested, foldersRequested, fileExtensions, cwd }; @@ -361,3 +375,4 @@ export function sanitizeProcessEnvironment(env: Record, ...prese } }); } + diff --git a/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts b/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts index 85f9cb6ca98..ce4fbb7bba6 100644 --- a/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts +++ b/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts @@ -6,7 +6,7 @@ import { deepStrictEqual, strictEqual } from 'assert'; import 'mocha'; import { basename } from 'path'; -import { asArray, getCompletionItemsFromSpecs } from '../terminalSuggestMain'; +import { asArray, getCompletionItemsFromSpecs, getCurrentCommandAndArgs } from '../terminalSuggestMain'; import { getTokenType } from '../tokens'; import { cdTestSuiteSpec as cdTestSuite } from './completions/cd.test'; import { codeSpecOptionsAndSubcommands, codeTestSuite, codeTunnelTestSuite } from './completions/code.test'; @@ -92,7 +92,7 @@ suite('Terminal Suggest', () => { test(`'${testSpec.input}' -> ${expectedString}`, async () => { const commandLine = testSpec.input.split('|')[0]; const cursorPosition = testSpec.input.indexOf('|'); - const prefix = commandLine.slice(0, cursorPosition).split(' ').at(-1) || ''; + const currentCommandString = getCurrentCommandAndArgs(commandLine, cursorPosition, undefined); const filesRequested = testSpec.expectedResourceRequests?.type === 'files' || testSpec.expectedResourceRequests?.type === 'both'; const foldersRequested = testSpec.expectedResourceRequests?.type === 'folders' || testSpec.expectedResourceRequests?.type === 'both'; const terminalContext = { commandLine, cursorPosition, allowFallbackCompletions: true }; @@ -100,7 +100,7 @@ suite('Terminal Suggest', () => { completionSpecs, terminalContext, availableCommands.map(c => { return { label: c }; }), - prefix, + currentCommandString, getTokenType(terminalContext, undefined), testPaths.cwd, {}, diff --git a/extensions/terminal-suggest/src/test/tokens.test.ts b/extensions/terminal-suggest/src/test/tokens.test.ts index 621a9b65388..fb3ea702bab 100644 --- a/extensions/terminal-suggest/src/test/tokens.test.ts +++ b/extensions/terminal-suggest/src/test/tokens.test.ts @@ -48,5 +48,54 @@ suite('Terminal Suggest', () => { test('arguments after reset char', () => { strictEqual(getTokenType({ commandLine: `Write-Host hello -and $true `, cursorPosition: `Write-Host hello -and $true `.length }, TerminalShellType.PowerShell), TokenType.Argument); }); + test('; reset char', () => { + strictEqual(getTokenType({ commandLine: `Write-Host hello; `, cursorPosition: `Write-Host hello; `.length }, TerminalShellType.PowerShell), TokenType.Command); + }); + suite('multiple commands on the line', () => { + test('multiple commands, cursor at end', () => { + strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && ech'.length }, undefined), TokenType.Command); + // Bash + strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && ech'.length }, TerminalShellType.Bash), TokenType.Command); + // Zsh + strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && ech'.length }, TerminalShellType.Zsh), TokenType.Command); + // Fish (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; ech'.length }, TerminalShellType.Fish), TokenType.Command); + // PowerShell (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; ech'.length }, TerminalShellType.PowerShell), TokenType.Command); + }); + test('multiple commands, cursor mid text', () => { + strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && echo w'.length }, undefined), TokenType.Argument); + // Bash + strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && echo w'.length }, TerminalShellType.Bash), TokenType.Argument); + // Zsh + strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && echo w'.length }, TerminalShellType.Zsh), TokenType.Argument); + // Fish (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; echo w'.length }, TerminalShellType.Fish), TokenType.Argument); + // PowerShell (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; echo w'.length }, TerminalShellType.PowerShell), TokenType.Argument); + }); + test('multiple commands, cursor at end with reset char', () => { + strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo world; '.length }, undefined), TokenType.Command); + // Bash + strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo world; '.length }, TerminalShellType.Bash), TokenType.Command); + // Zsh + strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo world; '.length }, TerminalShellType.Zsh), TokenType.Command); + // Fish (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo world; '.length }, TerminalShellType.Fish), TokenType.Command); + // PowerShell (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo world; '.length }, TerminalShellType.PowerShell), TokenType.Command); + }); + test('multiple commands, cursor mid text with reset char', () => { + strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo worl'.length }, undefined), TokenType.Argument); + // Bash + strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo worl'.length }, TerminalShellType.Bash), TokenType.Argument); + // Zsh + strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo worl'.length }, TerminalShellType.Zsh), TokenType.Argument); + // Fish (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo worl'.length }, TerminalShellType.Fish), TokenType.Argument); + // PowerShell (use ';' as separator) + strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo worl'.length }, TerminalShellType.PowerShell), TokenType.Argument); + }); + }); }); }); diff --git a/extensions/terminal-suggest/src/tokens.ts b/extensions/terminal-suggest/src/tokens.ts index 0520a2315a4..ee39314b6f9 100644 --- a/extensions/terminal-suggest/src/tokens.ts +++ b/extensions/terminal-suggest/src/tokens.ts @@ -11,21 +11,38 @@ export const enum TokenType { Argument, } -const shellTypeResetChars = new Map([ +export const shellTypeResetChars = new Map([ [TerminalShellType.Bash, ['>', '>>', '<', '2>', '2>>', '&>', '&>>', '|', '|&', '&&', '||', '&', ';', '(', '{', '<<']], [TerminalShellType.Zsh, ['>', '>>', '<', '2>', '2>>', '&>', '&>>', '<>', '|', '|&', '&&', '||', '&', ';', '(', '{', '<<', '<<<', '<(']], - [TerminalShellType.PowerShell, ['>', '>>', '<', '2>', '2>>', '*>', '*>>', '|', '-and', '-or', '-not', '!', '&', '-eq', '-ne', '-gt', '-lt', '-ge', '-le', '-like', '-notlike', '-match', '-notmatch', '-contains', '-notcontains', '-in', '-notin']] + [TerminalShellType.PowerShell, ['>', '>>', '<', '2>', '2>>', '*>', '*>>', '|', ';', '-and', '-or', '-not', '!', '&', '-eq', '-ne', '-gt', '-lt', '-ge', '-le', '-like', '-notlike', '-match', '-notmatch', '-contains', '-notcontains', '-in', '-notin']] ]); -const defaultShellTypeResetChars = shellTypeResetChars.get(TerminalShellType.Bash)!; +export const defaultShellTypeResetChars = shellTypeResetChars.get(TerminalShellType.Bash)!; export function getTokenType(ctx: { commandLine: string; cursorPosition: number }, shellType: TerminalShellType | undefined): TokenType { - const spaceIndex = ctx.commandLine.substring(0, ctx.cursorPosition).lastIndexOf(' '); + const commandLine = ctx.commandLine; + const cursorPosition = ctx.cursorPosition; + const commandResetChars = shellType === undefined ? defaultShellTypeResetChars : shellTypeResetChars.get(shellType) ?? defaultShellTypeResetChars; + + // Check for reset char before the current word + const beforeCursor = commandLine.substring(0, cursorPosition); + const wordStart = beforeCursor.lastIndexOf(' ') + 1; + const beforeWord = commandLine.substring(0, wordStart); + + // Look for " " before the word + for (const resetChar of commandResetChars) { + const pattern = ` ${resetChar} `; + if (beforeWord.endsWith(pattern)) { + return TokenType.Command; + } + } + + // Fallback to original logic for the very first command + const spaceIndex = beforeCursor.lastIndexOf(' '); if (spaceIndex === -1) { return TokenType.Command; } - const previousTokens = ctx.commandLine.substring(0, spaceIndex + 1).trim(); - const commandResetChars = shellType === undefined ? defaultShellTypeResetChars : shellTypeResetChars.get(shellType) ?? defaultShellTypeResetChars; + const previousTokens = beforeCursor.substring(0, spaceIndex + 1).trim(); if (commandResetChars.some(e => previousTokens.endsWith(e))) { return TokenType.Command; } From f7f11881697db564bf0890184cdb707113206d03 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Jun 2025 12:25:04 -0700 Subject: [PATCH 175/236] tools: respect chat.editor.wordWrap setting in tool confirms (#251133) Closes https://github.com/microsoft/vscode-copilot/issues/17373 --- .../toolInvocationParts/chatToolConfirmationSubPart.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/toolInvocationParts/chatToolConfirmationSubPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/toolInvocationParts/chatToolConfirmationSubPart.ts index 85170e72008..da36386ccaa 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/toolInvocationParts/chatToolConfirmationSubPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/toolInvocationParts/chatToolConfirmationSubPart.ts @@ -118,7 +118,6 @@ export class ToolConfirmationSubPart extends BaseChatToolInvocationSubPart { reserveWidth: 19, verticalPadding: 5, editorOptions: { - wordWrap: 'on', tabFocusMode: true, ariaLabel: typeof title === 'string' ? title : title.value }, From 10066c9ec39bad2a849a2b857271d9917f33b79e Mon Sep 17 00:00:00 2001 From: Aaron Munger <2019016+amunger@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:30:54 -0700 Subject: [PATCH 176/236] more certainty for resuming the paused emitter (#251130) --- .../ipynb/src/test/clearOutputs.test.ts | 2 +- .../workbench/api/common/extHostNotebook.ts | 2 +- .../common/model/notebookTextModel.ts | 53 ++++++++++--------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/extensions/ipynb/src/test/clearOutputs.test.ts b/extensions/ipynb/src/test/clearOutputs.test.ts index fc2608ee227..62e40d6110d 100644 --- a/extensions/ipynb/src/test/clearOutputs.test.ts +++ b/extensions/ipynb/src/test/clearOutputs.test.ts @@ -25,7 +25,7 @@ suite(`ipynb Clear Outputs`, () => { await vscode.commands.executeCommand('workbench.action.closeAllEditors'); }); - test.skip('Clear outputs after opening Notebook', async () => { + test('Clear outputs after opening Notebook', async () => { const cells: nbformat.ICell[] = [ { cell_type: 'code', diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index a4e75dc114f..1dea8c800d7 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -327,7 +327,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { } if (document.versionId !== versionId) { - throw new Error('Document version mismatch'); + throw new Error('Document version mismatch, expected: ' + versionId + ', actual: ' + document.versionId); } if (!this._extHostFileSystem.value.isWritableFileSystem(uri.scheme)) { diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index 237e0ff8bdf..925dcdd8bc2 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -49,8 +49,8 @@ class StackOperation implements IWorkspaceUndoRedoElement { constructor( readonly textModel: NotebookTextModel, readonly undoRedoGroup: UndoRedoGroup | undefined, - private _pauseableEmitter: PauseableEmitter, - private _postUndoRedo: (alternativeVersionId: string) => void, + private readonly _pauseableEmitter: PauseableEmitter, + private readonly _postUndoRedo: (alternativeVersionId: string) => void, selectionState: ISelectionState | undefined, beginAlternativeVersionId: string ) { @@ -621,32 +621,35 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel applyEdits(rawEdits: ICellEditOperation[], synchronous: boolean, beginSelectionState: ISelectionState | undefined, endSelectionsComputer: () => ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined, computeUndoRedo: boolean): boolean { this._pauseableEmitter.pause(); - this._operationManager.pushStackElement(this._alternativeVersionId, undefined); - - if (computeUndoRedo && this.isOnlyEditingMetadataOnNewCells(rawEdits)) { - if (!this._operationManager.appendPreviousOperation()) { - // we can't append the previous operation, so just don't compute undo/redo - computeUndoRedo = false; - } - } else if (computeUndoRedo) { - this.newCellsFromLastEdit.clear(); - } - try { - this._doApplyEdits(rawEdits, synchronous, computeUndoRedo, beginSelectionState, undoRedoGroup); - return true; - } finally { - if (!this._pauseableEmitter.isEmpty) { - // Update selection and versionId after applying edits. - const endSelections = endSelectionsComputer(); - this._increaseVersionId(this._operationManager.isUndoStackEmpty() && !this._pauseableEmitter.isDirtyEvent()); + this._operationManager.pushStackElement(this._alternativeVersionId, undefined); - // Finalize undo element - this._operationManager.pushStackElement(this._alternativeVersionId, endSelections); - - // Broadcast changes - this._pauseableEmitter.fire({ rawEvents: [], versionId: this.versionId, synchronous: synchronous, endSelectionState: endSelections }); + if (computeUndoRedo && this.isOnlyEditingMetadataOnNewCells(rawEdits)) { + if (!this._operationManager.appendPreviousOperation()) { + // we can't append the previous operation, so just don't compute undo/redo + computeUndoRedo = false; + } + } else if (computeUndoRedo) { + this.newCellsFromLastEdit.clear(); } + + try { + this._doApplyEdits(rawEdits, synchronous, computeUndoRedo, beginSelectionState, undoRedoGroup); + return true; + } finally { + if (!this._pauseableEmitter.isEmpty) { + // Update selection and versionId after applying edits. + const endSelections = endSelectionsComputer(); + this._increaseVersionId(this._operationManager.isUndoStackEmpty() && !this._pauseableEmitter.isDirtyEvent()); + + // Finalize undo element + this._operationManager.pushStackElement(this._alternativeVersionId, endSelections); + + // Broadcast changes + this._pauseableEmitter.fire({ rawEvents: [], versionId: this.versionId, synchronous: synchronous, endSelectionState: endSelections }); + } + } + } finally { this._pauseableEmitter.resume(); } } From b1cd91be02f7c957721077c78ef3f410c48a79fd Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 10 Jun 2025 14:18:20 -0700 Subject: [PATCH 177/236] de-dupe terminal suggest commands for which there are specs (#251142) fix #244918 --- extensions/terminal-suggest/src/terminalSuggestMain.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/terminal-suggest/src/terminalSuggestMain.ts b/extensions/terminal-suggest/src/terminalSuggestMain.ts index ead819b23b8..8798ffa872d 100644 --- a/extensions/terminal-suggest/src/terminalSuggestMain.ts +++ b/extensions/terminal-suggest/src/terminalSuggestMain.ts @@ -280,7 +280,9 @@ export async function getCompletionItemsFromSpecs( const labels = new Set(items.map((i) => typeof i.label === 'string' ? i.label : i.label.label)); for (const command of availableCommands) { const commandTextLabel = typeof command.label === 'string' ? command.label : command.label.label; - if (!labels.has(commandTextLabel)) { + // Remove any file extension for matching on Windows + const labelWithoutExtension = isWindows ? commandTextLabel.replace(/\.[^ ]+$/, '') : commandTextLabel; + if (!labels.has(labelWithoutExtension)) { items.push(createCompletionItem( terminalContext.cursorPosition, currentCommandString, From 6bfb59d217aff82e1b696f4851244075bf0ea99b Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 10 Jun 2025 14:27:30 -0700 Subject: [PATCH 178/236] improve consistency of function names (#251145) --- .../suggest/browser/terminalCompletionService.ts | 4 ++-- .../suggest/browser/terminalGitBashHelpers.ts | 2 +- .../test/browser/terminalCompletionService.test.ts | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts index 6c580e5ebc3..79069fb688a 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts @@ -17,7 +17,7 @@ import { TerminalCompletionItemKind, type ITerminalCompletion } from './terminal import { env as processEnv } from '../../../../../base/common/process.js'; import type { IProcessEnvironment } from '../../../../../base/common/platform.js'; import { timeout } from '../../../../../base/common/async.js'; -import { gitBashPathToWindows } from './terminalGitBashHelpers.js'; +import { gitBashToWindowsPath } from './terminalGitBashHelpers.js'; export const ITerminalCompletionService = createDecorator('terminalCompletionService'); @@ -282,7 +282,7 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo } case 'absolute': { if (shellType === WindowsShellType.GitBash) { - lastWordFolderResource = URI.file(gitBashPathToWindows(lastWordFolder, this._processEnv.SystemDrive)); + lastWordFolderResource = URI.file(gitBashToWindowsPath(lastWordFolder, this._processEnv.SystemDrive)); } else { lastWordFolderResource = URI.file(lastWordFolder.replaceAll('\\ ', ' ')); } diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts index fb7c6b6fab7..32363fac9f9 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalGitBashHelpers.ts @@ -11,7 +11,7 @@ * "/c/Users/foo" => "C:\\Users\\foo" * "/d/bar" => "D:\\bar" */ -export function gitBashPathToWindows(path: string, driveLetter?: string): string { +export function gitBashToWindowsPath(path: string, driveLetter?: string): string { // Dynamically determine the system drive (default to 'C:' if not set) const systemDrive = (driveLetter || 'C:').toUpperCase(); // Handle root "/" diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts index 6b458c5de6e..30ae35bb978 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/test/browser/terminalCompletionService.test.ts @@ -19,7 +19,7 @@ import { TerminalCapability } from '../../../../../../platform/terminal/common/c import { ITerminalCompletion, TerminalCompletionItemKind } from '../../browser/terminalCompletionItem.js'; import { count } from '../../../../../../base/common/strings.js'; import { WindowsShellType } from '../../../../../../platform/terminal/common/terminal.js'; -import { gitBashPathToWindows, windowsToGitBashPath } from '../../browser/terminalGitBashHelpers.js'; +import { gitBashToWindowsPath, windowsToGitBashPath } from '../../browser/terminalGitBashHelpers.js'; const pathSeparator = isWindows ? '\\' : '/'; @@ -615,10 +615,10 @@ suite('TerminalCompletionService', () => { if (isWindows) { suite('gitbash', () => { test('should convert Git Bash absolute path to Windows absolute path', () => { - assert.strictEqual(gitBashPathToWindows('/'), 'C:\\'); - assert.strictEqual(gitBashPathToWindows('/c/'), 'C:\\'); - assert.strictEqual(gitBashPathToWindows('/c/Users/foo'), 'C:\\Users\\foo'); - assert.strictEqual(gitBashPathToWindows('/d/bar'), 'D:\\bar'); + assert.strictEqual(gitBashToWindowsPath('/'), 'C:\\'); + assert.strictEqual(gitBashToWindowsPath('/c/'), 'C:\\'); + assert.strictEqual(gitBashToWindowsPath('/c/Users/foo'), 'C:\\Users\\foo'); + assert.strictEqual(gitBashToWindowsPath('/d/bar'), 'D:\\bar'); }); test('should convert Windows absolute path to Git Bash absolute path', () => { From 7a24d629165d7d42d655b833f7bf44e38faf1c0e Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 11 Jun 2025 07:34:40 +1000 Subject: [PATCH 179/236] Disable variable line heights in notebook cells (#251063) --- .../contrib/notebook/browser/diff/diffComponents.ts | 6 ++++-- .../contrib/notebook/browser/diff/notebookDiffList.ts | 1 + .../contrib/notebook/browser/view/cellParts/markupCell.ts | 1 + .../contrib/notebook/browser/view/notebookCellEditorPool.ts | 1 + .../contrib/notebook/browser/view/renderers/cellRenderer.ts | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index a0a5557ddab..cfefb3c005c 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -860,7 +860,8 @@ abstract class AbstractElementRenderer extends Disposable { height: this.cell.layoutInfo.metadataHeight }, overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(), - readOnly: false + readOnly: false, + allowVariableLineHeights: false }, {}); this.layout({ metadataHeight: true }); this._metadataEditorDisposeStore.add(this._metadataEditor); @@ -956,7 +957,8 @@ abstract class AbstractElementRenderer extends Disposable { width: Math.min(OUTPUT_EDITOR_HEIGHT_MAGIC, this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, this.cell.type === 'unchanged' || this.cell.type === 'modified') - 32), height: this.cell.layoutInfo.rawOutputHeight }, - overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode() + overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(), + allowVariableLineHeights: false }, {}); this._outputEditorDisposeStore.add(this._outputEditor); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts index 047e35327a7..c36959700cd 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.ts @@ -621,6 +621,7 @@ function buildSourceEditor(instantiationService: IInstantiationService, notebook }, automaticLayout: false, overflowWidgetsDomNode: notebookEditor.getOverflowContainerDomNode(), + allowVariableLineHeights: false, readOnly: true, }, { contributions: EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1) diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts index 1797591072f..004ed1c4747 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts @@ -331,6 +331,7 @@ export class MarkupCell extends Disposable { width: width, height: editorHeight }, + allowVariableLineHeights: false, // overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode() }, { contributions: this.notebookEditor.creationOptions.cellEditorContributions diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellEditorPool.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellEditorPool.ts index 973f914aecb..f47594f0796 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellEditorPool.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellEditorPool.ts @@ -61,6 +61,7 @@ export class NotebookCellEditorPool extends Disposable { handleMouseWheel: false, useShadows: false, }, + allowVariableLineHeights: false, }, { contributions: this.notebookEditor.creationOptions.cellEditorContributions })); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 3904dd608ff..867645b650a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -286,6 +286,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende const editor = editorInstaService.createInstance(CodeEditorWidget, editorContainer, { ...this.editorOptions.getDefaultValue(), + allowVariableLineHeights: false, dimension: { width: 0, height: 0 From 2aee1bc22bcf3df06754d265f010977057441332 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Jun 2025 14:47:05 -0700 Subject: [PATCH 180/236] chat: move mcp and extension tools out of preview (#251116) Following DSB approval. --- src/vs/workbench/contrib/chat/browser/chat.contribution.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index be5215d19e5..f9d9e7c8a63 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -302,13 +302,10 @@ configurationRegistry.registerConfiguration({ type: 'boolean', description: nls.localize('chat.extensionToolsEnabled', "Enable using tools contributed by third-party extensions."), default: true, - tags: ['preview'], policy: { name: 'ChatAgentExtensionTools', minimumVersion: '1.99', description: nls.localize('chat.extensionToolsPolicy', "Enable using tools contributed by third-party extensions."), - previewFeature: true, - defaultValue: false } }, [ChatConfiguration.AgentEnabled]: { From fa298e0de07a1623b063be669bf68c9c09a90da4 Mon Sep 17 00:00:00 2001 From: Aaron Munger <2019016+amunger@users.noreply.github.com> Date: Tue, 10 Jun 2025 15:50:26 -0700 Subject: [PATCH 181/236] skip flaky test (#251158) --- extensions/ipynb/src/test/clearOutputs.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ipynb/src/test/clearOutputs.test.ts b/extensions/ipynb/src/test/clearOutputs.test.ts index 62e40d6110d..fc2608ee227 100644 --- a/extensions/ipynb/src/test/clearOutputs.test.ts +++ b/extensions/ipynb/src/test/clearOutputs.test.ts @@ -25,7 +25,7 @@ suite(`ipynb Clear Outputs`, () => { await vscode.commands.executeCommand('workbench.action.closeAllEditors'); }); - test('Clear outputs after opening Notebook', async () => { + test.skip('Clear outputs after opening Notebook', async () => { const cells: nbformat.ICell[] = [ { cell_type: 'code', From 99b897a32a83ed981218496db1124bceb02ec80a Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Jun 2025 16:13:04 -0700 Subject: [PATCH 182/236] eng: adopt killBehavior polite (#251159) * tools: respect chat.editor.wordWrap setting in tool confirms Closes https://github.com/microsoft/vscode-copilot/issues/17373 * eng: adopt killBehavior polite Refs https://github.com/microsoft/vscode-js-debug/pull/2238 Closes https://github.com/microsoft/vscode/issues/244111 --- .vscode/launch.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index f922b5d9c80..6b95eed617f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -254,6 +254,7 @@ "VSCODE_SKIP_PRELAUNCH": "1", }, "cleanUp": "wholeBrowser", + "killBehavior": "polite", "runtimeArgs": [ "--inspect-brk=5875", "--no-cached-data", From 9f296339fbbd4434027a88683e388a329c2a7335 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:39:13 -0700 Subject: [PATCH 183/236] feat: improve AI settings search tooltip label (#251163) feat: add AI settings search loading tooltip text --- src/vs/base/browser/ui/toggle/toggle.ts | 10 +++++++++- .../contrib/preferences/browser/settingsEditor2.ts | 13 ++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/toggle/toggle.ts b/src/vs/base/browser/ui/toggle/toggle.ts index aa2072ff03a..93fd6f82c06 100644 --- a/src/vs/base/browser/ui/toggle/toggle.ts +++ b/src/vs/base/browser/ui/toggle/toggle.ts @@ -55,10 +55,12 @@ export class ToggleActionViewItem extends BaseActionViewItem { constructor(context: unknown, action: IAction, options: IActionViewItemOptions) { super(context, action, options); + const title = (this.options).keybinding ? + `${this._action.label} (${(this.options).keybinding})` : this._action.label; this.toggle = this._register(new Toggle({ actionClassName: this._action.class, isChecked: !!this._action.checked, - title: (this.options).keybinding ? `${this._action.label} (${(this.options).keybinding})` : this._action.label, + title, notFocusable: true, inputActiveOptionBackground: options.toggleStyles?.inputActiveOptionBackground, inputActiveOptionBorder: options.toggleStyles?.inputActiveOptionBorder, @@ -94,6 +96,12 @@ export class ToggleActionViewItem extends BaseActionViewItem { this.toggle.checked = !!this._action.checked; } + protected override updateLabel(): void { + const title = (this.options).keybinding ? + `${this._action.label} (${(this.options).keybinding})` : this._action.label; + this.toggle.setTitle(title); + } + override focus(): void { this.toggle.domNode.tabIndex = 0; this.toggle.focus(); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 29b4bbb3b50..6379ca44dcb 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -634,11 +634,18 @@ export class SettingsEditor2 extends EditorPane { if (!setupHidden && showSuggestions) { const showAiResultActionClassNames = ['action-label', ThemeIcon.asClassName(preferencesAiResultsIcon)]; const searchServiceEnabled = this.aiSettingsSearchService.isEnabled(); + this.showAiResultsAction = this._register(new Action(SETTINGS_EDITOR_COMMAND_SHOW_AI_RESULTS, - localize('showAiResultsDescription', "Search settings with AI"), showAiResultActionClassNames.join(' '), searchServiceEnabled + searchServiceEnabled + ? localize('showAiResultsDescription', "Search settings with AI") + : localize('showAiResultsNotReady', "AI search functionality loading..."), + showAiResultActionClassNames.join(' '), searchServiceEnabled )); this._register(this.aiSettingsSearchService.onProviderRegistered(() => { - this.showAiResultsAction!.enabled = true; + if (this.showAiResultsAction) { + this.showAiResultsAction.label = localize('showAiResultsDescription', "Search settings with AI"); + this.showAiResultsAction.enabled = true; + } })); this._register(this.showAiResultsAction.onDidChange(() => { this.onSearchInputChanged(true); @@ -724,7 +731,7 @@ export class SettingsEditor2 extends EditorPane { return this.instantiationService.createInstance(SettingsSearchFilterDropdownMenuActionViewItem, action, options, this.actionRunner, this.searchWidget); } if (this.showAiResultsAction && action.id === this.showAiResultsAction.id) { - return new ToggleActionViewItem(null, action, { ...options, toggleStyles: defaultToggleStyles }); + return new ToggleActionViewItem(null, action, { ...options, keybinding: 'Ctrl+I', toggleStyles: defaultToggleStyles }); } return undefined; } From 62f57f9cbd6dca9b0a1c44be545e0de9e3592480 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Tue, 10 Jun 2025 19:46:00 -0700 Subject: [PATCH 184/236] vscodebot chat classifier (#251174) --- .github/commands.json | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/.github/commands.json b/.github/commands.json index 38da97915a2..57aeb77bd9f 100644 --- a/.github/commands.json +++ b/.github/commands.json @@ -538,5 +538,62 @@ "addLabel": "info-needed", "removeLabel": "~confirmation-needed", "comment": "Please diagnose the root cause of the issue by running the command `F1 > Help: Troubleshoot Issue` and following the instructions. Once you have done that, please update the issue with the results.\n\nHappy Coding!" + }, + { + "type": "label", + "name": "~chat-rate-limiting", + "removeLabel": "~chat-rate-limiting", + "action": "close", + "reason": "not_planned", + "comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2627. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem." + }, + { + "type": "label", + "name": "~chat-request-failed", + "removeLabel": "~chat-request-failed", + "action": "close", + "reason": "not_planned", + "comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/4332. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem." + }, + { + "type": "label", + "name": "~chat-rai-content-filters", + "removeLabel": "~chat-rai-content-filters", + "action": "close", + "reason": "not_planned", + "comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2625. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem." + }, + { + "type": "label", + "name": "~chat-public-code-blocking", + "removeLabel": "~chat-public-code-blocking", + "action": "close", + "reason": "not_planned", + "comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2626. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem." + }, + { + "type": "label", + "name": "~chat-lm-unavailable", + "removeLabel": "~chat-lm-unavailable", + "action": "close", + "reason": "not_planned", + "comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2116. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem." + }, + { + "type": "label", + "name": "~chat-authentication", + "removeLabel": "~chat-authentication", + "action": "close", + "reason": "not_planned", + "comment": "Please look at the following meta issue: https://github.com/microsoft/vscode-copilot-release/issues/11078, if the bug you are experiencing is not there, please comment on this closed issue thread so we can re-open it.", + "assign": ["TylerLeonhardt"] + }, + { + "type": "label", + "name": "~chat-no-response-returned", + "removeLabel": "~chat-no-response-returned", + "action": "close", + "reason": "not_planned", + "comment": "Please look at the following meta issue: https://github.com/microsoft/vscode-copilot-release/issues/7034. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem." } ] From be489936ee8c474aa72359f8270674f40bd4c23e Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Jun 2025 23:37:17 -0700 Subject: [PATCH 185/236] testing: fix not apply configured editor options to result editor (#251181) Fixes #250333 Fixes #250549 --- .../testResultsView/testResultsOutput.ts | 84 ++++++++++++++++--- .../testResultsView/testResultsViewContent.ts | 5 +- 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts index ce9d447356f..c8796a108b2 100644 --- a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts +++ b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts @@ -10,6 +10,7 @@ import { Event } from '../../../../../base/common/event.js'; import { Iterable } from '../../../../../base/common/iterator.js'; import { Lazy } from '../../../../../base/common/lazy.js'; import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable, combinedDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; +import { ScrollEvent } from '../../../../../base/common/scrollable.js'; import { URI } from '../../../../../base/common/uri.js'; import { ICodeEditor, IDiffEditorConstructionOptions } from '../../../../../editor/browser/editorBrowser.js'; import { CodeEditorWidget } from '../../../../../editor/browser/widget/codeEditor/codeEditorWidget.js'; @@ -18,30 +19,31 @@ import { DiffEditorWidget } from '../../../../../editor/browser/widget/diffEdito import { EmbeddedDiffEditorWidget } from '../../../../../editor/browser/widget/diffEditor/embeddedDiffEditorWidget.js'; import { MarkdownRenderer } from '../../../../../editor/browser/widget/markdownRenderer/browser/markdownRenderer.js'; import { IDiffEditorOptions, IEditorOptions } from '../../../../../editor/common/config/editorOptions.js'; +import { ITextModel } from '../../../../../editor/common/model.js'; import { IResolvedTextEditorModel, ITextModelService } from '../../../../../editor/common/services/resolverService.js'; import { peekViewResultsBackground } from '../../../../../editor/contrib/peekView/browser/peekView.js'; import { localize } from '../../../../../nls.js'; +import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { TerminalCapability } from '../../../../../platform/terminal/common/capabilities/capabilities.js'; import { TerminalCapabilityStore } from '../../../../../platform/terminal/common/capabilities/terminalCapabilityStore.js'; import { formatMessageForTerminal } from '../../../../../platform/terminal/common/terminalStrings.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; +import { IEditorConfiguration } from '../../../../browser/parts/editor/textEditor.js'; import { EditorModel } from '../../../../common/editor/editorModel.js'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from '../../../../common/theme.js'; import { IViewDescriptorService, ViewContainerLocation } from '../../../../common/views.js'; +import { CALL_STACK_WIDGET_HEADER_HEIGHT } from '../../../debug/browser/callStackWidget.js'; import { DetachedProcessInfo } from '../../../terminal/browser/detachedTerminal.js'; import { IDetachedTerminalInstance, ITerminalService } from '../../../terminal/browser/terminal.js'; import { getXtermScaledDimensions } from '../../../terminal/browser/xterm/xtermTerminal.js'; import { TERMINAL_BACKGROUND_COLOR } from '../../../terminal/common/terminalColorRegistry.js'; -import { colorizeTestMessageInEditor } from '../testMessageColorizer.js'; -import { InspectSubject, MessageSubject, TaskSubject, TestOutputSubject } from './testResultsSubject.js'; import { Testing } from '../../common/constants.js'; import { MutableObservableValue } from '../../common/observableValue.js'; import { ITaskRawOutput, ITestResult, ITestRunTaskResults, LiveTestResult, TestResultItemChangeReason } from '../../common/testResult.js'; import { ITestMessage, TestMessageType, getMarkId } from '../../common/testTypes.js'; -import { ScrollEvent } from '../../../../../base/common/scrollable.js'; -import { CALL_STACK_WIDGET_HEADER_HEIGHT } from '../../../debug/browser/callStackWidget.js'; -import { ITextModel } from '../../../../../editor/common/model.js'; +import { colorizeTestMessageInEditor } from '../testMessageColorizer.js'; +import { InspectSubject, MessageSubject, TaskSubject, TestOutputSubject } from './testResultsSubject.js'; class SimpleDiffEditorModel extends EditorModel { @@ -110,6 +112,35 @@ const diffEditorOptions: IDiffEditorConstructionOptions = { diffAlgorithm: 'advanced', }; +function applyEditorMirrorOptions(base: T, cfg: IConfigurationService, update: (options: Partial) => void) { + const immutable = new Set(Object.keys(base)); + function applyCurrent() { + const configuration = cfg.getValue('editor'); + + let changed = false; + const patch: Partial = {}; + for (const [key, value] of Object.entries(configuration)) { + if (!immutable.has(key) && (base as any)[key] !== value) { + (patch as any)[key] = value; + changed = true; + } + } + + return changed ? patch : undefined; + } + + Object.assign(base, applyCurrent()); + + return cfg.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor')) { + const patch = applyCurrent(); + if (patch) { + update(patch); + Object.assign(base, patch); + } + } + }); +} export class DiffContentProvider extends Disposable implements IPeekOutputRenderer { private readonly widget = this._register(new MutableDisposable()); @@ -126,6 +157,7 @@ export class DiffContentProvider extends Disposable implements IPeekOutputRender private readonly container: HTMLElement, @IInstantiationService private readonly instantiationService: IInstantiationService, @ITextModelService private readonly modelService: ITextModelService, + @IConfigurationService private readonly configurationService: IConfigurationService, ) { super(); } @@ -148,21 +180,32 @@ export class DiffContentProvider extends Disposable implements IPeekOutputRender const model = this.model.value = new SimpleDiffEditorModel(original, modified); if (!this.widget.value) { - this.widget.value = this.editor ? this.instantiationService.createInstance( + const options = { ...diffEditorOptions }; + const listener = applyEditorMirrorOptions( + options, + this.configurationService, + u => editor.updateOptions(u) + ); + + const editor = this.widget.value = this.editor ? this.instantiationService.createInstance( EmbeddedDiffEditorWidget, this.container, - diffEditorOptions, + options, {}, this.editor, ) : this.instantiationService.createInstance( DiffEditorWidget, this.container, - diffEditorOptions, + options, {}, ); + Event.once(editor.onDidDispose)(() => { + listener.dispose(); + }); + if (this.dimension) { - this.widget.value.layout(this.dimension); + editor.layout(this.dimension); } } @@ -191,6 +234,7 @@ export class DiffContentProvider extends Disposable implements IPeekOutputRender editor.getOriginalEditor().getContentHeight(), editor.getModifiedEditor().getContentHeight() ); + editor.updateOptions({ scrollbar: { ...commonEditorOptions.scrollbar, handleMouseWheel: !hasMultipleFrames } }); this.helper = new ScrollHelper(hasMultipleFrames, height, dimensions.height); return height; } @@ -293,6 +337,7 @@ export class PlainTextMessagePeek extends Disposable implements IPeekOutputRende private readonly container: HTMLElement, @IInstantiationService private readonly instantiationService: IInstantiationService, @ITextModelService private readonly modelService: ITextModelService, + @IConfigurationService private readonly configurationService: IConfigurationService, ) { super(); } @@ -311,21 +356,32 @@ export class PlainTextMessagePeek extends Disposable implements IPeekOutputRende const modelRef = this.model.value = await this.modelService.createModelReference(subject.messageUri); if (!this.widget.value) { - this.widget.value = this.editor ? this.instantiationService.createInstance( + const options = { ...commonEditorOptions }; + const listener = applyEditorMirrorOptions( + options, + this.configurationService, + u => editor.updateOptions(u) + ); + + const editor = this.widget.value = this.editor ? this.instantiationService.createInstance( EmbeddedCodeEditorWidget, this.container, - commonEditorOptions, + options, {}, this.editor, ) : this.instantiationService.createInstance( CodeEditorWidget, this.container, - commonEditorOptions, + options, { isSimpleWidget: true } ); + Event.once(editor.onDidDispose)(() => { + listener.dispose(); + }); + if (this.dimension) { - this.widget.value.layout(this.dimension); + editor.layout(this.dimension); } } @@ -355,6 +411,8 @@ export class PlainTextMessagePeek extends Disposable implements IPeekOutputRende editor.layout(dimensions); const height = editor.getContentHeight(); this.helper = new ScrollHelper(hasMultipleFrames, height, dimensions.height); + editor.updateOptions({ scrollbar: { ...commonEditorOptions.scrollbar, handleMouseWheel: !hasMultipleFrames } }); + return height; } } diff --git a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsViewContent.ts b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsViewContent.ts index 5f2990a413a..d507557bcb8 100644 --- a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsViewContent.ts +++ b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsViewContent.ts @@ -393,9 +393,10 @@ export class TestResultsViewContent extends Disposable { if (provider.onDidContentSizeChange) { this.currentSubjectStore.add(provider.onDidContentSizeChange(() => { - if (this.dimension && !this.isDoingLayoutUpdate) { + const width = this.splitView.getViewSize(SubView.Diff); + if (this.dimension && !this.isDoingLayoutUpdate && width !== -1) { this.isDoingLayoutUpdate = true; - topFrame.height.set(provider.layout(this.dimension, hasMultipleFrames)!, undefined); + topFrame.height.set(provider.layout({ width, height: this.dimension.height }, hasMultipleFrames)!, undefined); this.isDoingLayoutUpdate = false; } })); From b6636327e73016e3ae382caaea9199ccbb8fddf7 Mon Sep 17 00:00:00 2001 From: Benjamin Christopher Simmonds <44439583+benibenj@users.noreply.github.com> Date: Wed, 11 Jun 2025 09:40:02 +0200 Subject: [PATCH 186/236] Adopt variable line height for NES (#251121) adopt variable lineheight for NES --- src/vs/editor/browser/observableCodeEditor.ts | 46 +++++++++++++++++++ .../components/gutterIndicatorView.ts | 2 +- .../inlineEditsViews/inlineEditsCustomView.ts | 2 +- .../inlineEditsInsertionView.ts | 6 +-- .../inlineEditsLineReplacementView.ts | 18 ++++++-- .../inlineEditsSideBySideView.ts | 4 +- .../inlineEditsWordInsertView.ts | 2 +- .../inlineEditsWordReplacementView.ts | 3 +- 8 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/browser/observableCodeEditor.ts b/src/vs/editor/browser/observableCodeEditor.ts index 42b6580e9bc..a30f01dacc8 100644 --- a/src/vs/editor/browser/observableCodeEditor.ts +++ b/src/vs/editor/browser/observableCodeEditor.ts @@ -148,6 +148,7 @@ export class ObservableCodeEditor extends Disposable { this.layoutInfoVerticalScrollbarWidth = this.layoutInfo.map(l => l.verticalScrollbarWidth); this.contentWidth = observableFromEvent(this.editor.onDidContentSizeChange, () => this.editor.getContentWidth()); this.contentHeight = observableFromEvent(this.editor.onDidContentSizeChange, () => this.editor.getContentHeight()); + this._widgetCounter = 0; this.openedPeekWidgets = observableValue(this, 0); @@ -403,6 +404,51 @@ export class ObservableCodeEditor extends Disposable { })); return isHovered; } + + observeLineHeightForPosition(position: IObservable | Position): IObservable; + observeLineHeightForPosition(position: IObservable): IObservable; + observeLineHeightForPosition(position: IObservable | Position): IObservable { + return derived(reader => { + const pos = position instanceof Position ? position : position.read(reader); + if (pos === null) { + return null; + } + + this.getOption(EditorOption.lineHeight).read(reader); + + return this.editor.getLineHeightForPosition(pos); + }); + } + + observeLineHeightForLine(lineNumber: IObservable | number): IObservable; + observeLineHeightForLine(lineNumber: IObservable): IObservable; + observeLineHeightForLine(lineNumber: IObservable | number): IObservable { + if (typeof lineNumber === 'number') { + return this.observeLineHeightForPosition(new Position(lineNumber, 1)); + } + + return derived(reader => { + const line = lineNumber.read(reader); + if (line === null) { + return null; + } + + return this.observeLineHeightForPosition(new Position(line, 1)).read(reader); + }); + } + + observeLineHeightsForLineRange(lineNumber: IObservable | LineRange): IObservable { + return derived(reader => { + const range = lineNumber instanceof LineRange ? lineNumber : lineNumber.read(reader); + + const heights: number[] = []; + for (let i = range.startLineNumber; i < range.endLineNumberExclusive; i++) { + heights.push(this.observeLineHeightForLine(i).read(reader)); + } + return heights; + }); + } + } interface IObservableOverlayWidget { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts index b43d49953be..6197b67ae97 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts @@ -197,7 +197,7 @@ export class InlineEditsGutterIndicator extends Disposable { const layout = this._editorObs.layoutInfo.read(reader); - const lineHeight = this._editorObs.getOption(EditorOption.lineHeight).read(reader); + const lineHeight = this._editorObs.observeLineHeightForLine(s.range.map(r => r.startLineNumber)).read(reader); const gutterViewPortPadding = 1; // Entire gutter view from top left to bottom right diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts index 01ca906fb37..78ed1ad3988 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsCustomView.ts @@ -136,7 +136,7 @@ export class InlineEditsCustomView extends Disposable implements IInlineEditsVie const { lineWidth, lineWidthBelow, lineWidthAbove, startContentLeftOffset, endContentLeftOffset } = contentState.read(reader); const contentLeft = this._editorObs.layoutInfoContentLeft.read(reader); - const lineHeight = this._editorObs.getOption(EditorOption.lineHeight).read(reader); + const lineHeight = this._editorObs.observeLineHeightForLine(startLineNumber).read(reader); const scrollTop = this._editorObs.scrollTop.read(reader); const scrollLeft = this._editorObs.scrollLeft.read(reader); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts index 2a681756bf4..5eb8cb5f67d 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts @@ -13,7 +13,6 @@ import { asCssVariable } from '../../../../../../../platform/theme/common/colorU import { ICodeEditor } from '../../../../../../browser/editorBrowser.js'; import { ObservableCodeEditor, observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; import { LineSource, renderLines, RenderOptions } from '../../../../../../browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; -import { EditorOption } from '../../../../../../common/config/editorOptions.js'; import { Rect } from '../../../../../../common/core/2d/rect.js'; import { Position } from '../../../../../../common/core/position.js'; import { Range } from '../../../../../../common/core/range.js'; @@ -54,13 +53,14 @@ export class InlineEditsInsertionView extends Disposable implements IInlineEdits }); private readonly _trimVertically = derived(this, reader => { - const text = this._state.read(reader)?.text; + const state = this._state.read(reader); + const text = state?.text; if (!text || text.trim() === '') { return { topOffset: 0, bottomOffset: 0, linesTop: 0, linesBottom: 0 }; } // Adjust for leading/trailing newlines - const lineHeight = this._editor.getOption(EditorOption.lineHeight); + const lineHeight = this._editor.getLineHeightForPosition(new Position(state.lineNumber, 1)); const eol = this._editor.getModel()!.getEOL(); let linesTop = 0; let linesBottom = 0; diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts index e014a42f695..060be8a3543 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts @@ -131,7 +131,15 @@ export class InlineEditsLineReplacementView extends Disposable implements IInlin const { prefixLeftOffset } = maxPrefixTrim; const { requiredWidth } = modifiedLines; - const lineHeight = this._editor.getOption(EditorOption.lineHeight).read(reader); + const originalLineHeights = this._editor.observeLineHeightsForLineRange(edit.originalRange).read(reader); + const modifiedLineHeights = (() => { + const lineHeights = originalLineHeights.slice(0, edit.modifiedRange.length); + while (lineHeights.length < edit.modifiedRange.length) { + lineHeights.push(originalLineHeights[originalLineHeights.length - 1]); + } + return lineHeights; + })(); + const contentLeft = this._editor.layoutInfoContentLeft.read(reader); const verticalScrollbarWidth = this._editor.layoutInfoVerticalScrollbarWidth.read(reader); const scrollLeft = this._editor.scrollLeft.read(reader); @@ -159,7 +167,7 @@ export class InlineEditsLineReplacementView extends Disposable implements IInlin originalLinesOverlay.left, originalLinesOverlay.bottom, originalLinesOverlay.width, - edit.modifiedRange.length * lineHeight + modifiedLineHeights.reduce((sum, h) => sum + h, 0) ); const background = Rect.hull([originalLinesOverlay, modifiedLinesOverlay]); @@ -172,6 +180,7 @@ export class InlineEditsLineReplacementView extends Disposable implements IInlin background, lowerBackground, lowerText, + modifiedLineHeights, minContentWidthRequired: prefixLeftOffset + maxLineWidth + verticalScrollbarWidth, }; }); @@ -204,10 +213,9 @@ export class InlineEditsLineReplacementView extends Disposable implements IInlin const layoutProps = layout.read(reader); const contentLeft = this._editor.layoutInfoContentLeft.read(reader); - const lineHeight = this._editor.getOption(EditorOption.lineHeight).read(reader); - modifiedLineElements.lines.forEach(l => { + modifiedLineElements.lines.forEach((l, i) => { l.style.width = `${layoutProps.lowerText.width}px`; - l.style.height = `${lineHeight}px`; + l.style.height = `${layoutProps.modifiedLineHeights[i]}px`; l.style.position = 'relative'; }); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts index 592be28800f..1585373421d 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts @@ -16,7 +16,6 @@ import { ICodeEditor } from '../../../../../../browser/editorBrowser.js'; import { observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; import { Rect } from '../../../../../../common/core/2d/rect.js'; import { EmbeddedCodeEditorWidget } from '../../../../../../browser/widget/codeEditor/embeddedCodeEditorWidget.js'; -import { EditorOption } from '../../../../../../common/config/editorOptions.js'; import { OffsetRange } from '../../../../../../common/core/ranges/offsetRange.js'; import { Position } from '../../../../../../common/core/position.js'; import { Range } from '../../../../../../common/core/range.js'; @@ -289,7 +288,8 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit codeRect = codeRect.withMargin(VERTICAL_PADDING, HORIZONTAL_PADDING); } - const editHeight = this._editor.getOption(EditorOption.lineHeight) * inlineEdit.modifiedLineRange.length; + const previewLineHeights = this._previewEditorObs.observeLineHeightsForLineRange(inlineEdit.modifiedLineRange).read(reader); + const editHeight = previewLineHeights.reduce((acc, h) => acc + h, 0); const codeHeight = selectionBottom - selectionTop; const previewEditorHeight = Math.max(codeHeight, editHeight); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts index f30d563df5c..cf662a612be 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts @@ -48,7 +48,7 @@ export class InlineEditsWordInsertView extends Disposable implements IInlineEdit return undefined; } const contentLeft = this._editor.layoutInfoContentLeft.read(reader); - const lineHeight = this._editor.getOption(EditorOption.lineHeight).read(reader); + const lineHeight = this._editor.observeLineHeightForPosition(this._edit.range.getStartPosition()).read(reader); const w = this._editor.getOption(EditorOption.fontInfo).read(reader).typicalHalfwidthCharacterWidth; const width = this._edit.text.length * w + 5; diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts index 93d45294f36..97f90697f6e 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts @@ -71,6 +71,7 @@ export class InlineEditsWordReplacementView extends Disposable implements IInlin const res = renderLines(new LineSource([tokens]), RenderOptions.fromEditor(this._editor.editor).withSetWidth(false).withScrollBeyondLastColumn(0), [], this._line, true); this._line.style.width = `${res.minWidthInPx}px`; }); + const modifiedLineHeight = this._editor.observeLineHeightForPosition(this._edit.range.getStartPosition()); this._layout = derived(this, reader => { this._renderTextEffect.read(reader); const widgetStart = this._start.read(reader); @@ -81,7 +82,7 @@ export class InlineEditsWordReplacementView extends Disposable implements IInlin return undefined; } - const lineHeight = this._editor.getOption(EditorOption.lineHeight).read(reader); + const lineHeight = modifiedLineHeight.read(reader); const scrollLeft = this._editor.scrollLeft.read(reader); const w = this._editor.getOption(EditorOption.fontInfo).read(reader).typicalHalfwidthCharacterWidth; From d1d42604e23a6a02061d2b38de21029f648b8c53 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 11 Jun 2025 11:00:48 +0200 Subject: [PATCH 187/236] prompt file watching: handle external folders (#251191) --- .../promptSyntax/utils/promptFilesLocator.ts | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts index fc1c7ab16be..ee3d3298130 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.ts @@ -59,30 +59,46 @@ export class PromptFilesLocator extends Disposable { } public createFilesUpdatedEvent(type: PromptsType): { readonly event: Event; dispose: () => void } { - const disoposables = new DisposableStore(); - const eventEmitter = disoposables.add(new Emitter()); - const key = getPromptFileLocationsConfigKey(type); + const disposables = new DisposableStore(); + const eventEmitter = disposables.add(new Emitter()); + const userDataFolder = this.userDataService.currentProfile.promptsHome; - let parentFolders = this.getLocalParentFolders(type).map(folder => folder.parent); - disoposables.add(this.configService.onDidChangeConfiguration(e => { + const key = getPromptFileLocationsConfigKey(type); + let parentFolders = this.getLocalParentFolders(type); + + const externalFolderWatchers = disposables.add(new DisposableStore()); + const updateExternalFolderWatchers = () => { + externalFolderWatchers.clear(); + for (const folder of parentFolders) { + if (!this.workspaceService.getWorkspaceFolder(folder.parent)) { + // if the folder is not part of the workspace, we need to watch it + const recursive = folder.filePattern !== undefined; + externalFolderWatchers.add(this.fileService.watch(folder.parent, { recursive, excludes: [] })); + } + } + }; + updateExternalFolderWatchers(); + disposables.add(this.configService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(key)) { - parentFolders = this.getLocalParentFolders(type).map(folder => folder.parent); + parentFolders = this.getLocalParentFolders(type); + updateExternalFolderWatchers(); eventEmitter.fire(); } })); - disoposables.add(this.fileService.onDidFilesChange(e => { + disposables.add(this.fileService.onDidFilesChange(e => { if (e.contains(userDataFolder)) { eventEmitter.fire(); return; } - if (parentFolders.some(folder => e.affects(folder))) { + if (parentFolders.some(folder => folder.filePattern !== undefined ? e.affects(folder.parent) : e.contains(folder.parent))) { eventEmitter.fire(); return; } })); - disoposables.add(this.fileService.watch(userDataFolder)); - return { event: eventEmitter.event, dispose: () => disoposables.dispose() }; + disposables.add(this.fileService.watch(userDataFolder)); + + return { event: eventEmitter.event, dispose: () => disposables.dispose() }; } /** From f91d77fc7c53659a5666d6f10979697942983071 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 11 Jun 2025 11:07:04 +0200 Subject: [PATCH 188/236] debt - make `vscode.executeDocumentSymbolProvider` very correct wrt what it returns (#251190) --- .../api/common/extHostApiCommands.ts | 33 ++++------ src/vs/workbench/api/common/extHostTypes.ts | 62 ++++++++++++++----- .../test/browser/extHostApiCommands.test.ts | 3 +- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 436e3505751..12d2a2bf41f 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -41,28 +41,21 @@ const newCommands: ApiCommand[] = [ if (isFalsyOrEmpty(value)) { return undefined; } - class MergedInfo extends types.SymbolInformation implements vscode.DocumentSymbol { - static to(symbol: languages.DocumentSymbol): MergedInfo { - const res = new MergedInfo( - symbol.name, - typeConverters.SymbolKind.to(symbol.kind), - symbol.containerName || '', - new types.Location(apiArgs[0], typeConverters.Range.to(symbol.range)) - ); - res.detail = symbol.detail; - res.range = res.location.range; - res.selectionRange = typeConverters.Range.to(symbol.selectionRange); - res.children = symbol.children ? symbol.children.map(MergedInfo.to) : []; - return res; - } - detail!: string; - range!: vscode.Range; - selectionRange!: vscode.Range; - children!: vscode.DocumentSymbol[]; - override containerName: string = ''; + function wrap(symbol: languages.DocumentSymbol): types.SymbolInformationAndDocumentSymbol { + return new types.SymbolInformationAndDocumentSymbol( + symbol.name, + typeConverters.SymbolKind.to(symbol.kind), + symbol.detail, + symbol.containerName || '', + apiArgs[0], + typeConverters.Range.to(symbol.range), + typeConverters.Range.to(symbol.selectionRange), + symbol.children ? symbol.children.map(wrap) : [] + ); } - return value.map(MergedInfo.to); + + return value.map(wrap); }) ), diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index d729adf4034..8984ceb7d0b 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1383,19 +1383,8 @@ export class SymbolInformation { } } -@es5ClassCompat -export class DocumentSymbol { - - static validate(candidate: DocumentSymbol): void { - if (!candidate.name) { - throw new Error('name must not be falsy'); - } - if (!candidate.range.contains(candidate.selectionRange)) { - throw new Error('selectionRange must be contained in fullRange'); - } - candidate.children?.forEach(DocumentSymbol.validate); - } +abstract class AbstractDocumentSymbol { name: string; detail: string; kind: SymbolKind; @@ -1411,11 +1400,56 @@ export class DocumentSymbol { this.range = range; this.selectionRange = selectionRange; this.children = []; - - DocumentSymbol.validate(this); } } +@es5ClassCompat +export class DocumentSymbol extends AbstractDocumentSymbol { + + static validate(candidate: DocumentSymbol): void { + if (!candidate.name) { + throw new Error('name must not be falsy'); + } + if (!candidate.range.contains(candidate.selectionRange)) { + throw new Error('selectionRange must be contained in fullRange'); + } + candidate.children?.forEach(DocumentSymbol.validate); + } + + constructor(name: string, detail: string, kind: SymbolKind, range: Range, selectionRange: Range) { + super(name, detail, kind, range, selectionRange); + DocumentSymbol.validate(this); + } + + static override[Symbol.hasInstance](candidate: unknown): boolean { + if (!isObject(candidate)) { + throw new TypeError(); + } + return candidate instanceof AbstractDocumentSymbol + || candidate instanceof SymbolInformationAndDocumentSymbol; + } +} + +// This is a special type that's used from the `vscode.executeDocumentSymbolProvider` API +// command which implements both shapes, vscode.SymbolInformation _and_ vscode.DocumentSymbol +export class SymbolInformationAndDocumentSymbol extends SymbolInformation implements vscode.DocumentSymbol { + + detail: string; + range: vscode.Range; + selectionRange: vscode.Range; + children: vscode.DocumentSymbol[]; + override containerName: string; + + constructor(name: string, kind: vscode.SymbolKind, detail: string, containerName: string, uri: URI, range: Range, selectionRange: Range, children?: SymbolInformationAndDocumentSymbol[]) { + super(name, kind, containerName, new Location(uri, range)); + + this.containerName = containerName; + this.detail = detail; + this.range = range; + this.selectionRange = selectionRange; + this.children = children ?? []; + } +} export enum CodeActionTriggerKind { Invoke = 1, diff --git a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts index 2e10b368a64..34abb354e35 100644 --- a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts +++ b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts @@ -774,8 +774,9 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.strictEqual(values.length, 2); const [first, second] = values; assert.strictEqual(first instanceof types.SymbolInformation, true); - assert.strictEqual(first instanceof types.DocumentSymbol, false); + assert.strictEqual(first instanceof types.DocumentSymbol, true); assert.strictEqual(second instanceof types.SymbolInformation, true); + assert.strictEqual(second instanceof types.DocumentSymbol, true); assert.strictEqual(first.name, 'DocumentSymbol'); assert.strictEqual(first.children.length, 1); assert.strictEqual(second.name, 'SymbolInformation'); From 0ac8174fbcf3ac0bfb41b32e498d336f604dd9af Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Jun 2025 11:51:06 +0200 Subject: [PATCH 189/236] debt - reduce some explicit `any` use (#251182) --- src/vs/base/browser/markdownRenderer.ts | 2 +- .../browser/ui/breadcrumbs/breadcrumbsWidget.ts | 2 +- src/vs/base/browser/ui/grid/grid.ts | 2 +- src/vs/base/browser/ui/grid/gridview.ts | 2 +- src/vs/base/common/async.ts | 2 +- src/vs/base/common/dataTransfer.ts | 2 +- src/vs/base/common/jsonEdit.ts | 2 +- .../observableInternal/experimental/utils.ts | 2 +- src/vs/base/common/product.ts | 2 +- src/vs/base/common/worker/webWorkerBootstrap.ts | 2 +- src/vs/editor/common/editorCommon.ts | 2 +- .../browser/model/inlineCompletionsSource.ts | 6 +++--- .../semanticTokens/common/getSemanticTokens.ts | 2 +- .../instantiation/common/instantiationService.ts | 2 +- src/vs/platform/list/browser/listService.ts | 7 ------- .../remote/browser/browserSocketFactory.ts | 14 +++++++------- .../remote/common/remoteAuthorityResolver.ts | 4 ++-- src/vs/platform/terminal/node/ptyService.ts | 2 +- src/vs/platform/userDataSync/common/content.ts | 2 +- src/vs/server/node/remoteExtensionsScanner.ts | 14 +++++++------- .../api/browser/mainThreadConfiguration.ts | 6 +++--- src/vs/workbench/api/common/extHost.protocol.ts | 7 ++++--- .../workbench/api/common/extHostConfiguration.ts | 4 ++-- .../api/common/extHostLanguageModelTools.ts | 2 +- .../workbench/api/common/extHostLanguageModels.ts | 2 +- .../workbench/api/common/extHostNotebookKernels.ts | 4 ++-- .../api/common/extHostNotebookRenderers.ts | 2 +- src/vs/workbench/api/common/extHostSCM.ts | 2 +- .../workbench/api/common/extHostTypeConverters.ts | 2 +- src/vs/workbench/api/common/extHostTypes.ts | 4 ++-- .../api/common/extHostWebviewMessaging.ts | 6 +++--- .../browser/parts/editor/breadcrumbsControl.ts | 2 +- .../browser/parts/editor/breadcrumbsPicker.ts | 2 +- .../contrib/debug/browser/callStackView.ts | 2 +- .../configuration/browser/configurationService.ts | 12 ++++++------ .../configuration/common/configurationEditing.ts | 2 +- .../services/configuration/common/jsonEditing.ts | 2 +- .../browser/baseConfigurationResolverService.ts | 4 ++-- .../common/configurationResolver.ts | 4 ++-- .../services/themes/common/themeConfiguration.ts | 2 +- 40 files changed, 71 insertions(+), 77 deletions(-) diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 2cb748afcdf..54e6fd71b87 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -323,7 +323,7 @@ function activateLink(markdown: IMarkdownString, options: MarkdownRenderOptions, } function uriMassage(markdown: IMarkdownString, part: string): string { - let data: any; + let data: unknown; try { data = parse(decodeURIComponent(part)); } catch (e) { diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index a4cb3361f9d..01e522130a9 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -32,7 +32,7 @@ export interface IBreadcrumbsItemEvent { type: 'select' | 'focus'; item: BreadcrumbsItem; node: HTMLElement; - payload: any; + payload: unknown; } export class BreadcrumbsWidget { diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index cd7aabf6cfb..882c2e980fb 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -749,7 +749,7 @@ export interface IViewDeserializer { export interface ISerializedLeafNode { type: 'leaf'; - data: any; + data: unknown; size: number; visible?: boolean; maximized?: boolean; diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index 09452c14992..bf3d737867f 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -145,7 +145,7 @@ export interface IViewDeserializer { export interface ISerializedLeafNode { type: 'leaf'; - data: any; + data: unknown; size: number; visible?: boolean; maximized?: boolean; diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index ca964301327..fb72d242be6 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -1743,7 +1743,7 @@ export class DeferredPromise { private completeCallback!: ValueCallback; private errorCallback!: (err: unknown) => void; - private outcome?: { outcome: DeferredOutcome.Rejected; value: any } | { outcome: DeferredOutcome.Resolved; value: T }; + private outcome?: { outcome: DeferredOutcome.Rejected; value: unknown } | { outcome: DeferredOutcome.Resolved; value: T }; public get isRejected() { return this.outcome?.outcome === DeferredOutcome.Rejected; diff --git a/src/vs/base/common/dataTransfer.ts b/src/vs/base/common/dataTransfer.ts index 3ce5770c57f..9f504a20c5a 100644 --- a/src/vs/base/common/dataTransfer.ts +++ b/src/vs/base/common/dataTransfer.ts @@ -19,7 +19,7 @@ export interface IDataTransferItem { id?: string; asString(): Thenable; asFile(): IDataTransferFile | undefined; - value: any; + value: unknown; } export function createStringDataTransferItem(stringOrPromise: string | Promise, id?: string): IDataTransferItem { diff --git a/src/vs/base/common/jsonEdit.ts b/src/vs/base/common/jsonEdit.ts index c699dbcb569..b3ae24ae69a 100644 --- a/src/vs/base/common/jsonEdit.ts +++ b/src/vs/base/common/jsonEdit.ts @@ -11,7 +11,7 @@ export function removeProperty(text: string, path: JSONPath, formattingOptions: return setProperty(text, path, undefined, formattingOptions); } -export function setProperty(text: string, originalPath: JSONPath, value: any, formattingOptions: FormattingOptions, getInsertionIndex?: (properties: string[]) => number): Edit[] { +export function setProperty(text: string, originalPath: JSONPath, value: unknown, formattingOptions: FormattingOptions, getInsertionIndex?: (properties: string[]) => number): Edit[] { const path = originalPath.slice(); const errors: ParseError[] = []; const root = parseTree(text, errors); diff --git a/src/vs/base/common/observableInternal/experimental/utils.ts b/src/vs/base/common/observableInternal/experimental/utils.ts index 3a64aae46f2..a9038ac0946 100644 --- a/src/vs/base/common/observableInternal/experimental/utils.ts +++ b/src/vs/base/common/observableInternal/experimental/utils.ts @@ -22,7 +22,7 @@ export function latestChangedValue[]>(owner: DebugOwn } let hasLastChangedValue = false; - let lastChangedValue: any = undefined; + let lastChangedValue: unknown = undefined; const result = observableFromEvent(owner, cb => { const store = new DisposableStore(); diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index c3df2a13a97..653a85bb523 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -11,7 +11,7 @@ export interface IBuiltInExtension { readonly name: string; readonly version: string; readonly repo: string; - readonly metadata: any; + readonly metadata: unknown; } export interface IProductWalkthrough { diff --git a/src/vs/base/common/worker/webWorkerBootstrap.ts b/src/vs/base/common/worker/webWorkerBootstrap.ts index dce9e79b757..946c3e98be9 100644 --- a/src/vs/base/common/worker/webWorkerBootstrap.ts +++ b/src/vs/base/common/worker/webWorkerBootstrap.ts @@ -6,7 +6,7 @@ import { IWebWorkerServerRequestHandler, IWebWorkerServerRequestHandlerFactory, WebWorkerServer } from './webWorker.js'; type MessageEvent = { - data: any; + data: unknown; }; declare const globalThis: { diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 3d0210dc4c4..ba900f3a584 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -153,7 +153,7 @@ export interface IContentSizeChangedEvent { export interface ITriggerEditorOperationEvent { source: string | null | undefined; handlerId: string; - payload: any; + payload: unknown; } export interface INewScrollPosition { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts index 499d0e0122d..029c0ec23a2 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts @@ -57,7 +57,7 @@ export class InlineCompletionsSource extends Disposable { this._loggingEnabled = observableConfigValue('editor.inlineSuggest.logFetch', false, this._configurationService).recomputeInitiallyAndOnChange(this._store); this._structuredFetchLogger = this._register(this._instantiationService.createInstance(StructuredLogger.cast< { kind: 'start'; requestId: number; context: unknown } & IRecordableEditorLogEntry - | { kind: 'end'; error: any; durationMs: number; result: unknown; requestId: number } & IRecordableLogEntry + | { kind: 'end'; error: unknown; durationMs: number; result: unknown; requestId: number } & IRecordableLogEntry >(), 'editor.inlineSuggest.logFetch.commandId' )); @@ -105,7 +105,7 @@ export class InlineCompletionsSource extends Disposable { private _log(entry: { sourceId: string; kind: 'start'; requestId: number; context: unknown } & IRecordableEditorLogEntry - | { sourceId: string; kind: 'end'; error: any; durationMs: number; result: unknown; requestId: number } & IRecordableLogEntry + | { sourceId: string; kind: 'end'; error: unknown; durationMs: number; result: unknown; requestId: number } & IRecordableLogEntry ) { if (this._loggingEnabled.get()) { this._logService.info(formatRecordableLogEntry(entry)); @@ -159,7 +159,7 @@ export class InlineCompletionsSource extends Disposable { const startTime = new Date(); let providerResult: InlineCompletionProviderResult | undefined = undefined; - let error: any = undefined; + let error: unknown = undefined; try { providerResult = await provideInlineCompletions( providers, diff --git a/src/vs/editor/contrib/semanticTokens/common/getSemanticTokens.ts b/src/vs/editor/contrib/semanticTokens/common/getSemanticTokens.ts index cd7cbd3e7c1..137abcc4826 100644 --- a/src/vs/editor/contrib/semanticTokens/common/getSemanticTokens.ts +++ b/src/vs/editor/contrib/semanticTokens/common/getSemanticTokens.ts @@ -48,7 +48,7 @@ export async function getDocumentSemanticTokens(registry: LanguageFeatureRegistr // Get tokens from all providers at the same time. const results = await Promise.all(providers.map(async (provider) => { let result: SemanticTokens | SemanticTokensEdits | null | undefined; - let error: any = null; + let error: unknown = null; try { result = await provider.provideDocumentSemanticTokens(model, (provider === lastProvider ? lastResultId : null), token); } catch (err) { diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index 86099cc8b66..77950178326 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -119,7 +119,7 @@ export class InstantiationService implements IInstantiationService { this._throwIfDisposed(); let _trace: Trace; - let result: any; + let result: unknown; if (ctorOrDescriptor instanceof SyncDescriptor) { _trace = Trace.traceCreation(this._enableTracing, ctorOrDescriptor.ctor); result = this._createInstance(ctorOrDescriptor.ctor, ctorOrDescriptor.staticArguments.concat(rest), _trace); diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 94c2acead57..27b1a2be4da 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -646,13 +646,6 @@ export class WorkbenchTable extends Table { } } -export interface IOpenResourceOptions { - editorOptions: IEditorOptions; - sideBySide: boolean; - element: any; - payload: any; -} - export interface IOpenEvent { editorOptions: IEditorOptions; sideBySide: boolean; diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts index 7aea766301a..0f01fc06138 100644 --- a/src/vs/platform/remote/browser/browserSocketFactory.ts +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -33,16 +33,16 @@ export interface IWebSocketCloseEvent { /** * Underlying event. */ - readonly event: any | undefined; + readonly event: unknown | undefined; } export interface IWebSocket { readonly onData: Event; readonly onOpen: Event; readonly onClose: Event; - readonly onError: Event; + readonly onError: Event; - traceSocketEvent?(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void; + traceSocketEvent?(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | unknown): void; send(data: ArrayBuffer | ArrayBufferView): void; close(): void; } @@ -58,7 +58,7 @@ class BrowserWebSocket extends Disposable implements IWebSocket { private readonly _onClose = this._register(new Emitter()); public readonly onClose = this._onClose.event; - private readonly _onError = this._register(new Emitter()); + private readonly _onError = this._register(new Emitter()); public readonly onError = this._onError.event; private readonly _debugLabel: string; @@ -127,7 +127,7 @@ class BrowserWebSocket extends Disposable implements IWebSocket { // delay the error event processing in the hope of receiving a close event // with more information - let pendingErrorEvent: any | null = null; + let pendingErrorEvent: unknown | null = null; const sendPendingErrorNow = () => { const err = pendingErrorEvent; @@ -137,13 +137,13 @@ class BrowserWebSocket extends Disposable implements IWebSocket { const errorRunner = this._register(new RunOnceScheduler(sendPendingErrorNow, 0)); - const sendErrorSoon = (err: any) => { + const sendErrorSoon = (err: unknown) => { errorRunner.cancel(); pendingErrorEvent = err; errorRunner.schedule(); }; - const sendErrorNow = (err: any) => { + const sendErrorNow = (err: unknown) => { errorRunner.cancel(); pendingErrorEvent = err; sendPendingErrorNow(); diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts index 938bbd80c48..56fb35c3f67 100644 --- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -120,11 +120,11 @@ export class RemoteAuthorityResolverError extends ErrorNoTelemetry { public readonly _message: string | undefined; public readonly _code: RemoteAuthorityResolverErrorCode; - public readonly _detail: any; + public readonly _detail: unknown; public isHandled: boolean; - constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: any) { + constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: unknown) { super(message); this._message = message; diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 01e98822f2f..a43f323716b 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -49,7 +49,7 @@ export function traceRpc(_target: any, key: string, descriptor: any) { if (this.traceRpcArgs.simulatedLatency) { await timeout(this.traceRpcArgs.simulatedLatency); } - let result: any; + let result: unknown; try { result = await fn.apply(this, args); } catch (e) { diff --git a/src/vs/platform/userDataSync/common/content.ts b/src/vs/platform/userDataSync/common/content.ts index 77a6f04dffa..3f3af755f14 100644 --- a/src/vs/platform/userDataSync/common/content.ts +++ b/src/vs/platform/userDataSync/common/content.ts @@ -8,7 +8,7 @@ import { setProperty } from '../../../base/common/jsonEdit.js'; import { FormattingOptions } from '../../../base/common/jsonFormatter.js'; -export function edit(content: string, originalPath: JSONPath, value: any, formattingOptions: FormattingOptions): string { +export function edit(content: string, originalPath: JSONPath, value: unknown, formattingOptions: FormattingOptions): string { const edit = setProperty(content, originalPath, value, formattingOptions)[0]; if (edit) { content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length); diff --git a/src/vs/server/node/remoteExtensionsScanner.ts b/src/vs/server/node/remoteExtensionsScanner.ts index 1bd6cf68c1d..bbc82fd06bc 100644 --- a/src/vs/server/node/remoteExtensionsScanner.ts +++ b/src/vs/server/node/remoteExtensionsScanner.ts @@ -11,7 +11,7 @@ import * as performance from '../../base/common/performance.js'; import { Event } from '../../base/common/event.js'; import { IURITransformer, transformOutgoingURIs } from '../../base/common/uriIpc.js'; import { IServerChannel } from '../../base/parts/ipc/common/ipc.js'; -import { ContextKeyDefinedExpr, ContextKeyEqualsExpr, ContextKeyExpr, ContextKeyExpression, ContextKeyGreaterEqualsExpr, ContextKeyGreaterExpr, ContextKeyInExpr, ContextKeyNotEqualsExpr, ContextKeyNotExpr, ContextKeyNotInExpr, ContextKeyRegexExpr, ContextKeySmallerEqualsExpr, ContextKeySmallerExpr, IContextKeyExprMapper } from '../../platform/contextkey/common/contextkey.js'; +import { ContextKeyDefinedExpr, ContextKeyEqualsExpr, ContextKeyExpr, ContextKeyExpression, ContextKeyGreaterEqualsExpr, ContextKeyGreaterExpr, ContextKeyInExpr, ContextKeyNotEqualsExpr, ContextKeyNotExpr, ContextKeyNotInExpr, ContextKeyRegexExpr, ContextKeySmallerEqualsExpr, ContextKeySmallerExpr, ContextKeyValue, IContextKeyExprMapper } from '../../platform/contextkey/common/contextkey.js'; import { IExtensionGalleryService, IExtensionManagementService, InstallExtensionSummary, InstallOptions } from '../../platform/extensionManagement/common/extensionManagement.js'; import { ExtensionManagementCLI } from '../../platform/extensionManagement/common/extensionManagementCLI.js'; import { IExtensionsScannerService, toExtensionDescription } from '../../platform/extensionManagement/common/extensionsScannerService.js'; @@ -238,30 +238,30 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS mapNot(key: string): ContextKeyExpression { return ContextKeyNotExpr.create(key); } - mapEquals(key: string, value: any): ContextKeyExpression { + mapEquals(key: string, value: ContextKeyValue): ContextKeyExpression { if (key === 'resourceScheme' && typeof value === 'string') { return ContextKeyEqualsExpr.create(key, _mapResourceSchemeValue(value, false)); } else { return ContextKeyEqualsExpr.create(key, value); } } - mapNotEquals(key: string, value: any): ContextKeyExpression { + mapNotEquals(key: string, value: ContextKeyValue): ContextKeyExpression { if (key === 'resourceScheme' && typeof value === 'string') { return ContextKeyNotEqualsExpr.create(key, _mapResourceSchemeValue(value, false)); } else { return ContextKeyNotEqualsExpr.create(key, value); } } - mapGreater(key: string, value: any): ContextKeyExpression { + mapGreater(key: string, value: ContextKeyValue): ContextKeyExpression { return ContextKeyGreaterExpr.create(key, value); } - mapGreaterEquals(key: string, value: any): ContextKeyExpression { + mapGreaterEquals(key: string, value: ContextKeyValue): ContextKeyExpression { return ContextKeyGreaterEqualsExpr.create(key, value); } - mapSmaller(key: string, value: any): ContextKeyExpression { + mapSmaller(key: string, value: ContextKeyValue): ContextKeyExpression { return ContextKeySmallerExpr.create(key, value); } - mapSmallerEquals(key: string, value: any): ContextKeyExpression { + mapSmallerEquals(key: string, value: ContextKeyValue): ContextKeyExpression { return ContextKeySmallerEqualsExpr.create(key, value); } mapRegex(key: string, regexp: RegExp | null): ContextKeyRegexExpr { diff --git a/src/vs/workbench/api/browser/mainThreadConfiguration.ts b/src/vs/workbench/api/browser/mainThreadConfiguration.ts index 86891475af3..07c29c26ee9 100644 --- a/src/vs/workbench/api/browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/browser/mainThreadConfiguration.ts @@ -45,7 +45,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { this._configurationListener.dispose(); } - $updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: any, overrides: IConfigurationOverrides | undefined, scopeToLanguage: boolean | undefined): Promise { + $updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: unknown, overrides: IConfigurationOverrides | undefined, scopeToLanguage: boolean | undefined): Promise { overrides = { resource: overrides?.resource ? URI.revive(overrides.resource) : undefined, overrideIdentifier: overrides?.overrideIdentifier }; return this.writeConfiguration(target, key, value, overrides, scopeToLanguage); } @@ -55,7 +55,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { return this.writeConfiguration(target, key, undefined, overrides, scopeToLanguage); } - private writeConfiguration(target: ConfigurationTarget | null, key: string, value: any, overrides: IConfigurationOverrides, scopeToLanguage: boolean | undefined): Promise { + private writeConfiguration(target: ConfigurationTarget | null, key: string, value: unknown, overrides: IConfigurationOverrides, scopeToLanguage: boolean | undefined): Promise { target = target !== null && target !== undefined ? target : this.deriveConfigurationTarget(key, overrides); const configurationValue = this.configurationService.inspect(key, overrides); switch (target) { @@ -72,7 +72,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { } } - private _updateValue(key: string, value: any, configurationTarget: ConfigurationTarget, overriddenValue: any | undefined, overrides: IConfigurationOverrides, scopeToLanguage: boolean | undefined): Promise { + private _updateValue(key: string, value: unknown, configurationTarget: ConfigurationTarget, overriddenValue: any | undefined, overrides: IConfigurationOverrides, scopeToLanguage: boolean | undefined): Promise { overrides = scopeToLanguage === true ? overrides : scopeToLanguage === false ? { resource: overrides.resource } : overrides.overrideIdentifier && overriddenValue !== undefined ? overrides diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index a4e53cbd021..8a5d067160d 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -68,6 +68,7 @@ import * as notebookCommon from '../../contrib/notebook/common/notebookCommon.js import { CellExecutionUpdateType } from '../../contrib/notebook/common/notebookExecutionService.js'; import { ICellExecutionComplete, ICellExecutionStateUpdate } from '../../contrib/notebook/common/notebookExecutionStateService.js'; import { ICellRange } from '../../contrib/notebook/common/notebookRange.js'; +import { ISCMHistoryOptions } from '../../contrib/scm/common/history.js'; import { InputValidationType } from '../../contrib/scm/common/scm.js'; import { IWorkspaceSymbol, NotebookPriorityInfo } from '../../contrib/search/common/search.js'; import { IRawClosedNotebookFileMatch } from '../../contrib/search/common/searchNotebookHelpers.js'; @@ -203,7 +204,7 @@ export interface MainThreadSecretStateShape extends IDisposable { } export interface MainThreadConfigurationShape extends IDisposable { - $updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: any, overrides: IConfigurationOverrides | undefined, scopeToLanguage: boolean | undefined): Promise; + $updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: unknown, overrides: IConfigurationOverrides | undefined, scopeToLanguage: boolean | undefined): Promise; $removeConfigurationOption(target: ConfigurationTarget | null, key: string, overrides: IConfigurationOverrides | undefined, scopeToLanguage: boolean | undefined): Promise; } @@ -1409,7 +1410,7 @@ export interface ExtHostLanguageModelToolsShape { $invokeTool(dto: IToolInvocation, token: CancellationToken): Promise | SerializableObjectWithBuffers>>; $countTokensForInvocation(callId: string, input: string, token: CancellationToken): Promise; - $prepareToolInvocation(toolId: string, parameters: any, token: CancellationToken): Promise; + $prepareToolInvocation(toolId: string, parameters: unknown, token: CancellationToken): Promise; } export interface MainThreadUrlsShape extends IDisposable { @@ -2570,7 +2571,7 @@ export interface ExtHostSCMShape { $validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string | IMarkdownString, number] | undefined>; $setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise; $provideHistoryItemRefs(sourceControlHandle: number, historyItemRefs: string[] | undefined, token: CancellationToken): Promise; - $provideHistoryItems(sourceControlHandle: number, options: any, token: CancellationToken): Promise; + $provideHistoryItems(sourceControlHandle: number, options: ISCMHistoryOptions, token: CancellationToken): Promise; $provideHistoryItemChanges(sourceControlHandle: number, historyItemId: string, historyItemParentId: string | undefined, token: CancellationToken): Promise; $resolveHistoryItemChatContext(sourceControlHandle: number, historyItemId: string, token: CancellationToken): Promise; $resolveHistoryItemRefsCommonAncestor(sourceControlHandle: number, historyItemRefs: string[], token: CancellationToken): Promise; diff --git a/src/vs/workbench/api/common/extHostConfiguration.ts b/src/vs/workbench/api/common/extHostConfiguration.ts index f0d9124a0da..425d303ff88 100644 --- a/src/vs/workbench/api/common/extHostConfiguration.ts +++ b/src/vs/workbench/api/common/extHostConfiguration.ts @@ -247,7 +247,7 @@ export class ExtHostConfigProvider { } return result; }, - update: (key: string, value: any, extHostConfigurationTarget: ExtHostConfigurationTarget | boolean, scopeToLanguage?: boolean) => { + update: (key: string, value: unknown, extHostConfigurationTarget: ExtHostConfigurationTarget | boolean, scopeToLanguage?: boolean) => { key = section ? `${section}.${key}` : key; const target = parseConfigurationTarget(extHostConfigurationTarget); if (value !== undefined) { @@ -299,7 +299,7 @@ export class ExtHostConfigProvider { set: (_target: any, property: PropertyKey, _value: any) => { throw new Error(`TypeError: Cannot assign to read only property '${String(property)}' of object`); }, deleteProperty: (_target: any, property: PropertyKey) => { throw new Error(`TypeError: Cannot delete read only property '${String(property)}' of object`); }, defineProperty: (_target: any, property: PropertyKey) => { throw new Error(`TypeError: Cannot define property '${String(property)}' for a readonly object`); }, - setPrototypeOf: (_target: any) => { throw new Error(`TypeError: Cannot set prototype for a readonly object`); }, + setPrototypeOf: (_target: unknown) => { throw new Error(`TypeError: Cannot set prototype for a readonly object`); }, isExtensible: () => false, preventExtensions: () => true }) : target; diff --git a/src/vs/workbench/api/common/extHostLanguageModelTools.ts b/src/vs/workbench/api/common/extHostLanguageModelTools.ts index bc1b1a263a2..f90a6a5d6e2 100644 --- a/src/vs/workbench/api/common/extHostLanguageModelTools.ts +++ b/src/vs/workbench/api/common/extHostLanguageModelTools.ts @@ -220,7 +220,7 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape return model; } - async $prepareToolInvocation(toolId: string, input: any, token: CancellationToken): Promise { + async $prepareToolInvocation(toolId: string, input: unknown, token: CancellationToken): Promise { const item = this._registeredTools.get(toolId); if (!item) { throw new Error(`Unknown tool ${toolId}`); diff --git a/src/vs/workbench/api/common/extHostLanguageModels.ts b/src/vs/workbench/api/common/extHostLanguageModels.ts index 2ab508631e7..f2fcab92ffc 100644 --- a/src/vs/workbench/api/common/extHostLanguageModels.ts +++ b/src/vs/workbench/api/common/extHostLanguageModels.ts @@ -263,7 +263,7 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { sendSoon({ index: fragment.index, part }); }); - let value: any; + let value: unknown; try { value = data.provider.provideLanguageModelResponse( diff --git a/src/vs/workbench/api/common/extHostNotebookKernels.ts b/src/vs/workbench/api/common/extHostNotebookKernels.ts index d96cbc78588..6e11a2c8d6b 100644 --- a/src/vs/workbench/api/common/extHostNotebookKernels.ts +++ b/src/vs/workbench/api/common/extHostNotebookKernels.ts @@ -31,7 +31,7 @@ interface IKernelData { extensionId: ExtensionIdentifier; controller: vscode.NotebookController; onDidChangeSelection: Emitter<{ selected: boolean; notebook: vscode.NotebookDocument }>; - onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor; message: any }>; + onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor; message: unknown }>; associatedNotebooks: ResourceMap; } @@ -135,7 +135,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { let isDisposed = false; const onDidChangeSelection = new Emitter<{ selected: boolean; notebook: vscode.NotebookDocument }>(); - const onDidReceiveMessage = new Emitter<{ editor: vscode.NotebookEditor; message: any }>(); + const onDidReceiveMessage = new Emitter<{ editor: vscode.NotebookEditor; message: unknown }>(); const data: INotebookKernelDto2 = { id: createKernelId(extension.identifier, id), diff --git a/src/vs/workbench/api/common/extHostNotebookRenderers.ts b/src/vs/workbench/api/common/extHostNotebookRenderers.ts index 56c273a7b0d..27035ab4590 100644 --- a/src/vs/workbench/api/common/extHostNotebookRenderers.ts +++ b/src/vs/workbench/api/common/extHostNotebookRenderers.ts @@ -12,7 +12,7 @@ import * as vscode from 'vscode'; export class ExtHostNotebookRenderers implements ExtHostNotebookRenderersShape { - private readonly _rendererMessageEmitters = new Map>(); + private readonly _rendererMessageEmitters = new Map>(); private readonly proxy: MainThreadNotebookRenderersShape; constructor(mainContext: IMainContext, private readonly _extHostNotebook: ExtHostNotebookController) { diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index eb77029e5f4..236a32470f5 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -1085,7 +1085,7 @@ export class ExtHostSCM implements ExtHostSCMShape { } } - async $provideHistoryItems(sourceControlHandle: number, options: any, token: CancellationToken): Promise { + async $provideHistoryItems(sourceControlHandle: number, options: vscode.SourceControlHistoryOptions, token: CancellationToken): Promise { try { const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; const historyItems = await historyProvider?.provideHistoryItems(options, token); diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 02f78542290..35e2cc93dea 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -406,7 +406,7 @@ export namespace MarkdownString { if (!part) { return part; } - let data: any; + let data: unknown; try { data = parse(part); } catch (e) { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 8984ceb7d0b..0f79fd6e814 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -584,9 +584,9 @@ export class RemoteAuthorityResolverError extends Error { public readonly _message: string | undefined; public readonly _code: RemoteAuthorityResolverErrorCode; - public readonly _detail: any; + public readonly _detail: unknown; - constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: any) { + constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: unknown) { super(message); this._message = message; diff --git a/src/vs/workbench/api/common/extHostWebviewMessaging.ts b/src/vs/workbench/api/common/extHostWebviewMessaging.ts index 49f0fa06c99..97a9de1b30c 100644 --- a/src/vs/workbench/api/common/extHostWebviewMessaging.ts +++ b/src/vs/workbench/api/common/extHostWebviewMessaging.ts @@ -20,7 +20,7 @@ class ArrayBufferSet { } export function serializeWebviewMessage( - message: any, + message: unknown, options: { serializeBuffersForPostMessage?: boolean } ): { message: string; buffers: VSBuffer[] } { if (options.serializeBuffersForPostMessage) { @@ -83,7 +83,7 @@ function getTypedArrayType(value: ArrayBufferView): extHostProtocol.WebviewMessa return undefined; } -export function deserializeWebviewMessage(jsonMessage: string, buffers: VSBuffer[]): { message: any; arrayBuffers: ArrayBuffer[] } { +export function deserializeWebviewMessage(jsonMessage: string, buffers: VSBuffer[]): { message: unknown; arrayBuffers: ArrayBuffer[] } { const arrayBuffers: ArrayBuffer[] = buffers.map(buffer => { const arrayBuffer = new ArrayBuffer(buffer.byteLength); const uint8Array = new Uint8Array(arrayBuffer); @@ -117,6 +117,6 @@ export function deserializeWebviewMessage(jsonMessage: string, buffers: VSBuffer return value; }; - const message = JSON.parse(jsonMessage, reviver); + const message = JSON.parse(jsonMessage, reviver) as unknown; return { message, arrayBuffers }; } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 838d74fd56f..a72236d0c57 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -576,7 +576,7 @@ export class BreadcrumbsControl { } } - private _getEditorGroup(data: object): SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE | undefined { + private _getEditorGroup(data: unknown): SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE | undefined { if (data === BreadcrumbsControl.Payload_RevealAside) { return SIDE_GROUP; } else if (data === BreadcrumbsControl.Payload_Reveal) { diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index e01631d1552..fd784e6f69b 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -82,7 +82,7 @@ export abstract class BreadcrumbsPicker { setTimeout(() => this._tree.dispose(), 0); // tree cannot be disposed while being opened... } - async show(input: any, maxHeight: number, width: number, arrowSize: number, arrowOffset: number): Promise { + async show(input: FileElement | OutlineElement2, maxHeight: number, width: number, arrowSize: number, arrowOffset: number): Promise { const theme = this._themeService.getColorTheme(); const color = theme.getColor(breadcrumbsPickerBackground); diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index a3083b15868..e853bcdeed5 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -74,7 +74,7 @@ function assignStackFrameContext(element: StackFrame, context: any) { return context; } -export function getContext(element: CallStackItem | null): any { +export function getContext(element: CallStackItem | null) { if (element instanceof StackFrame) { return assignStackFrameContext(element, {}); } else if (element instanceof Thread) { diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index c56106ddd6a..e3715ce5097 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -332,10 +332,10 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat } updateValue(key: string, value: any): Promise; - updateValue(key: string, value: any, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides): Promise; - updateValue(key: string, value: any, target: ConfigurationTarget): Promise; - updateValue(key: string, value: any, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides, target: ConfigurationTarget, options?: IConfigurationUpdateOptions): Promise; - async updateValue(key: string, value: any, arg3?: any, arg4?: any, options?: any): Promise { + updateValue(key: string, value: unknown, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides): Promise; + updateValue(key: string, value: unknown, target: ConfigurationTarget): Promise; + updateValue(key: string, value: unknown, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides, target: ConfigurationTarget, options?: IConfigurationUpdateOptions): Promise; + async updateValue(key: string, value: unknown, arg3?: any, arg4?: any, options?: any): Promise { const overrides: IConfigurationUpdateOverrides | undefined = isConfigurationUpdateOverrides(arg3) ? arg3 : isConfigurationOverrides(arg3) ? { resource: arg3.resource, overrideIdentifiers: arg3.overrideIdentifier ? [arg3.overrideIdentifier] : undefined } : undefined; const target: ConfigurationTarget | undefined = overrides ? arg4 : arg3; @@ -996,7 +996,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat return validWorkspaceFolders; } - private async writeConfigurationValue(key: string, value: any, target: ConfigurationTarget, overrides: IConfigurationUpdateOverrides | undefined, options?: IConfigurationUpdateOverrides): Promise { + private async writeConfigurationValue(key: string, value: unknown, target: ConfigurationTarget, overrides: IConfigurationUpdateOverrides | undefined, options?: IConfigurationUpdateOverrides): Promise { if (!this.instantiationService) { throw new Error('Cannot write configuration because the configuration service is not yet ready to accept writes.'); } @@ -1080,7 +1080,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat } } - private deriveConfigurationTargets(key: string, value: any, inspect: IConfigurationValue): ConfigurationTarget[] { + private deriveConfigurationTargets(key: string, value: unknown, inspect: IConfigurationValue): ConfigurationTarget[] { if (equals(value, inspect.value)) { return []; } diff --git a/src/vs/workbench/services/configuration/common/configurationEditing.ts b/src/vs/workbench/services/configuration/common/configurationEditing.ts index 18f3c329745..1cbb3f351a6 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditing.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditing.ts @@ -112,7 +112,7 @@ export class ConfigurationEditingError extends ErrorNoTelemetry { export interface IConfigurationValue { key: string; - value: any; + value: unknown; } export interface IConfigurationEditingOptions extends IConfigurationUpdateOptions { diff --git a/src/vs/workbench/services/configuration/common/jsonEditing.ts b/src/vs/workbench/services/configuration/common/jsonEditing.ts index 41481d442c7..0dcef249fb7 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditing.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditing.ts @@ -25,7 +25,7 @@ export class JSONEditingError extends Error { export interface IJSONValue { path: JSONPath; - value: any; + value: unknown; } export interface IJSONEditingService { diff --git a/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts index c192b3a38a7..2c96891407d 100644 --- a/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts @@ -143,14 +143,14 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR this.resolvableVariables.add('input'); } - override async resolveWithInteractionReplace(folder: IWorkspaceFolderData | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise { + override async resolveWithInteractionReplace(folder: IWorkspaceFolderData | undefined, config: unknown, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise { const parsed = ConfigurationResolverExpression.parse(config); await this.resolveWithInteraction(folder, parsed, section, variables, target); return parsed.toObject(); } - override async resolveWithInteraction(folder: IWorkspaceFolderData | undefined, config: any, section?: string, variableToCommandMap?: IStringDictionary, target?: ConfigurationTarget): Promise | undefined> { + override async resolveWithInteraction(folder: IWorkspaceFolderData | undefined, config: unknown, section?: string, variableToCommandMap?: IStringDictionary, target?: ConfigurationTarget): Promise | undefined> { const expr = ConfigurationResolverExpression.parse(config); // Get values for input variables from UI diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index 333de5abbd7..15f7c61d9b6 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -34,13 +34,13 @@ export interface IConfigurationResolverService { * @param section For example, 'tasks' or 'debug'. Used for resolving inputs. * @param variables Aliases for commands. */ - resolveWithInteractionReplace(folder: IWorkspaceFolderData | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise; + resolveWithInteractionReplace(folder: IWorkspaceFolderData | undefined, config: unknown, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise; /** * Similar to resolveWithInteractionReplace, except without the replace. Returns a map of variables and their resolution. * Keys in the map will be of the format input:variableName or command:variableName. */ - resolveWithInteraction(folder: IWorkspaceFolderData | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise | undefined>; + resolveWithInteraction(folder: IWorkspaceFolderData | undefined, config: unknown, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise | undefined>; /** * Contributes a variable that can be resolved later. Consumers that use resolveAny, resolveWithInteraction, diff --git a/src/vs/workbench/services/themes/common/themeConfiguration.ts b/src/vs/workbench/services/themes/common/themeConfiguration.ts index b4a84348fb7..09187c4940f 100644 --- a/src/vs/workbench/services/themes/common/themeConfiguration.ts +++ b/src/vs/workbench/services/themes/common/themeConfiguration.ts @@ -360,7 +360,7 @@ export class ThemeConfiguration { return ConfigurationTarget.USER; } - private async writeConfiguration(key: string, value: any, settingsTarget: ThemeSettingTarget): Promise { + private async writeConfiguration(key: string, value: unknown, settingsTarget: ThemeSettingTarget): Promise { if (settingsTarget === undefined || settingsTarget === 'preview') { return; } From 13d49873b7d5eed7acaa3086c59f83b0c5935cb2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Jun 2025 12:15:35 +0200 Subject: [PATCH 190/236] Support setting encoding from extension (fix #251188) (#251195) --- .../src/singlefolder-tests/workspace.test.ts | 8 ++++++++ src/vs/workbench/api/browser/mainThreadDocuments.ts | 3 +++ 2 files changed, 11 insertions(+) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index 7ee205256bb..549bd426c13 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -1399,6 +1399,14 @@ suite('vscode API - workspace', () => { assert.strictEqual(doc2.encoding, 'cp1252'); }); + test('encoding: openTextDocument - can change the encoding of an existing untitled document', async () => { + const doc = await vscode.workspace.openTextDocument({ content: 'Hello World' }); + assert.strictEqual(doc.encoding, 'utf8'); + + await vscode.workspace.openTextDocument(doc.uri, { encoding: 'windows1252' }); + assert.strictEqual(doc.encoding, 'windows1252'); + }); + test('encoding: decode', async function () { const uri = root.with({ path: posix.join(root.path, 'file.txt') }); diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index 47925bd1c08..91655eb0ff3 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -290,6 +290,9 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen initialValue: options?.content, encoding: options?.encoding }); + if (options?.encoding) { + await model.setEncoding(options.encoding); + } const resource = model.resource; const ref = await this._textModelResolverService.createModelReference(resource); if (!this._modelTrackers.has(resource)) { From 44fd9a6ffb3a438c5972d421f0d3da6f2330ed6a Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 11 Jun 2025 15:18:59 +0200 Subject: [PATCH 191/236] Recompute sticky scroll model when folder providers change (#251106) recompute sticky model when folder providers change --- .../browser/stickyScrollModelProvider.ts | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollModelProvider.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollModelProvider.ts index 7b0800a58c4..14111d8b810 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollModelProvider.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollModelProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, IDisposable, MutableDisposable } from '../../../../base/common/lifecycle.js'; import { IActiveCodeEditor } from '../../../browser/editorBrowser.js'; import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js'; import { OutlineElement, OutlineGroup, OutlineModel } from '../../documentSymbols/browser/outlineModel.js'; @@ -385,17 +385,26 @@ class StickyModelFromCandidateIndentationFoldingProvider extends StickyModelFrom class StickyModelFromCandidateSyntaxFoldingProvider extends StickyModelFromCandidateFoldingProvider { - private readonly provider: SyntaxRangeProvider | undefined; + private readonly provider: MutableDisposable = this._register(new MutableDisposable()); - constructor(editor: IActiveCodeEditor, + constructor( + editor: IActiveCodeEditor, onProviderUpdate: () => void, @ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService ) { super(editor); + this._register(this._languageFeaturesService.foldingRangeProvider.onDidChange(() => { + this._updateProvider(editor, onProviderUpdate); + })); + this._updateProvider(editor, onProviderUpdate); + } + + private _updateProvider(editor: IActiveCodeEditor, onProviderUpdate: () => void): void { const selectedProviders = FoldingController.getFoldingRangeProviders(this._languageFeaturesService, editor.getModel()); - if (selectedProviders.length > 0) { - this.provider = this._register(new SyntaxRangeProvider(editor.getModel(), selectedProviders, onProviderUpdate, this._foldingLimitReporter, undefined)); + if (selectedProviders.length === 0) { + return; } + this.provider.value = new SyntaxRangeProvider(editor.getModel(), selectedProviders, onProviderUpdate, this._foldingLimitReporter, undefined); } protected override isProviderValid(): boolean { @@ -403,6 +412,6 @@ class StickyModelFromCandidateSyntaxFoldingProvider extends StickyModelFromCandi } protected override async createModelFromProvider(token: CancellationToken): Promise { - return this.provider?.compute(token) ?? null; + return this.provider.value?.compute(token) ?? null; } } From c367a5fa5642806fb8a281aaf1dd1c5a70bdbfc6 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 11 Jun 2025 16:50:26 +0200 Subject: [PATCH 192/236] Core part of https://github.com/microsoft/vscode-copilot/issues/18246 (#251205) --- .../contrib/inlineCompletions/browser/model/changeRecorder.ts | 2 +- .../inlineCompletions/browser/model/inlineCompletionsSource.ts | 2 +- .../contrib/inlineCompletions/browser/structuredLogger.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts index a9f6b247849..9dee6faeb9c 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts @@ -55,7 +55,7 @@ export class TextModelChangeRecorder extends Disposable { sourceId: 'TextModel.setChangeReason', source: source, time: Date.now(), - modelUri: tm.uri.toString(), + modelUri: tm.uri, modelVersion: tm.getVersionId(), }; setTimeout(() => { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts index 029c0ec23a2..5e9195b4794 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts @@ -154,7 +154,7 @@ export class InlineCompletionsSource extends Disposable { const requestId = InlineCompletionsSource._requestId++; if (this._loggingEnabled.get() || this._structuredFetchLogger.isEnabled.get()) { - this._log({ sourceId: 'InlineCompletions.fetch', kind: 'start', requestId, modelUri: this._textModel.uri.toString(), modelVersion: this._textModel.getVersionId(), context: { triggerKind: context.triggerKind }, time: Date.now() }); + this._log({ sourceId: 'InlineCompletions.fetch', kind: 'start', requestId, modelUri: this._textModel.uri, modelVersion: this._textModel.getVersionId(), context: { triggerKind: context.triggerKind }, time: Date.now() }); } const startTime = new Date(); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/structuredLogger.ts b/src/vs/editor/contrib/inlineCompletions/browser/structuredLogger.ts index e6bacf3486a..f7b79676b70 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/structuredLogger.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/structuredLogger.ts @@ -5,6 +5,7 @@ import { Disposable } from '../../../../base/common/lifecycle.js'; import { IObservable, observableFromEvent } from '../../../../base/common/observable.js'; +import { URI } from '../../../../base/common/uri.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; @@ -14,7 +15,7 @@ export interface IRecordableLogEntry { } export interface IRecordableEditorLogEntry extends IRecordableLogEntry { - modelUri: string; + modelUri: URI; // This has to be a URI, so that it gets translated automatically in remote scenarios modelVersion: number; } From 312284e7db0d90894a576a67c0aaf07319fc470b Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 11 Jun 2025 17:44:14 +0200 Subject: [PATCH 193/236] EditContext: migrate to non-experimental setting name (#251211) migrating to non experimental setting name --- .../editor/browser/config/migrateOptions.ts | 11 ++++++++++ src/vs/editor/browser/view.ts | 12 +++++------ .../viewParts/viewCursors/viewCursors.ts | 8 ++++---- src/vs/editor/common/config/editorOptions.ts | 20 +++++++++---------- .../common/standalone/standaloneEnums.ts | 4 ++-- .../contrib/clipboard/browser/clipboard.ts | 6 +++--- src/vs/monaco.d.ts | 10 +++++----- .../codeEditor/browser/simpleEditorOptions.ts | 2 +- 8 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/vs/editor/browser/config/migrateOptions.ts b/src/vs/editor/browser/config/migrateOptions.ts index a056495bfef..61c0c1aab35 100644 --- a/src/vs/editor/browser/config/migrateOptions.ts +++ b/src/vs/editor/browser/config/migrateOptions.ts @@ -196,6 +196,17 @@ registerEditorSettingMigration('experimental.stickyScroll.maxLineCount', (value, } }); +// Edit Context + +registerEditorSettingMigration('editor.experimentalEditContextEnabled', (value, read, write) => { + if (typeof value === 'boolean') { + write('editor.experimentalEditContextEnabled', undefined); + if (typeof read('editor.editContext') === 'undefined') { + write('editor.editContext', value); + } + } +}); + // Code Actions on Save registerEditorSettingMigration('codeActionsOnSave', (value, read, write) => { if (value && typeof value === 'object') { diff --git a/src/vs/editor/browser/view.ts b/src/vs/editor/browser/view.ts index 53acaf14f7f..ef187061795 100644 --- a/src/vs/editor/browser/view.ts +++ b/src/vs/editor/browser/view.ts @@ -103,7 +103,7 @@ export class View extends ViewEventHandler { private readonly _viewParts: ViewPart[]; private readonly _viewController: ViewController; - private _experimentalEditContextEnabled: boolean; + private _editContextEnabled: boolean; private _accessibilitySupport: AccessibilitySupport; private _editContext: AbstractEditContext; private readonly _pointerHandler: PointerHandler; @@ -157,7 +157,7 @@ export class View extends ViewEventHandler { this._viewParts = []; // Keyboard handler - this._experimentalEditContextEnabled = this._context.configuration.options.get(EditorOption.effectiveExperimentalEditContextEnabled); + this._editContextEnabled = this._context.configuration.options.get(EditorOption.effectiveEditContext); this._accessibilitySupport = this._context.configuration.options.get(EditorOption.accessibilitySupport); this._editContext = this._instantiateEditContext(); @@ -289,7 +289,7 @@ export class View extends ViewEventHandler { } private _instantiateEditContext(): AbstractEditContext { - const usingExperimentalEditContext = this._context.configuration.options.get(EditorOption.effectiveExperimentalEditContextEnabled); + const usingExperimentalEditContext = this._context.configuration.options.get(EditorOption.effectiveEditContext); if (usingExperimentalEditContext) { return this._instantiationService.createInstance(NativeEditContext, this._ownerID, this._context, this._overflowGuardContainer, this._viewController, this._createTextAreaHandlerHelper()); } else { @@ -298,12 +298,12 @@ export class View extends ViewEventHandler { } private _updateEditContext(): void { - const experimentalEditContextEnabled = this._context.configuration.options.get(EditorOption.effectiveExperimentalEditContextEnabled); + const editContextEnabled = this._context.configuration.options.get(EditorOption.effectiveEditContext); const accessibilitySupport = this._context.configuration.options.get(EditorOption.accessibilitySupport); - if (this._experimentalEditContextEnabled === experimentalEditContextEnabled && this._accessibilitySupport === accessibilitySupport) { + if (this._editContextEnabled === editContextEnabled && this._accessibilitySupport === accessibilitySupport) { return; } - this._experimentalEditContextEnabled = experimentalEditContextEnabled; + this._editContextEnabled = editContextEnabled; this._accessibilitySupport = accessibilitySupport; const isEditContextFocused = this._editContext.isFocused(); const indexOfEditContext = this._viewParts.indexOf(this._editContext); diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts index 82c46115a1b..d3fd3861bb2 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts @@ -35,7 +35,7 @@ export class ViewCursors extends ViewPart { private _cursorBlinking: TextEditorCursorBlinkingStyle; private _cursorStyle: TextEditorCursorStyle; private _cursorSmoothCaretAnimation: 'off' | 'explicit' | 'on'; - private _experimentalEditContextEnabled: boolean; + private _editContextEnabled: boolean; private _selectionIsEmpty: boolean; private _isComposingInput: boolean; @@ -61,7 +61,7 @@ export class ViewCursors extends ViewPart { this._cursorBlinking = options.get(EditorOption.cursorBlinking); this._cursorStyle = options.get(EditorOption.effectiveCursorStyle); this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation); - this._experimentalEditContextEnabled = options.get(EditorOption.effectiveExperimentalEditContextEnabled); + this._editContextEnabled = options.get(EditorOption.effectiveEditContext); this._selectionIsEmpty = true; this._isComposingInput = false; @@ -116,7 +116,7 @@ export class ViewCursors extends ViewPart { this._cursorBlinking = options.get(EditorOption.cursorBlinking); this._cursorStyle = options.get(EditorOption.effectiveCursorStyle); this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation); - this._experimentalEditContextEnabled = options.get(EditorOption.effectiveExperimentalEditContextEnabled); + this._editContextEnabled = options.get(EditorOption.effectiveEditContext); this._updateBlinking(); this._updateDomClassName(); @@ -226,7 +226,7 @@ export class ViewCursors extends ViewPart { private _getCursorBlinking(): TextEditorCursorBlinkingStyle { // TODO: Remove the following if statement when experimental edit context is made default sole implementation - if (this._isComposingInput && !this._experimentalEditContextEnabled) { + if (this._isComposingInput && !this._editContextEnabled) { // avoid double cursors return TextEditorCursorBlinkingStyle.Hidden; } diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 1c2b54f46f9..035e449c231 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -778,7 +778,7 @@ export interface IEditorOptions { /** * Sets whether the new experimental edit context should be used instead of the text area. */ - experimentalEditContextEnabled?: boolean; + editContext?: boolean; /** * Controls support for changing how content is pasted into the editor. @@ -1966,14 +1966,14 @@ class EffectiveCursorStyle extends ComputedEditorOption { +class EffectiveEditContextEnabled extends ComputedEditorOption { constructor() { - super(EditorOption.effectiveExperimentalEditContextEnabled); + super(EditorOption.effectiveEditContext); } public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions): boolean { - return env.editContextSupported && options.get(EditorOption.experimentalEditContextEnabled); + return env.editContextSupported && options.get(EditorOption.editContext); } } @@ -5537,7 +5537,7 @@ export const enum EditorOption { domReadOnly, dragAndDrop, dropIntoEditor, - experimentalEditContextEnabled, + editContext, emptySelectionClipboard, experimentalGpuAcceleration, experimentalWhitespaceRendering, @@ -5657,7 +5657,7 @@ export const enum EditorOption { defaultColorDecorators, colorDecoratorsActivatedOn, inlineCompletionsAccessibilityVerbose, - effectiveExperimentalEditContextEnabled + effectiveEditContext } export const EditorOptions = { @@ -5931,10 +5931,10 @@ export const EditorOptions = { )), emptySelectionClipboard: register(new EditorEmptySelectionClipboard()), dropIntoEditor: register(new EditorDropIntoEditor()), - experimentalEditContextEnabled: register(new EditorBooleanOption( - EditorOption.experimentalEditContextEnabled, 'experimentalEditContextEnabled', true, + editContext: register(new EditorBooleanOption( + EditorOption.editContext, 'editContext', true, { - description: nls.localize('experimentalEditContextEnabled', "Sets whether the new experimental edit context should be used instead of the text area."), + description: nls.localize('editContext', "Sets whether the EditContext API should be used instead of the text area to power input in the editor."), included: platform.isChrome || platform.isEdge || platform.isNative } )), @@ -6498,7 +6498,7 @@ export const EditorOptions = { wrappingInfo: register(new EditorWrappingInfoComputer()), wrappingIndent: register(new WrappingIndentOption()), wrappingStrategy: register(new WrappingStrategy()), - effectiveExperimentalEditContextEnabled: register(new EffectiveExperimentalEditContextEnabled()) + effectiveEditContextEnabled: register(new EffectiveEditContextEnabled()) }; type EditorOptionsType = typeof EditorOptions; diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index b0aa004c999..ba19d1861ee 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -214,7 +214,7 @@ export enum EditorOption { domReadOnly = 37, dragAndDrop = 38, dropIntoEditor = 39, - experimentalEditContextEnabled = 40, + editContext = 40, emptySelectionClipboard = 41, experimentalGpuAcceleration = 42, experimentalWhitespaceRendering = 43, @@ -333,7 +333,7 @@ export enum EditorOption { defaultColorDecorators = 156, colorDecoratorsActivatedOn = 157, inlineCompletionsAccessibilityVerbose = 158, - effectiveExperimentalEditContextEnabled = 159 + effectiveEditContext = 159 } /** diff --git a/src/vs/editor/contrib/clipboard/browser/clipboard.ts b/src/vs/editor/contrib/clipboard/browser/clipboard.ts index 6a382131fce..638f39be363 100644 --- a/src/vs/editor/contrib/clipboard/browser/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/browser/clipboard.ts @@ -205,7 +205,7 @@ function registerExecCommandImpl(target: MultiCommand | undefined, browserComman return true; } // TODO this is very ugly. The entire copy/paste/cut system needs a complete refactoring. - if (focusedEditor.getOption(EditorOption.effectiveExperimentalEditContextEnabled) && browserCommand === 'cut') { + if (focusedEditor.getOption(EditorOption.effectiveEditContext) && browserCommand === 'cut') { // execCommand(copy) works for edit context, but not execCommand(cut). focusedEditor.getContainerDomNode().ownerDocument.execCommand('copy'); focusedEditor.trigger(undefined, Handler.Cut, undefined); @@ -239,8 +239,8 @@ if (PasteAction) { const focusedEditor = codeEditorService.getFocusedCodeEditor(); if (focusedEditor && focusedEditor.hasModel() && focusedEditor.hasTextFocus()) { // execCommand(paste) does not work with edit context - const experimentalEditContextEnabled = focusedEditor.getOption(EditorOption.effectiveExperimentalEditContextEnabled); - if (experimentalEditContextEnabled) { + const editContextEnabled = focusedEditor.getOption(EditorOption.effectiveEditContext); + if (editContextEnabled) { const nativeEditContext = NativeEditContextRegistry.get(focusedEditor.getId()); if (nativeEditContext) { nativeEditContext.onWillPaste(); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index ed45b5fbbea..b61ba153ebf 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3833,7 +3833,7 @@ declare namespace monaco.editor { /** * Sets whether the new experimental edit context should be used instead of the text area. */ - experimentalEditContextEnabled?: boolean; + editContext?: boolean; /** * Controls support for changing how content is pasted into the editor. */ @@ -4959,7 +4959,7 @@ declare namespace monaco.editor { domReadOnly = 37, dragAndDrop = 38, dropIntoEditor = 39, - experimentalEditContextEnabled = 40, + editContext = 40, emptySelectionClipboard = 41, experimentalGpuAcceleration = 42, experimentalWhitespaceRendering = 43, @@ -5078,7 +5078,7 @@ declare namespace monaco.editor { defaultColorDecorators = 156, colorDecoratorsActivatedOn = 157, inlineCompletionsAccessibilityVerbose = 158, - effectiveExperimentalEditContextEnabled = 159 + effectiveEditContext = 159 } export const EditorOptions: { @@ -5126,7 +5126,7 @@ declare namespace monaco.editor { dragAndDrop: IEditorOption; emptySelectionClipboard: IEditorOption; dropIntoEditor: IEditorOption>>; - experimentalEditContextEnabled: IEditorOption; + editContext: IEditorOption; stickyScroll: IEditorOption>>; experimentalGpuAcceleration: IEditorOption; experimentalWhitespaceRendering: IEditorOption; @@ -5241,7 +5241,7 @@ declare namespace monaco.editor { wrappingInfo: IEditorOption; wrappingIndent: IEditorOption; wrappingStrategy: IEditorOption; - effectiveExperimentalEditContextEnabled: IEditorOption; + effectiveEditContextEnabled: IEditorOption; }; type EditorOptionsType = typeof EditorOptions; diff --git a/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts b/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts index 20d03403370..d366a6c17b2 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts @@ -47,7 +47,7 @@ export function getSimpleEditorOptions(configurationService: IConfigurationServi }, accessibilitySupport: configurationService.getValue<'auto' | 'off' | 'on'>('editor.accessibilitySupport'), cursorBlinking: configurationService.getValue<'blink' | 'smooth' | 'phase' | 'expand' | 'solid'>('editor.cursorBlinking'), - experimentalEditContextEnabled: configurationService.getValue('editor.experimentalEditContextEnabled'), + editContext: configurationService.getValue('editor.editContext'), defaultColorDecorators: 'never', }; } From defae8c9c0b442a9eca2d87413223be88bfb8caa Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 11 Jun 2025 08:44:31 -0700 Subject: [PATCH 194/236] provide proper URIs for remotes so suggest works for those envs (#251129) fix wsl suggestions --- extensions/terminal-suggest/src/terminalSuggestMain.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/terminal-suggest/src/terminalSuggestMain.ts b/extensions/terminal-suggest/src/terminalSuggestMain.ts index 8798ffa872d..b026ccb9334 100644 --- a/extensions/terminal-suggest/src/terminalSuggestMain.ts +++ b/extensions/terminal-suggest/src/terminalSuggestMain.ts @@ -143,7 +143,13 @@ export async function activate(context: vscode.ExtensionContext) { } if (terminal.shellIntegration?.cwd && (result.filesRequested || result.foldersRequested)) { - return new vscode.TerminalCompletionList(result.items, { filesRequested: result.filesRequested, foldersRequested: result.foldersRequested, fileExtensions: result.fileExtensions, cwd: result.cwd ?? terminal.shellIntegration.cwd, env: terminal.shellIntegration?.env?.value, }); + let cwd; + if (vscode.env.remoteName) { + cwd = vscode.Uri.file((result.cwd ?? terminal.shellIntegration.cwd).path).with({ authority: vscode.env.remoteName, scheme: 'vscode-remote' }); + } else { + cwd = vscode.Uri.file((result.cwd ?? terminal.shellIntegration.cwd).fsPath); + } + return new vscode.TerminalCompletionList(result.items, { filesRequested: result.filesRequested, foldersRequested: result.foldersRequested, fileExtensions: result.fileExtensions, cwd, env: terminal.shellIntegration?.env?.value, }); } return result.items; } From 6ab0967549293db83dae2d7be268bb514e4a3cc0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 11 Jun 2025 09:07:07 -0700 Subject: [PATCH 195/236] Register disposables Fixes #251193 --- .../contrib/codeActions/browser/codeActionsContribution.ts | 4 ++-- .../contrib/dropOrPasteInto/browser/configurationSchema.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts b/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts index a7a7ce4c176..9d2c63f2e51 100644 --- a/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts +++ b/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts @@ -132,10 +132,10 @@ export class CodeActionsContribution extends Disposable implements IWorkbenchCon this._onDidChangeSchemaContributions.fire(); })); - keybindingService.registerSchemaContribution({ + this._register(keybindingService.registerSchemaContribution({ getSchemaAdditions: () => this.getKeybindingSchemaAdditions(), onDidChange: this._onDidChangeSchemaContributions.event, - }); + })); } private getAllProvidedCodeActionKinds(): Array { diff --git a/src/vs/workbench/contrib/dropOrPasteInto/browser/configurationSchema.ts b/src/vs/workbench/contrib/dropOrPasteInto/browser/configurationSchema.ts index 648270466ac..29490d17d8b 100644 --- a/src/vs/workbench/contrib/dropOrPasteInto/browser/configurationSchema.ts +++ b/src/vs/workbench/contrib/dropOrPasteInto/browser/configurationSchema.ts @@ -86,10 +86,10 @@ export class DropOrPasteSchemaContribution extends Disposable implements IWorkbe this._onDidChangeSchemaContributions.fire(); })); - keybindingService.registerSchemaContribution({ + this._register(keybindingService.registerSchemaContribution({ getSchemaAdditions: () => this.getKeybindingSchemaAdditions(), onDidChange: this._onDidChangeSchemaContributions.event, - }); + })); } private updateProvidedKinds(): void { From 325c681f8e4615a4ba405c80b6e83c0392be5776 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Jun 2025 09:37:21 -0700 Subject: [PATCH 196/236] Fix markdown cell status bar showing misleading grab cursor (#251154) * Initial plan for issue * Fix markdown cell status bar showing misleading grab cursor Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> --- .../contrib/notebook/browser/media/notebookCellStatusBar.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebookCellStatusBar.css b/src/vs/workbench/contrib/notebook/browser/media/notebookCellStatusBar.css index 64dd58eecd2..e18a2855b7a 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebookCellStatusBar.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebookCellStatusBar.css @@ -9,6 +9,7 @@ display: flex; position: relative; overflow: hidden; + cursor: default; } .monaco-workbench .notebookOverlay .cell-statusbar-hidden .cell-statusbar-container { From e3bc6ea700243313ce336ce54b1b70bfe1e50e69 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Jun 2025 09:37:30 -0700 Subject: [PATCH 197/236] Fix inconsistent scrolling behavior in notebook outline entries (#251027) * Initial plan for issue * Fix notebook outline scrolling to use consistent Top reveal type Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Remove ineffective test as requested in code review Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Remove extra blank line to address whitespace feedback Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Remove empty line as requested in code review Co-authored-by: rzhao271 <7199958+rzhao271@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> Co-authored-by: rzhao271 <7199958+rzhao271@users.noreply.github.com> --- .../contrib/notebook/browser/contrib/outline/notebookOutline.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts index 61286b39689..786603a18fb 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts @@ -740,7 +740,7 @@ export class NotebookCellOutline implements IOutline { const notebookEditorOptions: INotebookEditorOptions = { ...options, override: this._editor.input?.editorId, - cellRevealType: CellRevealType.NearTopIfOutsideViewport, + cellRevealType: CellRevealType.Top, selection: entry.position, viewState: undefined, }; From d1d6762ca81128aba1b1debf81688d2cd7b61ebd Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 11 Jun 2025 13:24:01 -0400 Subject: [PATCH 198/236] support builtin commands for git bash (#251216) fix #248558 --- extensions/terminal-suggest/src/terminalSuggestMain.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extensions/terminal-suggest/src/terminalSuggestMain.ts b/extensions/terminal-suggest/src/terminalSuggestMain.ts index b026ccb9334..95567c16fae 100644 --- a/extensions/terminal-suggest/src/terminalSuggestMain.ts +++ b/extensions/terminal-suggest/src/terminalSuggestMain.ts @@ -58,6 +58,7 @@ for (const spec of upstreamSpecs) { const getShellSpecificGlobals: Map) => Promise<(string | ICompletionResource)[]>> = new Map([ [TerminalShellType.Bash, getBashGlobals], [TerminalShellType.Zsh, getZshGlobals], + [TerminalShellType.GitBash, getBashGlobals], // Git Bash is a bash shell // TODO: Ghost text in the command line prevents completions from working ATM for fish [TerminalShellType.Fish, getFishGlobals], [TerminalShellType.PowerShell, getPwshGlobals], @@ -72,7 +73,11 @@ async function getShellGlobals(shellType: TerminalShellType, existingCommands?: if (!shellType) { return; } - const options: ExecOptionsWithStringEncoding = { encoding: 'utf-8', shell: shellType }; + let execShellType = shellType; + if (shellType === TerminalShellType.GitBash) { + execShellType = TerminalShellType.Bash; // Git Bash is a bash shell + } + const options: ExecOptionsWithStringEncoding = { encoding: 'utf-8', shell: execShellType, windowsHide: true }; const mixedCommands: (string | ICompletionResource)[] | undefined = await getShellSpecificGlobals.get(shellType)?.(options, existingCommands); const normalizedCommands = mixedCommands?.map(command => typeof command === 'string' ? ({ label: command }) : command); cachedGlobals.set(shellType, normalizedCommands); From 6a8e32e03f32e61e5624aa788967362cdd35e85e Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 11 Jun 2025 13:33:10 -0400 Subject: [PATCH 199/236] don't add `\` if path already starts with that on pwsh for suggestions (#251219) fix #25127 --- .../suggest/browser/terminalCompletionService.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts index 79069fb688a..b3b8ac86afd 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionService.ts @@ -525,6 +525,9 @@ function getFriendlyPath(uri: URI, pathSeparator: string, kind: TerminalCompleti */ function addPathRelativePrefix(text: string, resourceRequestConfig: Pick, lastWordFolderHasDotPrefix: boolean): string { if (!lastWordFolderHasDotPrefix) { + if (text.startsWith(resourceRequestConfig.pathSeparator)) { + return `.${text}`; + } return `.${resourceRequestConfig.pathSeparator}${text}`; } return text; From 8def6db21b079ee2f80f84f757952217cdf497f9 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 11 Jun 2025 11:12:10 -0700 Subject: [PATCH 200/236] chore: bump vscode/ripgrep (#251213) * chore: bump vscode/ripgrep * Update error message --- build/package-lock.json | 8 ++++---- build/package.json | 2 +- package-lock.json | 8 ++++---- package.json | 2 +- remote/package-lock.json | 8 ++++---- remote/package.json | 2 +- .../search/test/node/textSearch.integrationTest.ts | 12 ++++++------ 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/build/package-lock.json b/build/package-lock.json index d3d02a29d7d..626ec828a5b 100644 --- a/build/package-lock.json +++ b/build/package-lock.json @@ -42,7 +42,7 @@ "@types/workerpool": "^6.4.0", "@types/xml2js": "0.0.33", "@vscode/iconv-lite-umd": "0.7.0", - "@vscode/ripgrep": "^1.15.10", + "@vscode/ripgrep": "^1.15.13", "@vscode/vsce": "2.20.1", "byline": "^5.0.0", "debug": "^4.3.2", @@ -1319,9 +1319,9 @@ "dev": true }, "node_modules/@vscode/ripgrep": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.10.tgz", - "integrity": "sha512-83Q6qFrELpFgf88bPOcwSWDegfY2r/cb6bIfdLTSZvN73Dg1wviSfO+1v6lTFMd0mAvUYYcTUu+Mn5xMroZMxA==", + "version": "1.15.13", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.13.tgz", + "integrity": "sha512-c62On5sLEIMv9yfetIZ8c0Mg0s6lvq54G0YLW2zY/XiPsJPyBBgrP54MR1s0hK3gsPy423cY+e2BDU6mOB2Yaw==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/build/package.json b/build/package.json index c19196d45c7..e34a23547ec 100644 --- a/build/package.json +++ b/build/package.json @@ -36,7 +36,7 @@ "@types/workerpool": "^6.4.0", "@types/xml2js": "0.0.33", "@vscode/iconv-lite-umd": "0.7.0", - "@vscode/ripgrep": "^1.15.10", + "@vscode/ripgrep": "^1.15.13", "@vscode/vsce": "2.20.1", "byline": "^5.0.0", "debug": "^4.3.2", diff --git a/package-lock.json b/package-lock.json index 3bb7fc3d2e8..82c97ab56f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@vscode/iconv-lite-umd": "0.7.0", "@vscode/policy-watcher": "^1.3.2", "@vscode/proxy-agent": "^0.32.0", - "@vscode/ripgrep": "^1.15.11", + "@vscode/ripgrep": "^1.15.13", "@vscode/spdlog": "^0.15.2", "@vscode/sqlite3": "5.1.8-vscode", "@vscode/sudo-prompt": "9.3.1", @@ -2712,9 +2712,9 @@ } }, "node_modules/@vscode/ripgrep": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.11.tgz", - "integrity": "sha512-G/VqtA6kR50mJkIH4WA+I2Q78V5blovgPPq0VPYM0QIRp57lYMkdV+U9VrY80b3AvaC72A1z8STmyxc8ZKiTsw==", + "version": "1.15.13", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.13.tgz", + "integrity": "sha512-c62On5sLEIMv9yfetIZ8c0Mg0s6lvq54G0YLW2zY/XiPsJPyBBgrP54MR1s0hK3gsPy423cY+e2BDU6mOB2Yaw==", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index d78d007e580..950cc277386 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@vscode/iconv-lite-umd": "0.7.0", "@vscode/policy-watcher": "^1.3.2", "@vscode/proxy-agent": "^0.32.0", - "@vscode/ripgrep": "^1.15.11", + "@vscode/ripgrep": "^1.15.13", "@vscode/spdlog": "^0.15.2", "@vscode/sqlite3": "5.1.8-vscode", "@vscode/sudo-prompt": "9.3.1", diff --git a/remote/package-lock.json b/remote/package-lock.json index 22cf60e74b7..9efb43a4180 100644 --- a/remote/package-lock.json +++ b/remote/package-lock.json @@ -14,7 +14,7 @@ "@vscode/deviceid": "^0.1.1", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/proxy-agent": "^0.32.0", - "@vscode/ripgrep": "^1.15.11", + "@vscode/ripgrep": "^1.15.13", "@vscode/spdlog": "^0.15.2", "@vscode/tree-sitter-wasm": "^0.1.4", "@vscode/vscode-languagedetection": "1.0.21", @@ -437,9 +437,9 @@ } }, "node_modules/@vscode/ripgrep": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.11.tgz", - "integrity": "sha512-G/VqtA6kR50mJkIH4WA+I2Q78V5blovgPPq0VPYM0QIRp57lYMkdV+U9VrY80b3AvaC72A1z8STmyxc8ZKiTsw==", + "version": "1.15.13", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.13.tgz", + "integrity": "sha512-c62On5sLEIMv9yfetIZ8c0Mg0s6lvq54G0YLW2zY/XiPsJPyBBgrP54MR1s0hK3gsPy423cY+e2BDU6mOB2Yaw==", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/remote/package.json b/remote/package.json index 8eefceeca6d..6a6fe3dfff4 100644 --- a/remote/package.json +++ b/remote/package.json @@ -9,7 +9,7 @@ "@vscode/deviceid": "^0.1.1", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/proxy-agent": "^0.32.0", - "@vscode/ripgrep": "^1.15.11", + "@vscode/ripgrep": "^1.15.13", "@vscode/spdlog": "^0.15.2", "@vscode/tree-sitter-wasm": "^0.1.4", "@vscode/vscode-languagedetection": "1.0.21", diff --git a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts index 85ef0f3dbc7..da33ca6c132 100644 --- a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts +++ b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import * as path from '../../../../../base/common/path.js'; import { CancellationTokenSource } from '../../../../../base/common/cancellation.js'; import * as glob from '../../../../../base/common/glob.js'; -import { URI } from '../../../../../base/common/uri.js'; -import { deserializeSearchError, IFolderQuery, ISearchRange, ITextQuery, ITextSearchContext, ITextSearchMatch, QueryType, SearchErrorCode, ISerializedFileMatch } from '../../common/search.js'; -import { TextSearchEngineAdapter } from '../../node/textSearchAdapter.js'; -import { flakySuite } from '../../../../../base/test/node/testUtils.js'; import { FileAccess } from '../../../../../base/common/network.js'; +import * as path from '../../../../../base/common/path.js'; +import { URI } from '../../../../../base/common/uri.js'; +import { flakySuite } from '../../../../../base/test/node/testUtils.js'; +import { deserializeSearchError, IFolderQuery, ISearchRange, ISerializedFileMatch, ITextQuery, ITextSearchContext, ITextSearchMatch, QueryType, SearchErrorCode } from '../../common/search.js'; +import { TextSearchEngineAdapter } from '../../node/textSearchAdapter.js'; const TEST_FIXTURES = path.normalize(FileAccess.asFileUri('vs/workbench/services/search/test/node/fixtures').fsPath); const EXAMPLES_FIXTURES = path.join(TEST_FIXTURES, 'examples'); @@ -405,7 +405,7 @@ flakySuite('TextSearch-integration', function () { throw new Error('expected fail'); }, err => { const searchError = deserializeSearchError(err); - const regexParseErrorForLookAround = 'Regex parse error: lookbehind assertion is not fixed length'; + const regexParseErrorForLookAround = 'Regex parse error: length of lookbehind assertion is not limited'; assert.strictEqual(searchError.message, regexParseErrorForLookAround); assert.strictEqual(searchError.code, SearchErrorCode.regexParseError); }); From 080c694447eddb6a1503a9d51e6609bbf9776075 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 11 Jun 2025 20:36:40 +0200 Subject: [PATCH 201/236] Refactoring sticky scroll widget file (#251218) * refactoring sticky scroll widget file * wip * polish * wip --- .../stickyScroll/browser/stickyScroll.css | 1 + .../browser/stickyScrollWidget.ts | 160 +++++++++--------- 2 files changed, 78 insertions(+), 83 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css index 44f4b3377d9..ecc59245dec 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css @@ -10,6 +10,7 @@ box-shadow: var(--vscode-editorStickyScroll-shadow) 0 4px 2px -2px; z-index: 4; right: initial !important; + margin-left: '0px'; } .monaco-editor .sticky-widget .sticky-widget-line-numbers { diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts index 1abf94328e2..a642c3c0c77 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts @@ -20,6 +20,7 @@ import { CharacterMapping, RenderLineInput, renderViewLine } from '../../../comm import { foldingCollapsedIcon, foldingExpandedIcon } from '../../folding/browser/foldingDecorations.js'; import { FoldingModel } from '../../folding/browser/foldingModel.js'; import { Emitter } from '../../../../base/common/event.js'; +import { IViewModel } from '../../../common/viewModel.js'; export class StickyScrollWidgetState { constructor( @@ -58,7 +59,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { private readonly _editor: ICodeEditor; - private _previousState: StickyScrollWidgetState | undefined; + private _state: StickyScrollWidgetState | undefined; private _lineHeight: number; private _renderedStickyLines: RenderedStickyLine[] = []; private _lineNumbers: number[] = []; @@ -142,49 +143,48 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { return this._lineNumbers; } - setState(_state: StickyScrollWidgetState | undefined, foldingModel: FoldingModel | undefined, _rebuildFromLine?: number): void { - if (_rebuildFromLine === undefined && - ((!this._previousState && !_state) || (this._previousState && this._previousState.equals(_state))) - ) { + setState(state: StickyScrollWidgetState | undefined, foldingModel: FoldingModel | undefined, rebuildFromIndexCandidate?: number): void { + const currentStateAndPreviousStateUndefined = !this._state && !state; + const currentStateDefinedAndEqualsPreviousState = this._state && this._state.equals(state); + if (currentStateAndPreviousStateUndefined || currentStateDefinedAndEqualsPreviousState) { return; } - const isWidgetHeightZero = this._isWidgetHeightZero(_state); - const state = isWidgetHeightZero ? undefined : _state; - const rebuildFromLine = isWidgetHeightZero ? 0 : this._findLineToRebuildWidgetFrom(_state, _rebuildFromLine); - - this._renderRootNode(state, foldingModel, rebuildFromLine); - this._previousState = _state; + const data = this._findRenderingData(state); + const previousLineNumbers = this._lineNumbers; + this._lineNumbers = data.lineNumbers; + this._lastLineRelativePosition = data.lastLineRelativePosition; + const rebuildFromIndex = this._findIndexToRebuildFrom(previousLineNumbers, this._lineNumbers, rebuildFromIndexCandidate); + this._renderRootNode(this._lineNumbers, this._lastLineRelativePosition, foldingModel, rebuildFromIndex); + this._state = state; } - private _isWidgetHeightZero(state: StickyScrollWidgetState | undefined): boolean { + private _findRenderingData(state: StickyScrollWidgetState | undefined): { lineNumbers: number[]; lastLineRelativePosition: number } { if (!state) { - return true; + return { lineNumbers: [], lastLineRelativePosition: 0 }; } - const futureWidgetHeight = this._getHeightOfLines(state.startLineNumbers, state.lastLineRelativePosition); - if (futureWidgetHeight > 0) { - this._lastLineRelativePosition = state.lastLineRelativePosition; - const lineNumbers = [...state.startLineNumbers]; - if (state.showEndForLine !== null) { - lineNumbers[state.showEndForLine] = state.endLineNumbers[state.showEndForLine]; - } - this._lineNumbers = lineNumbers; - } else { - this._lastLineRelativePosition = 0; - this._lineNumbers = []; + const candidateLineNumbers = [...state.startLineNumbers]; + if (state.showEndForLine !== null) { + candidateLineNumbers[state.showEndForLine] = state.endLineNumbers[state.showEndForLine]; } - return futureWidgetHeight === 0; + let totalHeight = 0; + for (let i = 0; i < candidateLineNumbers.length; i++) { + totalHeight += this._editor.getLineHeightForPosition(new Position(candidateLineNumbers[i], 1)); + } + if (totalHeight === 0) { + return { lineNumbers: [], lastLineRelativePosition: 0 }; + } + return { lineNumbers: candidateLineNumbers, lastLineRelativePosition: state.lastLineRelativePosition }; } - private _findLineToRebuildWidgetFrom(state: StickyScrollWidgetState | undefined, _rebuildFromLine?: number): number { - if (!state || !this._previousState) { + private _findIndexToRebuildFrom(previousLineNumbers: number[], newLineNumbers: number[], rebuildFromIndexCandidate?: number): number { + if (newLineNumbers.length === 0) { return 0; } - if (_rebuildFromLine !== undefined) { - return _rebuildFromLine; + if (rebuildFromIndexCandidate !== undefined) { + return rebuildFromIndexCandidate; } - const previousState = this._previousState; - const indexOfLinesAlreadyRendered = state.startLineNumbers.findIndex(startLineNumber => !previousState.startLineNumbers.includes(startLineNumber)); - return (indexOfLinesAlreadyRendered === -1) ? 0 : indexOfLinesAlreadyRendered; + const validIndex = newLineNumbers.findIndex(startLineNumber => !previousLineNumbers.includes(startLineNumber)); + return validIndex === -1 ? 0 : validIndex; } private _updateWidgetWidth(): void { @@ -195,18 +195,6 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { this._rootDomNode.style.width = `${layoutInfo.width - layoutInfo.verticalScrollbarWidth}px`; } - private _clearStickyLinesFromLine(clearFromLine: number) { - this._foldingIconStore.clear(); - // Removing only the lines that need to be rerendered - for (let i = clearFromLine; i < this._renderedStickyLines.length; i++) { - const stickyLine = this._renderedStickyLines[i]; - stickyLine.lineNumberDomNode.remove(); - stickyLine.lineDomNode.remove(); - } - // Keep the lines that need to be updated - this._renderedStickyLines = this._renderedStickyLines.slice(0, clearFromLine); - } - private _useFoldingOpacityTransition(requireTransitions: boolean) { this._lineNumbersDomNode.style.setProperty('--vscode-editorStickyScroll-foldingOpacityTransition', `opacity ${requireTransitions ? 0.5 : 0}s`); } @@ -221,51 +209,55 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { } } - private async _renderRootNode(state: StickyScrollWidgetState | undefined, foldingModel: FoldingModel | undefined, rebuildFromLine: number): Promise { - this._clearStickyLinesFromLine(rebuildFromLine); - if (!state) { - // make sure the dom is 0 height and display:none - this._setHeight(0); + private async _renderRootNode(lineNumbers: number[], lastLineRelativePosition: number, foldingModel: FoldingModel | undefined, rebuildFromIndex: number): Promise { + const viewModel = this._editor._getViewModel(); + if (!viewModel) { + this._clearWidget(); return; } - let top: number = 0; - // For existing sticky lines update the top and z-index - for (const stickyLine of this._renderedStickyLines) { - this._updatePosition(stickyLine, top); - top += stickyLine.height; + if (lineNumbers.length === 0) { + this._clearWidget(); + return; } - // For new sticky lines - const layoutInfo = this._editor.getLayoutInfo(); - const linesToRender = this._lineNumbers.slice(rebuildFromLine); - for (const [index, line] of linesToRender.entries()) { - const stickyLine = this._renderChildNode(index + rebuildFromLine, line, top, foldingModel, layoutInfo); - if (!stickyLine) { - continue; + const renderedStickyLines: RenderedStickyLine[] = []; + const lastLineNumber = lineNumbers[lineNumbers.length - 1]; + let top: number = 0; + for (let i = 0; i < this._renderedStickyLines.length; i++) { + if (i < rebuildFromIndex) { + const renderedLine = this._renderedStickyLines[i]; + renderedStickyLines.push(this._updatePosition(renderedLine, top, renderedLine.lineNumber === lastLineNumber)); + top += renderedLine.height; + } else { + const renderedLine = this._renderedStickyLines[i]; + renderedLine.lineNumberDomNode.remove(); + renderedLine.lineDomNode.remove(); } + } + const layoutInfo = this._editor.getLayoutInfo(); + for (let i = rebuildFromIndex; i < lineNumbers.length; i++) { + const stickyLine = this._renderChildNode(viewModel, i, lineNumbers[i], top, lastLineNumber === lineNumbers[i], foldingModel, layoutInfo); top += stickyLine.height; this._linesDomNode.appendChild(stickyLine.lineDomNode); this._lineNumbersDomNode.appendChild(stickyLine.lineNumberDomNode); - this._renderedStickyLines.push(stickyLine); + renderedStickyLines.push(stickyLine); } if (foldingModel) { this._setFoldingHoverListeners(); this._useFoldingOpacityTransition(!this._isOnGlyphMargin); } - - const widgetHeight = top + this._lastLineRelativePosition; - this._setHeight(widgetHeight); - - this._rootDomNode.style.marginLeft = '0px'; this._minContentWidthInPx = Math.max(...this._renderedStickyLines.map(l => l.scrollWidth)) + layoutInfo.verticalScrollbarWidth; + this._renderedStickyLines = renderedStickyLines; + this._setHeight(top + lastLineRelativePosition); this._editor.layoutOverlayWidget(this); } - private _getHeightOfLines(lineNumbers: number[], lastLineRelativePosition: number): number { - let totalHeight = 0; - for (let i = 0; i < lineNumbers.length; i++) { - totalHeight += this._editor.getLineHeightForPosition(new Position(lineNumbers[i], 1)); + private _clearWidget(): void { + for (let i = 0; i < this._renderedStickyLines.length; i++) { + const stickyLine = this._renderedStickyLines[i]; + stickyLine.lineNumberDomNode.remove(); + stickyLine.lineDomNode.remove(); } - return totalHeight + lastLineRelativePosition; + this._setHeight(0); } private _setHeight(height: number): void { @@ -302,11 +294,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { })); } - private _renderChildNode(index: number, line: number, top: number, foldingModel: FoldingModel | undefined, layoutInfo: EditorLayoutInfo): RenderedStickyLine | undefined { - const viewModel = this._editor._getViewModel(); - if (!viewModel) { - return; - } + private _renderChildNode(viewModel: IViewModel, index: number, line: number, top: number, isLastLine: boolean, foldingModel: FoldingModel | undefined, layoutInfo: EditorLayoutInfo): RenderedStickyLine { const viewLineNumber = viewModel.coordinatesConverter.convertModelPositionToViewPosition(new Position(line, 1)).lineNumber; const lineRenderingData = viewModel.getViewLineRenderingData(viewLineNumber); const lineNumberOption = this._editor.getOption(EditorOption.lineNumbers); @@ -376,21 +364,27 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { this._editor.applyFontInfo(lineHTMLNode); this._editor.applyFontInfo(lineNumberHTMLNode); - lineNumberHTMLNode.style.lineHeight = `${lineHeight}px`; lineHTMLNode.style.lineHeight = `${lineHeight}px`; lineNumberHTMLNode.style.height = `${lineHeight}px`; lineHTMLNode.style.height = `${lineHeight}px`; - const renderedLine = new RenderedStickyLine(index, line, lineHTMLNode, lineNumberHTMLNode, foldingIcon, renderOutput.characterMapping, lineHTMLNode.scrollWidth, lineHeight); - return this._updatePosition(renderedLine, top); + const renderedLine = new RenderedStickyLine( + index, + line, + lineHTMLNode, + lineNumberHTMLNode, + foldingIcon, + renderOutput.characterMapping, + lineHTMLNode.scrollWidth, + lineHeight + ); + return this._updatePosition(renderedLine, top, isLastLine); } - private _updatePosition(stickyLine: RenderedStickyLine, top: number): RenderedStickyLine { - const index = stickyLine.index; + private _updatePosition(stickyLine: RenderedStickyLine, top: number, isLastLine: boolean): RenderedStickyLine { const lineHTMLNode = stickyLine.lineDomNode; const lineNumberHTMLNode = stickyLine.lineNumberDomNode; - const isLastLine = index === this._lineNumbers.length - 1; if (isLastLine) { const zIndex = '0'; lineHTMLNode.style.zIndex = zIndex; From 53a4ef70187fdf34964d492e7fc5191a19fefa50 Mon Sep 17 00:00:00 2001 From: heoh Date: Thu, 12 Jun 2025 02:42:26 +0900 Subject: [PATCH 202/236] Fix markdown preview scroll crawls at EOF (fix #249278) --- extensions/markdown-language-features/preview-src/scroll-sync.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/markdown-language-features/preview-src/scroll-sync.ts b/extensions/markdown-language-features/preview-src/scroll-sync.ts index a884730a152..cba22fc48d5 100644 --- a/extensions/markdown-language-features/preview-src/scroll-sync.ts +++ b/extensions/markdown-language-features/preview-src/scroll-sync.ts @@ -156,7 +156,6 @@ export function scrollToRevealSourceLine(line: number, documentVersion: number, const progressInElement = line - Math.floor(line); scrollTo = previousTop + (rect.height * progressInElement); } - scrollTo = Math.abs(scrollTo) < 1 ? Math.sign(scrollTo) : scrollTo; window.scroll(window.scrollX, Math.max(1, window.scrollY + scrollTo)); } From af66efed69c691f98d4b262a433694b8fd29e5d1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 11 Jun 2025 21:11:26 +0200 Subject: [PATCH 203/236] Ability to programmatically assign documents to open in a workspace before it's opened (fix #251202) (#251229) --- .../workbench/browser/actions/workspaceCommands.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/actions/workspaceCommands.ts b/src/vs/workbench/browser/actions/workspaceCommands.ts index 5d45d2f2cfa..3df2f3426eb 100644 --- a/src/vs/workbench/browser/actions/workspaceCommands.ts +++ b/src/vs/workbench/browser/actions/workspaceCommands.ts @@ -20,7 +20,7 @@ import { ILanguageService } from '../../../editor/common/languages/language.js'; import { IFileDialogService, IPickAndOpenOptions } from '../../../platform/dialogs/common/dialogs.js'; import { URI, UriComponents } from '../../../base/common/uri.js'; import { Schemas } from '../../../base/common/network.js'; -import { IOpenEmptyWindowOptions, IOpenWindowOptions, IWindowOpenable } from '../../../platform/window/common/window.js'; +import { IFileToOpen, IFolderToOpen, IOpenEmptyWindowOptions, IOpenWindowOptions, IWorkspaceToOpen } from '../../../platform/window/common/window.js'; import { IRecent, IWorkspacesService } from '../../../platform/workspaces/common/workspaces.js'; import { IPathService } from '../../services/path/common/pathService.js'; import { ILocalizedString } from '../../../platform/action/common/action.js'; @@ -160,6 +160,7 @@ interface IOpenFolderAPICommandOptions { forceLocalWindow?: boolean; forceProfile?: string; forceTempProfile?: boolean; + filesToOpen?: UriComponents[]; } CommandsRegistry.registerCommand({ @@ -197,8 +198,9 @@ CommandsRegistry.registerCommand({ forceTempProfile: arg?.forceTempProfile, }; - const uriToOpen: IWindowOpenable = (hasWorkspaceFileExtension(uri) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri }; - return commandService.executeCommand('_files.windowOpen', [uriToOpen], options); + const workspaceToOpen: IWorkspaceToOpen | IFolderToOpen = (hasWorkspaceFileExtension(uri) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri }; + const filesToOpen: IFileToOpen[] = typeof arg === 'object' ? arg.filesToOpen?.map(file => ({ fileUri: URI.from(file, true) })) ?? [] : []; + return commandService.executeCommand('_files.windowOpen', [workspaceToOpen, ...filesToOpen], options); }, metadata: { description: 'Open a folder or workspace in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder/workspace unless the newWindow parameter is set to true.', @@ -213,6 +215,10 @@ CommandsRegistry.registerCommand({ '`forceNewWindow`: Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window. ' + '`forceReuseWindow`: Whether to force opening the folder/workspace in the same window. Defaults to false. ' + '`noRecentEntry`: Whether the opened URI will appear in the \'Open Recent\' list. Defaults to false. ' + + '`forceLocalWindow`: Whether to force opening the folder/workspace in a local window. Defaults to false. ' + + '`forceProfile`: The profile to use when opening the folder/workspace. Defaults to the current profile. ' + + '`forceTempProfile`: Whether to use a temporary profile when opening the folder/workspace. Defaults to false. ' + + '`filesToOpen`: An array of files to open in the new window. Defaults to an empty array. ' + 'Note, for backward compatibility, options can also be of type boolean, representing the `forceNewWindow` setting.', constraint: (value: any) => value === undefined || typeof value === 'object' || typeof value === 'boolean' } From 5a79cf41b9f569ea5662464db956c3768de3a133 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 11 Jun 2025 12:35:59 -0700 Subject: [PATCH 204/236] fix: tweak count widget layout (#251232) --- .../contrib/preferences/browser/media/settingsEditor2.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index a4f800ab02f..18d620c221b 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -40,13 +40,13 @@ .settings-editor > .settings-header > .search-container > .settings-count-widget { position: absolute; - right: 46px; + right: 48px; top: 0px; - margin: 4px 0px; + margin: 2.5px 0px; } .settings-editor > .settings-header > .search-container.with-ai-toggle > .settings-count-widget { - right: 65px; + right: 69px; } .settings-editor > .settings-header > .search-container > .settings-count-widget:empty { From 768477eaff2f79b519afd6ae3f490faf36f7886a Mon Sep 17 00:00:00 2001 From: Anthony Kim <62267334+anthonykim1@users.noreply.github.com> Date: Wed, 11 Jun 2025 12:50:03 -0700 Subject: [PATCH 205/236] Consolidate ps1 shell integration vars into __VSCodeState (#251114) * Consolidate vscode_ps1 var into __VSCodeState * Remove comments --- .../common/scripts/shellIntegration.ps1 | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/common/scripts/shellIntegration.ps1 b/src/vs/workbench/contrib/terminal/common/scripts/shellIntegration.ps1 index 4c3dbf35a94..395d35c385b 100644 --- a/src/vs/workbench/contrib/terminal/common/scripts/shellIntegration.ps1 +++ b/src/vs/workbench/contrib/terminal/common/scripts/shellIntegration.ps1 @@ -4,7 +4,7 @@ # --------------------------------------------------------------------------------------------- # Prevent installing more than once per session -if (Test-Path variable:global:__VSCodeOriginalPrompt) { +if (Test-Path variable:global:__VSCodeState.OriginalPrompt) { return; } @@ -13,27 +13,33 @@ if ($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") { return; } -$Global:__VSCodeOriginalPrompt = $function:Prompt - -$Global:__LastHistoryId = -1 -$Global:__VSCodeIsInExecution = $false +$Global:__VSCodeState = @{ + OriginalPrompt = $function:Prompt + LastHistoryId = -1 + IsInExecution = $false + EnvVarsToReport = @() + Nonce = $null + IsStable = $null + IsWindows10 = $false +} # Store the nonce in script scope and unset the global -$Nonce = $env:VSCODE_NONCE +$Global:__VSCodeState.Nonce = $env:VSCODE_NONCE $env:VSCODE_NONCE = $null -$isStable = $env:VSCODE_STABLE +$Global:__VSCodeState.IsStable = $env:VSCODE_STABLE $env:VSCODE_STABLE = $null $__vscode_shell_env_reporting = $env:VSCODE_SHELL_ENV_REPORTING $env:VSCODE_SHELL_ENV_REPORTING = $null -$Global:envVarsToReport = @() if ($__vscode_shell_env_reporting) { - $Global:envVarsToReport = $__vscode_shell_env_reporting.Split(',') + $Global:__VSCodeState.EnvVarsToReport = $__vscode_shell_env_reporting.Split(',') } +Remove-Variable -Name __vscode_shell_env_reporting -ErrorAction SilentlyContinue $osVersion = [System.Environment]::OSVersion.Version -$isWindows10 = $IsWindows -and $osVersion.Major -eq 10 -and $osVersion.Minor -eq 0 -and $osVersion.Build -lt 22000 +$Global:__VSCodeState.IsWindows10 = $IsWindows -and $osVersion.Major -eq 10 -and $osVersion.Minor -eq 0 -and $osVersion.Build -lt 22000 +Remove-Variable -Name osVersion -ErrorAction SilentlyContinue if ($env:VSCODE_ENV_REPLACE) { $Split = $env:VSCODE_ENV_REPLACE.Split(":") @@ -80,9 +86,9 @@ function Global:Prompt() { $Result = "" # Skip finishing the command if the first command has not yet started or an execution has not # yet begun - if ($Global:__LastHistoryId -ne -1 -and $Global:__VSCodeIsInExecution -eq $true) { - $Global:__VSCodeIsInExecution = $false - if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) { + if ($Global:__VSCodeState.LastHistoryId -ne -1 -and $Global:__VSCodeState.IsInExecution -eq $true) { + $Global:__VSCodeState.IsInExecution = $false + if ($LastHistoryEntry.Id -eq $Global:__VSCodeState.LastHistoryId) { # Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command) $Result += "$([char]0x1b)]633;D`a" } @@ -101,15 +107,15 @@ function Global:Prompt() { # Send current environment variables as JSON # OSC 633 ; EnvJson ; ; - if ($Global:envVarsToReport.Count -gt 0) { + if ($Global:__VSCodeState.EnvVarsToReport.Count -gt 0) { $envMap = @{} - foreach ($varName in $envVarsToReport) { + foreach ($varName in $Global:__VSCodeState.EnvVarsToReport) { if (Test-Path "env:$varName") { $envMap[$varName] = (Get-Item "env:$varName").Value } } $envJson = $envMap | ConvertTo-Json -Compress - $Result += "$([char]0x1b)]633;EnvJson;$(__VSCode-Escape-Value $envJson);$Nonce`a" + $Result += "$([char]0x1b)]633;EnvJson;$(__VSCode-Escape-Value $envJson);$($Global:__VSCodeState.Nonce)`a" } # Before running the original prompt, put $? back to what it was: @@ -117,18 +123,18 @@ function Global:Prompt() { Write-Error "failure" -ea ignore } # Run the original prompt - $OriginalPrompt += $Global:__VSCodeOriginalPrompt.Invoke() + $OriginalPrompt += $Global:__VSCodeState.OriginalPrompt.Invoke() $Result += $OriginalPrompt # Prompt # OSC 633 ; = ST - if ($isStable -eq "0") { + if ($Global:__VSCodeState.IsStable -eq "0") { $Result += "$([char]0x1b)]633;P;Prompt=$(__VSCode-Escape-Value $OriginalPrompt)`a" } # Write command started $Result += "$([char]0x1b)]633;B`a" - $Global:__LastHistoryId = $LastHistoryEntry.Id + $Global:__VSCodeState.LastHistoryId = $LastHistoryEntry.Id return $Result } @@ -148,10 +154,10 @@ elseif ((Test-Path variable:global:GitPromptSettings) -and $Global:GitPromptSett if (Get-Module -Name PSReadLine) { [Console]::Write("$([char]0x1b)]633;P;HasRichCommandDetection=True`a") - $__VSCodeOriginalPSConsoleHostReadLine = $function:PSConsoleHostReadLine + $Global:__VSCodeState.OriginalPSConsoleHostReadLine = $function:PSConsoleHostReadLine function Global:PSConsoleHostReadLine { - $CommandLine = $__VSCodeOriginalPSConsoleHostReadLine.Invoke() - $Global:__VSCodeIsInExecution = $true + $CommandLine = $Global:__VSCodeState.OriginalPSConsoleHostReadLine.Invoke() + $Global:__VSCodeState.IsInExecution = $true # Command line # OSC 633 ; E [; [; ]] ST @@ -159,8 +165,8 @@ if (Get-Module -Name PSReadLine) { $Result += $(__VSCode-Escape-Value $CommandLine) # Only send the nonce if the OS is not Windows 10 as it seems to echo to the terminal # sometimes - if ($IsWindows10 -eq $false) { - $Result += ";$Nonce" + if ($Global:__VSCodeState.IsWindows10 -eq $false) { + $Result += ";$($Global:__VSCodeState.Nonce)" } $Result += "`a" @@ -175,9 +181,9 @@ if (Get-Module -Name PSReadLine) { } # Set ContinuationPrompt property - $ContinuationPrompt = (Get-PSReadLineOption).ContinuationPrompt - if ($ContinuationPrompt) { - [Console]::Write("$([char]0x1b)]633;P;ContinuationPrompt=$(__VSCode-Escape-Value $ContinuationPrompt)`a") + $Global:__VSCodeState.ContinuationPrompt = (Get-PSReadLineOption).ContinuationPrompt + if ($Global:__VSCodeState.ContinuationPrompt) { + [Console]::Write("$([char]0x1b)]633;P;ContinuationPrompt=$(__VSCode-Escape-Value $Global:__VSCodeState.ContinuationPrompt)`a") } } From 0fd5ef7300f0ab6ee95ce2737e03599604f1540a Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 11 Jun 2025 22:50:24 +0200 Subject: [PATCH 206/236] use regular chatAttachmentWidgets for prompt files --- .../promptInstructionsCollectionWidget.ts | 200 -------------- .../promptInstructionsWidget.ts | 176 ------------ .../chat/browser/chatAttachmentModel.ts | 62 +++-- .../chatPromptAttachmentModel.ts | 23 +- .../chatPromptAttachmentsCollection.ts | 261 ++++-------------- .../chat/browser/chatAttachmentWidgets.ts | 87 ++++++ .../contrib/chat/browser/chatInputPart.ts | 66 ++--- .../contrib/chat/browser/chatWidget.ts | 41 ++- .../browser/contrib/chatImplicitContext.ts | 22 +- .../contrib/chat/browser/media/chat.css | 2 +- .../promptSyntax/attachInstructionsAction.ts | 19 +- .../chat/common/chatVariableEntries.ts | 65 ++++- 12 files changed, 301 insertions(+), 723 deletions(-) delete mode 100644 src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts delete mode 100644 src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts diff --git a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts deleted file mode 100644 index c396b55a253..00000000000 --- a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsCollectionWidget.ts +++ /dev/null @@ -1,200 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { URI } from '../../../../../../base/common/uri.js'; -import { Emitter } from '../../../../../../base/common/event.js'; -import { ResourceLabels } from '../../../../../browser/labels.js'; -import { Disposable } from '../../../../../../base/common/lifecycle.js'; -import { ILogService } from '../../../../../../platform/log/common/log.js'; -import { InstructionsAttachmentWidget } from './promptInstructionsWidget.js'; -import { IModelService } from '../../../../../../editor/common/services/model.js'; -import { INSTRUCTIONS_LANGUAGE_ID } from '../../../common/promptSyntax/promptTypes.js'; -import { ILanguageService } from '../../../../../../editor/common/languages/language.js'; -import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { ChatPromptAttachmentsCollection } from '../../chatAttachmentModel/chatPromptAttachmentsCollection.js'; - -/** - * Widget for a collection of prompt instructions attachments. - * See {@link InstructionsAttachmentWidget}. - */ -export class PromptInstructionsAttachmentsCollectionWidget extends Disposable { - /** - * List of child instruction attachment widgets. - */ - private children: InstructionsAttachmentWidget[] = []; - - /** - * Event that fires when number of attachments change - * - * See {@link onAttachmentsChange}. - */ - private _onAttachmentsChange = this._register(new Emitter()); - /** - * Subscribe to the event that fires when number of attachments change. - */ - public readonly onAttachmentsChange = this._onAttachmentsChange.event; - - /** - * The parent DOM node this widget was rendered into. - */ - private parentNode: HTMLElement | undefined; - - /** - * Get all `URI`s of all valid references, including all - * the possible references nested inside the children. - */ - public get references(): readonly URI[] { - return this.model.references; - } - - /** - * Get the list of all prompt instruction attachment variables, including all - * nested child references of each attachment explicitly attached by user. - */ - public get chatAttachments() { - return this.model.chatAttachments; - } - - /** - * Get a promise that resolves when parsing/resolving processes - * are fully completed, including all possible nested child references. - */ - public allSettled() { - return this.model.allSettled(); - } - - /** - * Check if child widget list is empty (no attachments present). - */ - public get empty(): boolean { - return this.children.length === 0; - } - - /** - * Check if any of the attachments is a prompt file. - */ - public get hasInstructions(): boolean { - return this.references.some((uri) => { - const model = this.modelService.getModel(uri); - const languageId = model ? model.getLanguageId() : this.languageService.guessLanguageIdByFilepathOrFirstLine(uri); - return languageId === INSTRUCTIONS_LANGUAGE_ID; - }); - } - - constructor( - private readonly model: ChatPromptAttachmentsCollection, - private readonly resourceLabels: ResourceLabels, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @ILanguageService private readonly languageService: ILanguageService, - @IModelService private readonly modelService: IModelService, - @ILogService private readonly logService: ILogService, - ) { - super(); - - // when a new attachment model is added, create a new child widget for it - this._register(this.model.onAdd((attachment) => { - const widget = this.instantiationService.createInstance( - InstructionsAttachmentWidget, - attachment, - this.resourceLabels, - ); - - // handle the child widget disposal event, removing it from the list - widget.onDispose(this.handleAttachmentDispose.bind(this, widget)); - - // register the new child widget - this.children.push(widget); - - // if parent node is present - append the widget to it, otherwise wait - // until the `render` method will be called - if (this.parentNode) { - this.parentNode.appendChild(widget.domNode); - } - - // fire the event to notify about the change in the number of attachments - this._onAttachmentsChange.fire(); - })); - } - - /** - * Handle child widget disposal. - * @param widget The child widget that was disposed. - */ - public handleAttachmentDispose(widget: InstructionsAttachmentWidget): this { - // common prefix for all log messages - const logPrefix = `[onChildDispose] Widget for instructions attachment '${widget.uri.path}'`; - - // flag to check if the widget was found in the children list - let widgetExists = false; - - // filter out disposed child widget from the list - this.children = this.children.filter((child) => { - if (child === widget) { - // because we filter out all objects here it might be ok to have multiple of them, but - // it also highlights a potential issue in our logic somewhere else, so trace a warning here - if (widgetExists) { - this.logService.warn( - `${logPrefix} is present in the children references list multiple times.`, - ); - } - - widgetExists = true; - return false; - } - - return true; - }); - - // no widget was found in the children list, while it might be ok it also - // highlights a potential issue in our logic, so trace a warning here - if (!widgetExists) { - this.logService.warn( - `${logPrefix} was disposed, but was not found in the child references.`, - ); - } - - if (!this.parentNode) { - this.logService.warn( - `${logPrefix} no parent node reference found.`, - ); - } - - // remove the child widget root node from the DOM - this.parentNode?.removeChild(widget.domNode); - - // fire the event to notify about the change in the number of attachments - this._onAttachmentsChange.fire(); - - return this; - } - - /** - * Render attachments into the provided `parentNode`. - * - * Note! this method assumes that the provided `parentNode` is cleared by the caller. - */ - public render( - parentNode: HTMLElement, - ): this { - this.parentNode = parentNode; - - for (const widget of this.children) { - this.parentNode.appendChild(widget.domNode); - } - - return this; - } - - /** - * Dispose of the widget, including all the child widget instances. - */ - public override dispose(): void { - for (const child of this.children) { - child.dispose(); - } - - super.dispose(); - } -} diff --git a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts b/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts deleted file mode 100644 index 0478cf49691..00000000000 --- a/src/vs/workbench/contrib/chat/browser/attachments/promptInstructions/promptInstructionsWidget.ts +++ /dev/null @@ -1,176 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { localize } from '../../../../../../nls.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import * as dom from '../../../../../../base/browser/dom.js'; -import { ResourceLabels } from '../../../../../browser/labels.js'; -import { Codicon } from '../../../../../../base/common/codicons.js'; -import { ThemeIcon } from '../../../../../../base/common/themables.js'; -import { ResourceContextKey } from '../../../../../common/contextkeys.js'; -import { Button } from '../../../../../../base/browser/ui/button/button.js'; -import { DisposableStore } from '../../../../../../base/common/lifecycle.js'; -import { basename, dirname } from '../../../../../../base/common/resources.js'; -import { ILabelService } from '../../../../../../platform/label/common/label.js'; -import { StandardMouseEvent } from '../../../../../../base/browser/mouseEvent.js'; -import { IModelService } from '../../../../../../editor/common/services/model.js'; -import { IHoverService } from '../../../../../../platform/hover/browser/hover.js'; -import { ILanguageService } from '../../../../../../editor/common/languages/language.js'; -import { FileKind, IFileService } from '../../../../../../platform/files/common/files.js'; -import { IMenuService, MenuId } from '../../../../../../platform/actions/common/actions.js'; -import { getCleanPromptName } from '../../../common/promptSyntax/config/promptFileLocations.js'; -import { ObservableDisposable } from '../../../common/promptSyntax/utils/observableDisposable.js'; -import { IContextKeyService } from '../../../../../../platform/contextkey/common/contextkey.js'; -import { ChatPromptAttachmentModel } from '../../chatAttachmentModel/chatPromptAttachmentModel.js'; -import { IContextMenuService } from '../../../../../../platform/contextview/browser/contextView.js'; -import { getDefaultHoverDelegate } from '../../../../../../base/browser/ui/hover/hoverDelegateFactory.js'; -import { getFlatContextMenuActions } from '../../../../../../platform/actions/browser/menuEntryActionViewItem.js'; - -/** - * Widget for a single prompt instructions attachment. - */ -export class InstructionsAttachmentWidget extends ObservableDisposable { - /** - * The root DOM node of the widget. - */ - public readonly domNode: HTMLElement; - - /** - * Get the `URI` associated with the model reference. - */ - public get uri(): URI { - return this.model.reference.uri; - } - - /** - * Temporary disposables used for rendering purposes. - */ - private readonly renderDisposables = this._register(new DisposableStore()); - - constructor( - private readonly model: ChatPromptAttachmentModel, - private readonly resourceLabels: ResourceLabels, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IHoverService private readonly hoverService: IHoverService, - @ILabelService private readonly labelService: ILabelService, - @IMenuService private readonly menuService: IMenuService, - @IFileService private readonly fileService: IFileService, - @ILanguageService private readonly languageService: ILanguageService, - @IModelService private readonly modelService: IModelService, - ) { - super(); - - this.domNode = dom.$('.chat-prompt-attachment.chat-attached-context-attachment.show-file-icons.implicit'); - - this._register(this.model.onUpdate(this.render.bind(this))); - this._register(this.model.onDispose(this.dispose.bind(this))); - - this.render(); - } - - /** - * Render this widget. - */ - private render() { - dom.clearNode(this.domNode); - this.renderDisposables.clear(); - this.domNode.classList.remove('warning', 'error', 'disabled'); - - const { topError } = this.model; - - const label = this.resourceLabels.create(this.domNode, { supportIcons: true }); - const file = this.model.reference.uri; - - const fileBasename = basename(file); - const fileDirname = dirname(file); - const friendlyName = `${fileBasename} ${fileDirname}`; - const isPrompt = this.languageService.guessLanguageIdByFilepathOrFirstLine(file) === 'prompt'; - const ariaLabel = isPrompt - ? localize('chat.promptAttachment', "Prompt file, {0}", friendlyName) - : localize('chat.instructionsAttachment', "Instructions attachment, {0}", friendlyName); - const typeLabel = isPrompt - ? localize('prompt', "Prompt") - : localize('instructions', "Instructions"); - - - const uriLabel = this.labelService.getUriLabel(file, { relative: true }); - - let title = `${typeLabel} ${uriLabel}`; - - // if there are some errors/warning during the process of resolving - // attachment references (including all the nested child references), - // add the issue details in the hover title for the attachment, one - // error/warning at a time because there is a limited space available - if (topError) { - const { errorSubject: subject } = topError; - const isError = (subject === 'root'); - - this.domNode.classList.add( - (isError) ? 'error' : 'warning', - ); - - const severity = (isError) - ? localize('error', "Error") - : localize('warning', "Warning"); - - title += `\n[${severity}]: ${topError.localizedMessage}`; - } - - const fileWithoutExtension = getCleanPromptName(file); - label.setFile(URI.file(fileWithoutExtension), { - fileKind: FileKind.FILE, - hidePath: true, - range: undefined, - title, - icon: ThemeIcon.fromId(Codicon.bookmark.id), - extraClasses: [], - }); - this.domNode.ariaLabel = ariaLabel; - this.domNode.tabIndex = 0; - - const hintElement = dom.append(this.domNode, dom.$('span.chat-implicit-hint', undefined, typeLabel)); - this._register(this.hoverService.setupManagedHover(getDefaultHoverDelegate('element'), hintElement, title)); - - // create the `remove` button - const removeButton = this.renderDisposables.add( - new Button( - this.domNode, - { - supportIcons: true, - title: localize('remove', "Remove"), - }, - ), - ); - - removeButton.icon = Codicon.close; - this.renderDisposables.add(removeButton.onDidClick((e) => { - e.stopPropagation(); - this.model.dispose(); - })); - - // context menu - const scopedContextKeyService = this.renderDisposables.add(this.contextKeyService.createScoped(this.domNode)); - - const resourceContextKey = this.renderDisposables.add( - new ResourceContextKey(scopedContextKeyService, this.fileService, this.languageService, this.modelService), - ); - resourceContextKey.set(file); - - this.renderDisposables.add(dom.addDisposableListener(this.domNode, dom.EventType.CONTEXT_MENU, async domEvent => { - const event = new StandardMouseEvent(dom.getWindow(domEvent), domEvent); - dom.EventHelper.stop(domEvent, true); - - this.contextMenuService.showContextMenu({ - contextKeyService: scopedContextKeyService, - getAnchor: () => event, - getActions: () => { - const menu = this.menuService.getMenuActions(MenuId.ChatInputResourceAttachmentContext, scopedContextKeyService, { arg: file }); - return getFlatContextMenuActions(menu); - }, - }); - })); - } -} diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts index 4ee4a59ea99..1533fcca6cd 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts @@ -8,7 +8,7 @@ import { Emitter } from '../../../../base/common/event.js'; import { basename } from '../../../../base/common/resources.js'; import { IRange } from '../../../../editor/common/core/range.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; -import { IChatRequestFileEntry, IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; +import { IChatRequestFileEntry, IChatRequestVariableEntry, isPromptFileVariableEntry, toPromptFileVariableEntry } from '../common/chatVariableEntries.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ChatPromptAttachmentsCollection } from './chatAttachmentModel/chatPromptAttachmentsCollection.js'; import { IFileService } from '../../../../platform/files/common/files.js'; @@ -28,7 +28,7 @@ export interface IChatAttachmentChangeEvent { export class ChatAttachmentModel extends Disposable { - readonly promptInstructions: ChatPromptAttachmentsCollection; + private readonly _promptInstructions: ChatPromptAttachmentsCollection; private readonly _attachments = new Map(); private _onDidChange = this._register(new Emitter()); @@ -42,7 +42,8 @@ export class ChatAttachmentModel extends Disposable { ) { super(); - this.promptInstructions = this._register(instaService.createInstance(ChatPromptAttachmentsCollection)); + this._promptInstructions = this._register(instaService.createInstance(ChatPromptAttachmentsCollection)); + this._register(this._promptInstructions.onUpdate(variable => this._onDidChange.fire({ updated: [variable], deleted: [], added: [] }))); } get attachments(): ReadonlyArray { @@ -74,6 +75,23 @@ export class ChatAttachmentModel extends Disposable { } } + addPromptFiles(promptFiles: readonly URI[]): void { + const variables = promptFiles.map(uri => toPromptFileVariableEntry(uri, true)); + this.addContext(...variables); + } + + hasPromptFiles(languageId: string): boolean { + return this._promptInstructions.hasPromptFiles(languageId); + } + + /** + * Get the list of all prompt instruction attachment variables, including all + * nested child references of each attachment explicitly attached by user. + */ + getPromptFileVariables(): Promise { + return this._promptInstructions.getAttachments(); + } + addFolder(uri: URI) { this.addContext({ kind: 'directory', @@ -84,14 +102,22 @@ export class ChatAttachmentModel extends Disposable { } clear(clearStickyAttachments: boolean = false): void { - const deleted = Array.from(this._attachments.keys()); - this._attachments.clear(); - if (clearStickyAttachments) { - this.promptInstructions.clear(); + const deleted = Array.from(this._attachments.keys()); + this._attachments.clear(); + this._promptInstructions.clear(); + this._onDidChange.fire({ deleted, added: [], updated: [] }); + } else { + const deleted: string[] = []; + const allIds = Array.from(this._attachments.keys()); + for (const id of allIds) { + const entry = this._attachments.get(id); + if (entry && !isPromptFileVariableEntry(entry)) { + this._attachments.delete(id); + } + } + this._onDidChange.fire({ deleted, added: [], updated: [] }); } - - this._onDidChange.fire({ deleted, added: [], updated: [] }); } addContext(...attachments: IChatRequestVariableEntry[]) { @@ -113,24 +139,24 @@ export class ChatAttachmentModel extends Disposable { const updated: IChatRequestVariableEntry[] = []; for (const id of toDelete) { - if (this._attachments.delete(id)) { + const item = this._attachments.get(id); + if (item) { + this._attachments.delete(id); deleted.push(id); + if (isPromptFileVariableEntry(item)) { + this._promptInstructions.remove(item); + } } } for (const item of upsert) { - - if (item.kind === 'promptFile') { - // TODO@jrieken @aeschli @legomushroom Let's make instructions normal - // attachment types so that this isn't needed - this.promptInstructions.add(item.value as URI); - continue; - } - const oldItem = this._attachments.get(item.id); if (!oldItem) { this._attachments.set(item.id, item); added.push(item); + if (isPromptFileVariableEntry(item)) { + this._promptInstructions.add([item]); + } } else if (!equals(oldItem, item)) { this._attachments.set(item.id, item); updated.push(item); diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts index 4cfa1311c62..b88ab8a540a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts @@ -4,12 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from '../../../../../base/common/uri.js'; -import { Emitter } from '../../../../../base/common/event.js'; import { PromptParser } from '../../common/promptSyntax/parsers/promptParser.js'; import { BasePromptParser } from '../../common/promptSyntax/parsers/basePromptParser.js'; -import { ObservableDisposable } from '../../common/promptSyntax/utils/observableDisposable.js'; import { IPromptContentsProvider } from '../../common/promptSyntax/contentProviders/types.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; +import { Disposable } from '../../../../../base/common/lifecycle.js'; /** * Type for a generic prompt parser object. @@ -19,7 +18,7 @@ type TPromptParser = BasePromptParser; /** * Model for a single chat prompt instructions attachment. */ -export class ChatPromptAttachmentModel extends ObservableDisposable { +export class ChatPromptAttachmentModel extends Disposable { /** * Private reference of the underlying prompt instructions * reference instance. @@ -84,22 +83,10 @@ export class ChatPromptAttachmentModel extends ObservableDisposable { return this.reference.topError; } - /** - * Event that fires when the error condition of the prompt - * reference changes. - * - * See {@link onUpdate}. - */ - protected _onUpdate = this._register(new Emitter()); - /** - * Subscribe to the event that fires when the underlying prompt - * reference instance is updated. - * See {@link BasePromptParser.onUpdate}. - */ - public readonly onUpdate = this._onUpdate.event; constructor( public readonly uri: URI, + private readonly _onUpdate: () => void, @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); @@ -115,9 +102,7 @@ export class ChatPromptAttachmentModel extends ObservableDisposable { ) ); - this._register(this._reference.onUpdate( - this._onUpdate.fire.bind(this._onUpdate), - )); + this._register(this._reference.onUpdate(() => this._onUpdate())); } /** diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts index 1732ee9508a..af7381fd783 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts @@ -4,108 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter } from '../../../../../base/common/event.js'; -import { Disposable, DisposableMap } from '../../../../../base/common/lifecycle.js'; -import { basename, isEqual } from '../../../../../base/common/resources.js'; -import { URI } from '../../../../../base/common/uri.js'; -import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; +import { Disposable } from '../../../../../base/common/lifecycle.js'; +import { ResourceMap } from '../../../../../base/common/map.js'; +import { ILanguageService } from '../../../../../editor/common/languages/language.js'; +import { IModelService } from '../../../../../editor/common/services/model.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; -import { IChatRequestVariableEntry, IPromptVariableEntry, isChatRequestFileEntry } from '../../common/chatVariableEntries.js'; -import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; -import { IPromptFileReference } from '../../common/promptSyntax/parsers/types.js'; +import { IChatRequestVariableEntry, IPromptFileVariableEntry, toPromptFileVariableEntry } from '../../common/chatVariableEntries.js'; + import { ChatPromptAttachmentModel } from './chatPromptAttachmentModel.js'; -/** - * Prefix for all prompt instruction variable IDs. - */ -const PROMPT_VARIABLE_ID_PREFIX = 'vscode.prompt.instructions'; - -/** - * Prompt IDs start with a well-defined prefix that is used by - * the copilot extension to identify prompt references. - * - * @param uri The URI of the prompt file. - * @param isRoot Whether the prompt file is the root file, or a - * child reference that is nested inside the root file. - */ -export const createPromptVariableId = ( - uri: URI, - isRoot: boolean, -): string => { - // the default prefix that is used for all prompt files - let prefix = PROMPT_VARIABLE_ID_PREFIX; - // if the reference is the root object, add the `.root` suffix - if (isRoot) { - prefix += '.root'; - } - - // final `id` for all `prompt files` starts with the well-defined - // part that the copilot extension(or other chatbot) can rely on - return `${prefix}__${uri}`; -}; - -/** - * Utility to convert a {@link reference} to a chat variable entry. - * The `id` of the chat variable can be one of the following: - * - * - `vscode.prompt.instructions__`: for all non-root prompt file references - * - `vscode.prompt.instructions.root__`: for *root* prompt file references - * - ``: for the rest of references(the ones that do not point to a prompt file) - * - * @param reference A reference object to convert to a chat variable entry. - * @param isRoot If the reference is the root reference in the references tree. - * This object most likely was explicitly attached by the user. - */ -export const toChatVariable = ( - reference: Pick, - isRoot: boolean, -): IPromptVariableEntry => { - const { uri, isPromptFile } = reference; - - // default `id` is the stringified `URI` - let id = `${uri}`; - - // prompts have special `id`s that are used by the copilot extension - if (isPromptFile) { - id = createPromptVariableId(uri, isRoot); - } - - const name = (isPromptFile) - ? `prompt:${basename(uri)}` - : `file:${basename(uri)}`; - - const modelDescription = (isPromptFile) - ? 'Prompt instructions file' - : 'File attachment'; - - return { - id, - name, - value: uri, - kind: 'file', - modelDescription, - isRoot, - }; -}; - -/** - * Checks of a provided chat variable is a `prompt file` variable. - */ -export function isPromptFileChatVariable( - variable: IChatRequestVariableEntry, -): variable is IPromptVariableEntry { - return isChatRequestFileEntry(variable) - && variable.id.startsWith(PROMPT_VARIABLE_ID_PREFIX); -} - -/** - * Adds the provided `newReference` to the list of chat variables if it is not already present. - */ -export function addPromptFileChatVariable(variables: IChatRequestVariableEntry[], newReference: URI): void { - if (!variables.some(variable => isPromptFileChatVariable(variable) && isEqual(IChatRequestVariableEntry.toUri(variable), newReference))) { - variables.push(toChatVariable({ uri: newReference, isPromptFile: true }, true)); - } -} - /** * Model for a collection of prompt instruction attachments. * See {@linkcode ChatPromptAttachmentModel} for individual attachment. @@ -116,79 +23,45 @@ export class ChatPromptAttachmentsCollection extends Disposable { * * See {@linkcode onUpdate}. */ - protected _onUpdate = this._register(new Emitter()); + protected _onUpdate = this._register(new Emitter()); /** * Subscribe to the `onUpdate` event. */ public onUpdate = this._onUpdate.event; - /** - * Event that fires when a new prompt instruction attachment is added. - * See {@linkcode onAdd}. - */ - protected _onAdd = this._register(new Emitter()); - /** - * The `onAdd` event fires when a new prompt instruction attachment is added. - */ - public onAdd = this._onAdd.event; - - /** - * Event that fires when a new prompt instruction attachment is removed. - * See {@linkcode onRemove}. - */ - protected _onRemove = this._register(new Emitter()); - /** - * The `onRemove` event fires when a new prompt instruction attachment is removed. - */ - public onRemove = this._onRemove.event; /** * List of all prompt instruction attachments. */ - private attachments: DisposableMap = - this._register(new DisposableMap()); + private _attachments: ResourceMap = new ResourceMap(); /** - * Get all `URI`s of all valid references, including all - * the possible references nested inside the children. + * Check if any of the attachments is a prompt file. */ - public get references(): readonly URI[] { - const result = []; + public hasPromptFiles(promptFileLanguageId: string): boolean { + const hasLanguage = ({ uri }: ChatPromptAttachmentModel) => { + const model = this.modelService.getModel(uri); + const languageId = model ? model.getLanguageId() : this.languageService.guessLanguageIdByFilepathOrFirstLine(uri); + return languageId === promptFileLanguageId; + }; - for (const child of this.attachments.values()) { - result.push(...child.references); - } - - return result; - } - - /** - * Get list of tools associated with all attached prompt files. - */ - public get toolsMetadata(): readonly string[] | null { - const result = []; - - for (const child of this.attachments.values()) { - const { toolsMetadata } = child; - - if (toolsMetadata === null) { - continue; + for (const child of this._attachments.values()) { + if (hasLanguage(child)) { + return true; } - - result.push(...toolsMetadata); } - - // return unique list of all tools - return [...new Set(result)]; + return false; } /** * Get the list of all prompt instruction attachment variables, including all * nested child references of each attachment explicitly attached by user. */ - public get chatAttachments(): readonly IChatRequestVariableEntry[] { + public async getAttachments(): Promise { + await this.allSettled(); + const result = []; - const attachments = [...this.attachments.values()]; + const attachments = [...this._attachments.values()]; for (const attachment of attachments) { const { reference } = attachment; @@ -197,20 +70,12 @@ export class ChatPromptAttachmentsCollection extends Disposable { // we do the same here - first add all child references of the model result.push( ...reference.allValidReferences.map((link) => { - return toChatVariable(link, false); + return toPromptFileVariableEntry(link.uri, false); }), ); // then add the root reference of the model itself - result.push( - toChatVariable({ - uri: reference.uri, - // the attached file must have been a prompt file therefore - // we force that assumption here; this makes sure that prompts - // in untitled documents can be also attached to the chat input - isPromptFile: true, - }, true), - ); + result.push(toPromptFileVariableEntry(reference.uri, true)); } return result; @@ -220,92 +85,70 @@ export class ChatPromptAttachmentsCollection extends Disposable { * Promise that resolves when parsing of all attached prompt instruction * files completes, including parsing of all its possible child references. */ - public async allSettled(): Promise { - const attachments = [...this.attachments.values()]; + async allSettled(): Promise { + const attachments = [...this._attachments.values()]; await Promise.allSettled( attachments.map((attachment) => { return attachment.allSettled; }), ); - - return this; } constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, - @IConfigurationService private readonly configService: IConfigurationService, + @ILanguageService private readonly languageService: ILanguageService, + @IModelService private readonly modelService: IModelService, ) { super(); } /** - * Add a prompt instruction attachment instance with the provided `URI`. - * @param uri URI of the prompt instruction attachment to add. + * Add prompt instruction attachment instances */ - public add(uris: URI | readonly URI[]) { - const uriList = Array.isArray(uris) ? uris : [uris]; + public add(entries: IPromptFileVariableEntry[]) { + for (const entry of entries) { + const uri = entry.value; - // if no URIs provided, nothing to do - if (uriList.length === 0) { - return; - } - - for (const uri of uriList) { // if already exists, nothing to do - if (this.attachments.has(uri.path)) { + if (this._attachments.has(uri)) { continue; } - const instruction = this.instantiationService.createInstance(ChatPromptAttachmentModel, uri); - instruction.addDisposables( - instruction.onDispose(() => { - // note! we have to use `deleteAndLeak` here, because the `*AndDispose` - // alternative results in an infinite loop of calling this callback - this.attachments.deleteAndLeak(uri.path); - this._onUpdate.fire(); - this._onRemove.fire(instruction); - }), - instruction.onUpdate(this._onUpdate.fire), - ); - - this.attachments.set(uri.path, instruction); - this._onAdd.fire(instruction); - this._onUpdate.fire(); + const instruction = this.instantiationService.createInstance(ChatPromptAttachmentModel, uri, () => this._onUpdate.fire(entry)); + this._attachments.set(uri, instruction); } } /** - * Remove a prompt instruction attachment instance by provided `URI`. - * @param uri URI of the prompt instruction attachment to remove. + * Remove a prompt instruction attachment instancs */ - public remove(uri: URI): this { - // if does not exist, nothing to do - if (!this.attachments.has(uri.path)) { - return this; - } + public remove(entry: IPromptFileVariableEntry): this { + const uri = entry.value; - this.attachments.deleteAndDispose(uri.path); + const attachment = this._attachments.get(uri); + if (attachment) { + this._attachments.delete(uri); + attachment.dispose(); + } return this; } - /** - * Checks if the prompt instructions feature is enabled in the user settings. - */ - public get featureEnabled(): boolean { - return PromptsConfig.enabled(this.configService); - } - /** * Clear all prompt instruction attachments. */ public clear(): this { - for (const attachment of this.attachments.values()) { - this.remove(attachment.uri); + for (const attachment of this._attachments.values()) { + attachment.dispose(); } + this._attachments.clear(); - this._onUpdate.fire(); return this; } + + public override dispose(): void { + super.dispose(); + this.clear(); // disposes of all attachments + } } diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts index eb6be7eaaf0..6e1e378ceaa 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts @@ -53,6 +53,7 @@ import { IChatContentReference } from '../common/chatService.js'; import { getHistoryItemEditorTitle, getHistoryItemHoverContent } from '../../scm/browser/util.js'; import { ILanguageModelToolsService, ToolSet } from '../common/languageModelToolsService.js'; import { Iterable } from '../../../../base/common/iterator.js'; +import { getCleanPromptName } from '../common/promptSyntax/config/promptFileLocations.js'; abstract class AbstractChatAttachmentWidget extends Disposable { public readonly element: HTMLElement; @@ -474,6 +475,92 @@ export class DefaultChatAttachmentWidget extends AbstractChatAttachmentWidget { } } +export class PromptFileAttachmentWidget extends AbstractChatAttachmentWidget { + + private hintElement: HTMLElement; + + constructor( + resource: URI, + attachment: IChatRequestVariableEntry, + correspondingContentReference: IChatContentReference | undefined, + currentLanguageModel: ILanguageModelChatMetadataAndIdentifier | undefined, + options: { shouldFocusClearButton: boolean; supportsDeletion: boolean }, + container: HTMLElement, + contextResourceLabels: ResourceLabels, + hoverDelegate: IHoverDelegate, + @ICommandService commandService: ICommandService, + @IOpenerService openerService: IOpenerService, + @ILabelService private readonly labelService: ILabelService, + @ILanguageService private readonly languageService: ILanguageService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + ) { + super(attachment, options, container, contextResourceLabels, hoverDelegate, currentLanguageModel, commandService, openerService); + + + this.hintElement = dom.append(this.element, dom.$('span.chat-implicit-hint')); + + this.updateLabel(resource); + + this.instantiationService.invokeFunction(accessor => { + this._register(hookUpResourceAttachmentDragAndContextMenu(accessor, this.element, resource)); + }); + this.addResourceOpenHandlers(resource, undefined); + + this.attachClearButton(); + } + + private updateLabel(resource: URI) { + const fileBasename = basename(resource.path); + const fileDirname = dirname(resource.path); + const friendlyName = `${fileBasename} ${fileDirname}`; + const isPrompt = this.languageService.guessLanguageIdByFilepathOrFirstLine(resource) === 'prompt'; + const ariaLabel = isPrompt + ? localize('chat.promptAttachment', "Prompt file, {0}", friendlyName) + : localize('chat.instructionsAttachment', "Instructions attachment, {0}", friendlyName); + const typeLabel = isPrompt + ? localize('prompt', "Prompt") + : localize('instructions', "Instructions"); + + const uriLabel = this.labelService.getUriLabel(resource, { relative: true }); + const title = `${typeLabel} ${uriLabel}`; + + //const { topError } = this.promptFile; + this.element.classList.remove('warning', 'error'); + + // if there are some errors/warning during the process of resolving + // attachment references (including all the nested child references), + // add the issue details in the hover title for the attachment, one + // error/warning at a time because there is a limited space available + // if (topError) { + // const { errorSubject: subject } = topError; + // const isError = (subject === 'root'); + // this.element.classList.add((isError) ? 'error' : 'warning'); + + // const severity = (isError) + // ? localize('error', "Error") + // : localize('warning', "Warning"); + + // title += `\n[${severity}]: ${topError.localizedMessage}`; + // } + + const fileWithoutExtension = getCleanPromptName(resource); + this.label.setFile(URI.file(fileWithoutExtension), { + fileKind: FileKind.FILE, + hidePath: true, + range: undefined, + title, + icon: ThemeIcon.fromId(Codicon.bookmark.id), + extraClasses: [], + }); + + this.hintElement.innerText = typeLabel; + + + this.element.ariaLabel = ariaLabel; + } +} + + export class ToolSetOrToolItemAttachmentWidget extends AbstractChatAttachmentWidget { constructor( attachment: IChatRequestToolSetEntry | IChatRequestToolEntry, diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index c495c5cb178..353bf4d9b8c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -76,7 +76,7 @@ import { IChatAgentService } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { IChatEditingSession } from '../common/chatEditingService.js'; import { ChatEntitlement, IChatEntitlementService } from '../common/chatEntitlementService.js'; -import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry } from '../common/chatVariableEntries.js'; +import { IChatRequestVariableEntry, ChatRequestVariableSet, isPromptFileVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry, toPromptFileVariableEntry } from '../common/chatVariableEntries.js'; import { ChatMode2, IChatMode, IChatModeService, isBuiltinChatMode, validateChatMode2 } from '../common/chatModes.js'; import { IChatFollowup } from '../common/chatService.js'; import { IChatVariablesService } from '../common/chatVariables.js'; @@ -86,11 +86,9 @@ import { ChatAgentLocation, ChatConfiguration, ChatMode, isChatMode, validateCha import { ILanguageModelChatMetadata, ILanguageModelChatMetadataAndIdentifier, ILanguageModelsService } from '../common/languageModels.js'; import { CancelAction, ChatEditingSessionSubmitAction, ChatOpenModelPickerActionId, ChatSubmitAction, IChatExecuteActionContext, ToggleAgentModeActionId } from './actions/chatExecuteActions.js'; import { ImplicitContextAttachmentWidget } from './attachments/implicitContextAttachment.js'; -import { PromptInstructionsAttachmentsCollectionWidget } from './attachments/promptInstructions/promptInstructionsCollectionWidget.js'; import { IChatWidget } from './chat.js'; import { ChatAttachmentModel } from './chatAttachmentModel.js'; -import { toChatVariable } from './chatAttachmentModel/chatPromptAttachmentsCollection.js'; -import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from './chatAttachmentWidgets.js'; +import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, PromptFileAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from './chatAttachmentWidgets.js'; import { IDisposableReference } from './chatContentParts/chatCollections.js'; import { CollapsibleListPool, IChatCollapsibleListItem } from './chatContentParts/chatReferencesContentPart.js'; import { ChatDragAndDrop } from './chatDragAndDrop.js'; @@ -104,6 +102,7 @@ import { ChatRelatedFiles } from './contrib/chatInputRelatedFilesContrib.js'; import { resizeImage } from './imageUtils.js'; import { IModelPickerDelegate, ModelPickerActionItem } from './modelPicker/modelPickerActionItem.js'; import { IModePickerDelegate, ModePickerActionItem } from './modelPicker/modePickerActionItem.js'; +import { PROMPT_LANGUAGE_ID } from '../common/promptSyntax/promptTypes.js'; const $ = dom.$; @@ -165,12 +164,20 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge readonly selectedToolsModel: ChatSelectedTools; - public async getAttachedAndImplicitContext(sessionId: string): Promise { - const contextArr = [...this.attachmentModel.attachments]; - if (this.implicitContext?.enabled && this.implicitContext.value) { + public async getAttachedAndImplicitContext(sessionId: string): Promise { + // prompt files may have nested child references to other prompt + // files that are resolved asynchronously, hence we need to wait + // for the entire prompt instruction tree to be processed + + const contextArr = new ChatRequestVariableSet(); + + contextArr.add(... await this.attachmentModel.getPromptFileVariables()); + contextArr.add(...this.attachmentModel.attachments); + + if (this.implicitContext?.enabled && this.implicitContext.value) { const implicitChatVariables = await this.implicitContext.toBaseEntries(); - contextArr.push(...implicitChatVariables); + contextArr.add(...implicitChatVariables); } // factor in nested file links of a prompt into the implicit context @@ -182,22 +189,12 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge // the usual URIs list of prompt instructions is `bottom-up`, therefore // we do the same here - first add all child references to the list - contextArr.push( + contextArr.add( ...variable.allValidReferences.map((link) => { - return toChatVariable(link, false); + return toPromptFileVariableEntry(link.uri, false); }), ); } - - // prompt files may have nested child references to other prompt - // files that are resolved asynchronously, hence we need to wait - // for the entire prompt instruction tree to be processed - this.promptInstructionsAttachmentsPart - .allSettled.bind(this.promptInstructionsAttachmentsPart); - - contextArr - .push(...this.promptInstructionsAttachmentsPart.chatAttachments); - return contextArr; } @@ -206,7 +203,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge */ get hasPromptFileAttachments(): boolean { // if prompt attached explicitly as a "prompt" attachment - if (this.promptInstructionsAttachmentsPart.hasInstructions) { + if (this._attachmentModel.hasPromptFiles(PROMPT_LANGUAGE_ID)) { return true; } @@ -360,12 +357,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge private readonly getInputState: () => IChatInputState; - /** - * Child widget of prompt instruction attachments. - * See {@linkcode PromptInstructionsAttachmentsCollectionWidget}. - */ - private promptInstructionsAttachmentsPart: PromptInstructionsAttachmentsCollectionWidget; - /** * Number consumers holding the 'generating' lock. */ @@ -468,19 +459,11 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this._hasFileAttachmentContextKey = ChatContextKeys.hasFileAttachments.bindTo(contextKeyService); - this.promptInstructionsAttachmentsPart = this._register( - instantiationService.createInstance( - PromptInstructionsAttachmentsCollectionWidget, - this.attachmentModel.promptInstructions, - this._contextResourceLabels, - ), - ); - // trigger re-layout of chat input when number of instruction attachment changes - this._register(this.promptInstructionsAttachmentsPart.onAttachmentsChange(() => { - this._handleAttachedContextChange(); - this._onDidChangeHeight.fire(); - })); + // this._register(this._attachmentModel.promptInstructions.onUpdate(() => { + // this._handleAttachedContextChange(); + // this._onDidChangeHeight.fire(); + // })); this.initSelectedModel(); @@ -1294,7 +1277,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge })); const attachments = [...this.attachmentModel.attachments.entries()]; - const hasAttachments = Boolean(attachments.length) || Boolean(this.implicitContext?.value) || !this.promptInstructionsAttachmentsPart.empty; + const hasAttachments = Boolean(attachments.length) || Boolean(this.implicitContext?.value); dom.setVisibility(Boolean(hasAttachments || (this.addFilesToolbar && !this.addFilesToolbar.isEmpty())), this.attachmentsContainer); dom.setVisibility(hasAttachments, this.attachedContextContainer); if (!attachments.length) { @@ -1303,7 +1286,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } this.promptFileAttached.set(this.hasPromptFileAttachments); - this.promptInstructionsAttachmentsPart.render(container); for (const [index, attachment] of attachments) { const resource = URI.isUri(attachment.value) ? attachment.value : attachment.value && typeof attachment.value === 'object' && 'uri' in attachment.value && URI.isUri(attachment.value.uri) ? attachment.value.uri : undefined; @@ -1316,6 +1298,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge attachmentWidget = this.instantiationService.createInstance(ToolSetOrToolItemAttachmentWidget, attachment, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); } else if (resource && isNotebookOutputVariableEntry(attachment)) { attachmentWidget = this.instantiationService.createInstance(NotebookCellOutputChatAttachmentWidget, resource, attachment, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); + } else if (resource && isPromptFileVariableEntry(attachment)) { + attachmentWidget = this.instantiationService.createInstance(PromptFileAttachmentWidget, resource, attachment, undefined, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); } else if (resource && (attachment.kind === 'file' || attachment.kind === 'directory')) { attachmentWidget = this.instantiationService.createInstance(FileAttachmentWidget, resource, range, attachment, undefined, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); } else if (isImageVariableEntry(attachment)) { diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index d24c33e180a..acb42d186d5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -59,7 +59,6 @@ import { handleModeSwitch } from './actions/chatActions.js'; import { ChatTreeItem, IChatAcceptInputOptions, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileTreeInfo, IChatListItemRendererOptions, IChatWidget, IChatWidgetService, IChatWidgetViewContext, IChatWidgetViewOptions } from './chat.js'; import { ChatAccessibilityProvider } from './chatAccessibilityProvider.js'; import { ChatAttachmentModel } from './chatAttachmentModel.js'; -import { addPromptFileChatVariable, isPromptFileChatVariable } from './chatAttachmentModel/chatPromptAttachmentsCollection.js'; import { ChatInputPart, IChatInputStyles } from './chatInputPart.js'; import { ChatListDelegate, ChatListItemRenderer, IChatRendererDelegate } from './chatListRenderer.js'; import { ChatEditorOptions } from './chatOptions.js'; @@ -68,7 +67,8 @@ import './media/chatAgentHover.css'; import './media/chatViewWelcome.css'; import { ChatViewWelcomePart } from './viewsWelcome/chatViewWelcomeController.js'; import { MicrotaskDelay } from '../../../../base/common/symbols.js'; -import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; +import { IChatRequestVariableEntry, ChatRequestVariableSet as ChatRequestVariableSet, isPromptFileVariableEntry, toPromptFileVariableEntry } from '../common/chatVariableEntries.js'; +import { PromptsConfig } from '../common/promptSyntax/config/config.js'; const $ = dom.$; @@ -1205,16 +1205,16 @@ export class ChatWidget extends Disposable implements IChatWidget { return inputState; } - private _findPromptFileInContext(attachedContext: IChatRequestVariableEntry[]): URI | undefined { - for (const item of attachedContext) { - if (isPromptFileChatVariable(item) && item.isRoot) { + private _findPromptFileInContext(attachedContext: ChatRequestVariableSet): URI | undefined { + for (const item of attachedContext.asArray()) { + if (isPromptFileVariableEntry(item) && item.isRoot) { return IChatRequestVariableEntry.toUri(item); } } return undefined; } - private async _applyPromptFileIfSet(requestInput: { input: string; attachedContext: IChatRequestVariableEntry[] }): Promise { + private async _applyPromptFileIfSet(requestInput: { input: string; attachedContext: ChatRequestVariableSet }): Promise { let metadata: IMetadata | undefined; @@ -1224,7 +1224,8 @@ export class ChatWidget extends Disposable implements IChatWidget { metadata = await this.promptsService.resolvePromptSlashCommand(agentSlashPromptPart.slashPromptCommand); if (metadata) { // add the prompt file to the context, but not sticky - addPromptFileChatVariable(requestInput.attachedContext, metadata.uri); + requestInput.attachedContext.add(toPromptFileVariableEntry(metadata.uri, true)); + // remove the slash command from the input requestInput.input = this.parsedInput.parts.filter(part => !(part instanceof ChatRequestSlashPromptPart)).map(part => part.text).join('').trim(); } @@ -1281,8 +1282,7 @@ export class ChatWidget extends Disposable implements IChatWidget { const isUserQuery = !query; - const { promptInstructions } = this.inputPart.attachmentModel; - const instructionsEnabled = promptInstructions.featureEnabled; + const instructionsEnabled = PromptsConfig.enabled(this.configurationService); if (instructionsEnabled) { await this._applyPromptFileIfSet(requestInputs); await this.autoAttachInstructions(requestInputs.attachedContext); @@ -1290,7 +1290,7 @@ export class ChatWidget extends Disposable implements IChatWidget { if (this.viewOptions.enableWorkingSet !== undefined && this.input.currentMode === ChatMode.Edit && !this.chatService.edits2Enabled) { const uniqueWorkingSetEntries = new ResourceSet(); // NOTE: this is used for bookkeeping so the UI can avoid rendering references in the UI that are already shown in the working set - const editingSessionAttachedContext: IChatRequestVariableEntry[] = requestInputs.attachedContext; + const editingSessionAttachedContext: ChatRequestVariableSet = requestInputs.attachedContext; // Collect file variables from previous requests before sending the request const previousRequests = this.viewModel.model.getRequests(); @@ -1299,7 +1299,7 @@ export class ChatWidget extends Disposable implements IChatWidget { if (URI.isUri(variable.value) && variable.kind === 'file') { const uri = variable.value; if (!uniqueWorkingSetEntries.has(uri)) { - editingSessionAttachedContext.push(variable); + editingSessionAttachedContext.add(variable); uniqueWorkingSetEntries.add(variable.value); } } @@ -1330,7 +1330,7 @@ export class ChatWidget extends Disposable implements IChatWidget { location: this.location, locationData: this._location.resolveData?.(), parserContext: { selectedAgent: this._lastSelectedAgent, mode: this.inputPart.currentMode }, - attachedContext: requestInputs.attachedContext, + attachedContext: requestInputs.attachedContext.asArray(), noCommandDetection: options?.noCommandDetection, userSelectedTools: this.getUserSelectedTools(), modeInstructions: this.input.currentMode2.body @@ -1619,24 +1619,17 @@ export class ChatWidget extends Disposable implements IChatWidget { * match file references in the attached context and then attaches * such instructions to the context. */ - private async autoAttachInstructions( - attachedContext: IChatRequestVariableEntry[], - ): Promise { + private async autoAttachInstructions(attachedContext: ChatRequestVariableSet): Promise { - const variableUris = attachedContext - .map(IChatRequestVariableEntry.toUri) - .filter(isDefined); + const variableUris = attachedContext.asArray().map(IChatRequestVariableEntry.toUri).filter(isDefined); - const automaticInstructions = await this.promptsService - .findInstructionFilesFor(variableUris); + const automaticInstructions = await this.promptsService.findInstructionFilesFor(variableUris); // add instructions to the final context list - automaticInstructions.forEach(instruction => addPromptFileChatVariable(attachedContext, instruction)); + attachedContext.add(...automaticInstructions.map(instruction => toPromptFileVariableEntry(instruction, true))); // add to attached list to make the instructions sticky - this.inputPart - .attachmentModel - .promptInstructions.add(automaticInstructions); + this.inputPart.attachmentModel.addPromptFiles(automaticInstructions); } } diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts index 1d570246e68..7f3d50eb1ce 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts @@ -21,14 +21,13 @@ import { EditorsOrder } from '../../../../common/editor.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { getNotebookEditorFromEditorPane, INotebookEditor } from '../../../notebook/browser/notebookBrowser.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { IChatRequestFileEntry, IChatRequestImplicitVariableEntry } from '../../common/chatVariableEntries.js'; +import { IChatRequestImplicitVariableEntry, IChatRequestVariableEntry, toPromptFileVariableEntry } from '../../common/chatVariableEntries.js'; import { IChatService } from '../../common/chatService.js'; import { ChatAgentLocation } from '../../common/constants.js'; import { ILanguageModelIgnoredFilesService } from '../../common/ignoredFiles.js'; import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/promptTypes.js'; import { IPromptsService, TSharedPrompt } from '../../common/promptSyntax/service/promptsService.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; -import { toChatVariable } from '../chatAttachmentModel/chatPromptAttachmentsCollection.js'; export class ChatImplicitContextContribution extends Disposable implements IWorkbenchContribution { static readonly ID = 'chat.implicitContext'; @@ -202,8 +201,7 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli get id() { if (this.prompt !== undefined) { - const variable = toChatVariable(this.prompt, true); - + const variable = toPromptFileVariableEntry(this.prompt.uri, true); return variable.id; } @@ -222,7 +220,7 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli get name(): string { if (this.prompt !== undefined) { - const variable = toChatVariable(this.prompt, true); + const variable = toPromptFileVariableEntry(this.prompt.uri, true); return variable.name; } @@ -240,7 +238,7 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli get modelDescription(): string { if (this.prompt !== undefined) { - const variable = toChatVariable(this.prompt, true); + const variable = toPromptFileVariableEntry(this.prompt.uri, true); return variable.modelDescription; } @@ -300,7 +298,7 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli this._onDidChangeValue.fire(); } - public async toBaseEntries(): Promise { + public async toBaseEntries(): Promise { // chat variable for non-prompt file attachment if (this.prompt === undefined) { return [{ @@ -319,16 +317,10 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli return [ // add all valid child references in the prompt ...this.prompt.allValidReferences.map((link) => { - return toChatVariable(link, false); + return toPromptFileVariableEntry(link.uri, false); }), // and then the root prompt reference itself - toChatVariable({ - uri: this.prompt.uri, - // the attached file must have been a prompt file therefore - // we force that assumption here; this makes sure that prompts - // in untitled documents can be also attached to the chat input - isPromptFile: true, - }, true), + toPromptFileVariableEntry(this.prompt.uri, true) ]; } diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index ce7d837ef98..62b35fbac51 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1129,7 +1129,7 @@ have to be updated for changes to the rules above, or to support more deeply nes color: inherit; text-decoration: none; } -.chat-attached-context .chat-prompt-attachment .chat-implicit-hint { +.chat-attached-context-attachment .chat-implicit-hint { opacity: 0.7; font-size: .9em; margin-top: -0.5px; diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts index d7ec82126ac..bf016fe1fad 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/attachInstructionsAction.ts @@ -24,12 +24,13 @@ import { INSTRUCTIONS_LANGUAGE_ID, PromptsType } from '../../common/promptSyntax import { compare } from '../../../../../base/common/strings.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; import { dirname } from '../../../../../base/common/resources.js'; -import { IPromptFileVariableEntry } from '../../common/chatVariableEntries.js'; +import { IPromptFileVariableEntry, toPromptFileVariableEntry } from '../../common/chatVariableEntries.js'; import { KeyMod, KeyCode } from '../../../../../base/common/keyCodes.js'; import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; import { CancellationToken } from '../../../../../base/common/cancellation.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; +import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; /** * Action ID for the `Attach Instruction` action. @@ -117,7 +118,7 @@ class AttachInstructionsAction extends Action2 { } if (skipSelectionDialog && resource) { - widget.attachmentModel.promptInstructions.add(resource); + widget.attachmentModel.addPromptFiles([resource]); widget.focusInput(); return; } @@ -130,7 +131,7 @@ class AttachInstructionsAction extends Action2 { const result = await pickers.selectPromptFile({ resource, placeholder, type: PromptsType.instructions }); if (result !== undefined) { - widget.attachmentModel.promptInstructions.add(result.promptFile); + widget.attachmentModel.addPromptFiles([result.promptFile]); widget.focusInput(); } } @@ -224,11 +225,12 @@ export class ChatInstructionsPickerPick implements IChatContextPickerItem { constructor( @IPromptsService private readonly promptsService: IPromptsService, - @ILabelService private readonly labelService: ILabelService + @ILabelService private readonly labelService: ILabelService, + @IConfigurationService private readonly configurationService: IConfigurationService, ) { } isEnabled(widget: IChatWidget): Promise | boolean { - return widget.attachmentModel.promptInstructions.featureEnabled; + return PromptsConfig.enabled(this.configurationService); } asPicker(): { readonly placeholder: string; readonly picks: Promise } { @@ -256,12 +258,7 @@ export class ChatInstructionsPickerPick implements IChatContextPickerItem { result.push({ label: getCleanPromptName(uri), asAttachment: (): IPromptFileVariableEntry => { - return { - kind: 'promptFile', - id: uri.toString(), - value: uri, - name: this.labelService.getUriBasenameLabel(uri), - }; + return toPromptFileVariableEntry(uri, true); } }); } diff --git a/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts b/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts index cd26353e890..7176b07846d 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts @@ -118,15 +118,7 @@ export interface IDiagnosticVariableEntryFilterData { readonly filterRange?: IRange; } -/** - * Chat variable that represents an attached prompt file. - */ -export interface IPromptVariableEntry extends IBaseChatRequestVariableEntry { - readonly kind: 'file'; - readonly value: URI | Location; - readonly isRoot: boolean; - readonly modelDescription: string; -} + export namespace IDiagnosticVariableEntryFilterData { export const icon = Codicon.error; @@ -192,6 +184,9 @@ export interface IElementVariableEntry extends IBaseChatRequestVariableEntry { export interface IPromptFileVariableEntry extends IBaseChatRequestVariableEntry { readonly kind: 'promptFile'; + readonly value: URI; + readonly isRoot: boolean; + readonly modelDescription: string; } export interface ISCMHistoryItemVariableEntry extends IBaseChatRequestVariableEntry { @@ -250,6 +245,10 @@ export function isChatRequestFileEntry(obj: IChatRequestVariableEntry): obj is I return obj.kind === 'file'; } +export function isPromptFileVariableEntry(obj: IChatRequestVariableEntry): obj is IPromptFileVariableEntry { + return obj.kind === 'promptFile'; +} + export function isChatRequestVariableEntry(obj: unknown): obj is IChatRequestVariableEntry { const entry = obj as IChatRequestVariableEntry; return typeof entry === 'object' && @@ -261,3 +260,51 @@ export function isChatRequestVariableEntry(obj: unknown): obj is IChatRequestVar export function isSCMHistoryItemVariableEntry(obj: IChatRequestVariableEntry): obj is ISCMHistoryItemVariableEntry { return obj.kind === 'scmHistoryItem'; } + +/** + * Utility to convert a {@link uri} to a chat variable entry. + * The `id` of the chat variable can be one of the following: + * + * - `vscode.prompt.instructions__`: for all non-root prompt file references + * - `vscode.prompt.instructions.root__`: for *root* prompt file references + * - ``: for the rest of references(the ones that do not point to a prompt file) + * + * @param uri A resource URI that points to a prompt instructions file. + * @param isRoot If the reference is the root reference in the references tree. + * This object most likely was explicitly attached by the user. + */ +export function toPromptFileVariableEntry(uri: URI, isRoot: boolean): IPromptFileVariableEntry { + return { + // `id` for all `prompt files` starts with the well-defined part that the copilot extension(or other chatbot) can rely on + id: `vscode.prompt.instructions${isRoot ? '.root' : ''}}__${uri.toString()}`, + name: `prompt:${basename(uri)}`, + value: uri, + kind: 'promptFile', + modelDescription: 'Prompt instructions file', + isRoot, + }; +} + +export class ChatRequestVariableSet { + private _entries = new Map(); + + public add(...entry: IChatRequestVariableEntry[]): void { + for (const e of entry) { + if (!this._entries.has(e.id)) { + this._entries.set(e.id, e); + } + } + } + + public remove(entry: IChatRequestVariableEntry): void { + this._entries.delete(entry.id); + } + + public has(entry: IChatRequestVariableEntry): boolean { + return this._entries.has(entry.id); + } + + public asArray(): IChatRequestVariableEntry[] { + return Array.from(this._entries.values()); + } +} From d03db82baf5d51c97ba099542bc5d55ae2f21568 Mon Sep 17 00:00:00 2001 From: Justin Chen <54879025+justschen@users.noreply.github.com> Date: Wed, 11 Jun 2025 15:32:37 -0700 Subject: [PATCH 207/236] remove header for non participant messages, better references border (#251242) --- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 6 ++++++ src/vs/workbench/contrib/chat/browser/media/chat.css | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 280a613236c..6ce39786729 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -83,6 +83,8 @@ import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; const $ = dom.$; +const COPILOT_USERNAME = 'GitHub Copilot'; + interface IChatListItemTemplate { currentElement?: ChatTreeItem; /** @@ -439,6 +441,10 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer Date: Wed, 11 Jun 2025 17:42:51 -0700 Subject: [PATCH 208/236] Misc MCP Auth fixes (#251246) 1. only do device code flow if the server supports it 2. fix route in loopback server where error cases were going to `/` which was a typo 3. fix port listening in loopback when default port is taken 4. some servers require registration to have scopes, so passed that through 5. some types clean up --- src/vs/base/common/oauth.ts | 66 +++++++++++++++---- src/vs/base/test/common/oauth.test.ts | 25 ++++--- .../api/common/extHostAuthentication.ts | 2 +- .../api/node/extHostAuthentication.ts | 31 +++++---- 4 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/vs/base/common/oauth.ts b/src/vs/base/common/oauth.ts index a32f3409884..005f5ad1fbc 100644 --- a/src/vs/base/common/oauth.ts +++ b/src/vs/base/common/oauth.ts @@ -8,9 +8,44 @@ import { decodeBase64 } from './buffer.js'; const WELL_KNOWN_ROUTE = '/.well-known'; export const AUTH_PROTECTED_RESOURCE_METADATA_DISCOVERY_PATH = `${WELL_KNOWN_ROUTE}/oauth-protected-resource`; export const AUTH_SERVER_METADATA_DISCOVERY_PATH = `${WELL_KNOWN_ROUTE}/oauth-authorization-server`; +export const AUTH_SCOPE_SEPARATOR = ' '; //#region types +/** + * Base OAuth 2.0 error codes as specified in RFC 6749. + */ +export const enum AuthorizationErrorType { + InvalidRequest = 'invalid_request', + InvalidClient = 'invalid_client', + InvalidGrant = 'invalid_grant', + UnauthorizedClient = 'unauthorized_client', + UnsupportedGrantType = 'unsupported_grant_type', + InvalidScope = 'invalid_scope' +} + +/** + * Device authorization grant specific error codes as specified in RFC 8628 section 3.5. + */ +export const enum AuthorizationDeviceCodeErrorType { + /** + * The authorization request is still pending as the end user hasn't completed the user interaction steps. + */ + AuthorizationPending = 'authorization_pending', + /** + * A variant of "authorization_pending", polling should continue but interval must be increased by 5 seconds. + */ + SlowDown = 'slow_down', + /** + * The authorization request was denied. + */ + AccessDenied = 'access_denied', + /** + * The "device_code" has expired and the device authorization session has concluded. + */ + ExpiredToken = 'expired_token' +} + /** * Metadata about a protected resource. */ @@ -395,18 +430,11 @@ export interface IAuthorizationDeviceResponse { * Error response from the token endpoint when using device authorization grant. * As defined in RFC 8628 section 3.5. */ -export interface IAuthorizationDeviceTokenErrorResponse { +export interface IAuthorizationErrorResponse { /** * REQUIRED. Error code as specified in OAuth 2.0 or in RFC 8628 section 3.5. - * Standard OAuth 2.0 error codes plus: - * - "authorization_pending": The authorization request is still pending as the end user hasn't completed the user interaction steps - * - "slow_down": A variant of "authorization_pending", polling should continue but interval must be increased by 5 seconds - * - "access_denied": The authorization request was denied - * - "expired_token": The "device_code" has expired and the device authorization session has concluded */ - error: 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'unauthorized_client' | - 'unsupported_grant_type' | 'invalid_scope' | 'authorization_pending' | - 'slow_down' | 'access_denied' | 'expired_token' | string; + error: AuthorizationErrorType | string; /** * OPTIONAL. Human-readable description of the error. @@ -419,6 +447,17 @@ export interface IAuthorizationDeviceTokenErrorResponse { error_uri?: string; } +/** + * Error response from the token endpoint when using device authorization grant. + * As defined in RFC 8628 section 3.5. + */ +export interface IAuthorizationDeviceTokenErrorResponse extends IAuthorizationErrorResponse { + /** + * REQUIRED. Error code as specified in OAuth 2.0 or in RFC 8628 section 3.5. + */ + error: AuthorizationErrorType | AuthorizationDeviceCodeErrorType | string; +} + export interface IAuthorizationJWTClaims { /** * REQUIRED. JWT ID. Unique identifier for the token. @@ -606,12 +645,12 @@ export function isAuthorizationDeviceResponse(obj: unknown): obj is IAuthorizati return response.device_code !== undefined && response.user_code !== undefined && response.verification_uri !== undefined && response.expires_in !== undefined; } -export function isAuthorizationDeviceTokenErrorResponse(obj: unknown): obj is IAuthorizationDeviceTokenErrorResponse { +export function isAuthorizationErrorResponse(obj: unknown): obj is IAuthorizationErrorResponse { if (typeof obj !== 'object' || obj === null) { return false; } - const response = obj as IAuthorizationDeviceTokenErrorResponse; - return response.error !== undefined && response.error_description !== undefined; + const response = obj as IAuthorizationErrorResponse; + return response.error !== undefined; } //#endregion @@ -646,7 +685,7 @@ export function getMetadataWithDefaultValues(metadata: IAuthorizationServerMetad * the spec and require an exact match. */ export const DEFAULT_AUTH_FLOW_PORT = 33418; -export async function fetchDynamicRegistration(registrationEndpoint: string, clientName: string): Promise { +export async function fetchDynamicRegistration(registrationEndpoint: string, clientName: string, scopes?: string[]): Promise { const response = await fetch(registrationEndpoint, { method: 'POST', headers: { @@ -669,6 +708,7 @@ export async function fetchDynamicRegistration(registrationEndpoint: string, cli `http://localhost:${DEFAULT_AUTH_FLOW_PORT}/`, `http://127.0.0.1:${DEFAULT_AUTH_FLOW_PORT}/` ], + scope: scopes?.join(AUTH_SCOPE_SEPARATOR), token_endpoint_auth_method: 'none' }) }); diff --git a/src/vs/base/test/common/oauth.test.ts b/src/vs/base/test/common/oauth.test.ts index 2dbeda2f1fe..0ef67b6dfe4 100644 --- a/src/vs/base/test/common/oauth.test.ts +++ b/src/vs/base/test/common/oauth.test.ts @@ -11,7 +11,7 @@ import { getMetadataWithDefaultValues, isAuthorizationAuthorizeResponse, isAuthorizationDeviceResponse, - isAuthorizationDeviceTokenErrorResponse, + isAuthorizationErrorResponse, isAuthorizationDynamicClientRegistrationResponse, isAuthorizationProtectedResourceMetadata, isAuthorizationServerMetadata, @@ -138,43 +138,42 @@ suite('OAuth', () => { assert.strictEqual(isAuthorizationDeviceResponse('not an object'), false); }); - test('isAuthorizationDeviceTokenErrorResponse should correctly identify device token error response', () => { + test('isAuthorizationErrorResponse should correctly identify error response', () => { // Valid error response - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({ + assert.strictEqual(isAuthorizationErrorResponse({ error: 'authorization_pending', error_description: 'The authorization request is still pending' }), true); // Valid error response with different error codes - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({ + assert.strictEqual(isAuthorizationErrorResponse({ error: 'slow_down', error_description: 'Polling too fast' }), true); - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({ + assert.strictEqual(isAuthorizationErrorResponse({ error: 'access_denied', error_description: 'The user denied the request' }), true); - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({ + assert.strictEqual(isAuthorizationErrorResponse({ error: 'expired_token', error_description: 'The device code has expired' }), true); // Valid response with optional error_uri - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({ + assert.strictEqual(isAuthorizationErrorResponse({ error: 'invalid_request', error_description: 'The request is missing a required parameter', error_uri: 'https://example.com/error' }), true); // Invalid cases - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse(null), false); - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse(undefined), false); - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({}), false); - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({ error: 'missing-description' }), false); - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse({ error_description: 'missing-error' }), false); - assert.strictEqual(isAuthorizationDeviceTokenErrorResponse('not an object'), false); + assert.strictEqual(isAuthorizationErrorResponse(null), false); + assert.strictEqual(isAuthorizationErrorResponse(undefined), false); + assert.strictEqual(isAuthorizationErrorResponse({}), false); + assert.strictEqual(isAuthorizationErrorResponse({ error_description: 'missing-error' }), false); + assert.strictEqual(isAuthorizationErrorResponse('not an object'), false); }); }); diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index 5008199eb58..66e7789e775 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -186,7 +186,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { throw new Error('Server does not support dynamic registration'); } try { - const registration = await fetchDynamicRegistration(serverMetadata.registration_endpoint, this._initData.environment.appName); + const registration = await fetchDynamicRegistration(serverMetadata.registration_endpoint, this._initData.environment.appName, resourceMetadata?.scopes_supported); clientId = registration.client_id; } catch (err) { throw new Error(`Dynamic registration failed: ${err.message}`); diff --git a/src/vs/workbench/api/node/extHostAuthentication.ts b/src/vs/workbench/api/node/extHostAuthentication.ts index 465e757d610..995e04e316e 100644 --- a/src/vs/workbench/api/node/extHostAuthentication.ts +++ b/src/vs/workbench/api/node/extHostAuthentication.ts @@ -73,7 +73,7 @@ class LoopbackAuthServer implements ILoopbackServer { const state = reqUrl.searchParams.get('state') ?? undefined; const error = reqUrl.searchParams.get('error') ?? undefined; if (error) { - res.writeHead(302, { location: `/?error=${reqUrl.searchParams.get('error_description')}` }); + res.writeHead(302, { location: `/done?error=${reqUrl.searchParams.get('error_description') || error}` }); res.end(); deferredPromise.error(new Error(error)); break; @@ -84,19 +84,19 @@ class LoopbackAuthServer implements ILoopbackServer { break; } if (this.state !== state) { - res.writeHead(302, { location: `/?error=${encodeURIComponent('State does not match.')}` }); + res.writeHead(302, { location: `/done?error=${encodeURIComponent('State does not match.')}` }); res.end(); deferredPromise.error(new Error('State does not match.')); break; } deferredPromise.complete({ code, state }); - res.writeHead(302, { location: '/success' }); + res.writeHead(302, { location: '/done' }); res.end(); break; } // Serve the static files - case '/success': - this._sendSuccessPage(res); + case '/done': + this._sendPage(res); break; default: res.writeHead(404); @@ -114,7 +114,7 @@ class LoopbackAuthServer implements ILoopbackServer { return `http://127.0.0.1:${this._port}/`; } - private _sendSuccessPage(res: http.ServerResponse): void { + private _sendPage(res: http.ServerResponse): void { const html = getHtml(this._appUri); res.writeHead(200, { 'Content-Type': 'text/html', @@ -147,11 +147,8 @@ class LoopbackAuthServer implements ILoopbackServer { this._server.on('error', err => { if ('code' in err && err.code === 'EADDRINUSE') { this._logger.error('Address in use, retrying with a different port...'); - setTimeout(() => { - this._server.close(); - // Best effort to use a specific port, but fallback to a random one if it is in use - this._server.listen(0, '127.0.0.1'); - }, 1000); + // Best effort to use a specific port, but fallback to a random one if it is in use + this._server.listen(0, '127.0.0.1'); return; } clearTimeout(portTimeout); @@ -232,11 +229,13 @@ export class NodeDynamicAuthProvider extends DynamicAuthProvider { }); } - // Add device code flow support (works in all environments) - this._createFlows.push({ - label: nls.localize('device code', "Device Code"), - handler: (scopes, progress, token) => this._createWithDeviceCode(scopes, progress, token) - }); + // Add device code flow to the end since it's not as streamlined + if (serverMetadata.device_authorization_endpoint) { + this._createFlows.push({ + label: nls.localize('device code', "Device Code"), + handler: (scopes, progress, token) => this._createWithDeviceCode(scopes, progress, token) + }); + } } private async _createWithLoopbackServer(scopes: string[], progress: vscode.Progress, token: vscode.CancellationToken): Promise { From 48e4737a8856d8da28f159f74cf7568848fd571d Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt <2644648+TylerLeonhardt@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:30:29 -0700 Subject: [PATCH 209/236] Improve async nature of register/unregister auth providers (#251244) * Improve async nature of register/unregister auth providers I noticed a race-condition or 2 with registering & unregistering auth providers. This change makes sure order is maintained dispite the async nature. * real passing tests * Try tracking disposable state --- .../test/common/testSecretStorageService.ts | 5 + .../api/browser/mainThreadAuthentication.ts | 15 +- .../api/common/extHostAuthentication.ts | 140 ++++---- .../api/node/extHostAuthentication.ts | 5 +- .../extHostAuthentication.integrationTest.ts | 304 +++++++++++++++--- ...ainThreadAuthentication.integrationTest.ts | 151 +++++++++ .../api/test/common/testRPCProtocol.ts | 4 +- .../browser/authenticationService.ts | 67 ++-- 8 files changed, 544 insertions(+), 147 deletions(-) create mode 100644 src/vs/workbench/api/test/browser/mainThreadAuthentication.integrationTest.ts diff --git a/src/vs/platform/secrets/test/common/testSecretStorageService.ts b/src/vs/platform/secrets/test/common/testSecretStorageService.ts index ec7482e72bb..fa3d5483507 100644 --- a/src/vs/platform/secrets/test/common/testSecretStorageService.ts +++ b/src/vs/platform/secrets/test/common/testSecretStorageService.ts @@ -33,4 +33,9 @@ export class TestSecretStorageService implements ISecretStorageService { clear(): void { this._storage.clear(); } + + dispose(): void { + this._onDidChangeSecretEmitter.dispose(); + this._storage.clear(); + } } diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index d8e6acdcbc7..7b31bb4a789 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -80,6 +80,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu private readonly _registrations = this._register(new DisposableMap()); private _sentProviderUsageEvents = new Set(); + private _suppressUnregisterEvent = false; constructor( extHostContext: IExtHostContext, @@ -101,7 +102,11 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostAuthentication); this._register(this.authenticationService.onDidChangeSessions(e => this._proxy.$onDidChangeAuthenticationSessions(e.providerId, e.label))); - this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(e => this._proxy.$onDidUnregisterAuthenticationProvider(e.id))); + this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(e => { + if (!this._suppressUnregisterEvent) { + this._proxy.$onDidUnregisterAuthenticationProvider(e.id); + } + })); this._register(this.authenticationExtensionsService.onDidChangeAccountPreference(e => { const providerInfo = this.authenticationService.getProvider(e.providerId); this._proxy.$onDidChangeAuthenticationSessions(providerInfo.id, providerInfo.label, e.extensionIds); @@ -153,7 +158,13 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu async $unregisterAuthenticationProvider(id: string): Promise { this._registrations.deleteAndDispose(id); - this.authenticationService.unregisterAuthenticationProvider(id); + // The ext host side already unregisters the provider, so we can suppress the event here. + this._suppressUnregisterEvent = true; + try { + this.authenticationService.unregisterAuthenticationProvider(id); + } finally { + this._suppressUnregisterEvent = false; + } } async $ensureProvider(id: string): Promise { diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index 66e7789e775..00dc61b1b72 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -16,7 +16,7 @@ import { URI, UriComponents } from '../../../base/common/uri.js'; import { fetchDynamicRegistration, getClaimsFromJWT, IAuthorizationJWTClaims, IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata, IAuthorizationTokenResponse, isAuthorizationTokenResponse } from '../../../base/common/oauth.js'; import { IExtHostWindow } from './extHostWindow.js'; import { IExtHostInitDataService } from './extHostInitDataService.js'; -import { ILogger, ILoggerService } from '../../../platform/log/common/log.js'; +import { ILogger, ILoggerService, ILogService } from '../../../platform/log/common/log.js'; import { autorun, derivedOpts, IObservable, ISettableObservable, observableValue } from '../../../base/common/observable.js'; import { stringHash } from '../../../base/common/hash.js'; import { DisposableStore, IDisposable } from '../../../base/common/lifecycle.js'; @@ -26,7 +26,7 @@ import { equals as arraysEqual } from '../../../base/common/arrays.js'; import { IExtHostProgress } from './extHostProgress.js'; import { IProgressStep } from '../../../platform/progress/common/progress.js'; import { CancellationError, isCancellationError } from '../../../base/common/errors.js'; -import { raceCancellationError } from '../../../base/common/async.js'; +import { raceCancellationError, SequencerByKey } from '../../../base/common/async.js'; export interface IExtHostAuthentication extends ExtHostAuthentication { } export const IExtHostAuthentication = createDecorator('IExtHostAuthentication'); @@ -46,6 +46,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { private _proxy: MainThreadAuthenticationShape; private _authenticationProviders: Map = new Map(); + private _providerOperations = new SequencerByKey(); private _onDidChangeSessions = new Emitter(); private _getSessionTaskSingler = new TaskSingler(); @@ -58,7 +59,8 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { @IExtHostWindow private readonly _extHostWindow: IExtHostWindow, @IExtHostUrlsService private readonly _extHostUrls: IExtHostUrlsService, @IExtHostProgress private readonly _extHostProgress: IExtHostProgress, - @ILoggerService private readonly _extHostLoggerService: ILoggerService + @ILoggerService private readonly _extHostLoggerService: ILoggerService, + @ILogService private readonly _logService: ILogService, ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadAuthentication); } @@ -98,58 +100,67 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { return await this._proxy.$getAccounts(providerId); } - async removeSession(providerId: string, sessionId: string): Promise { - const providerData = this._authenticationProviders.get(providerId); - if (!providerData) { - return this._proxy.$removeSession(providerId, sessionId); - } - - return providerData.provider.removeSession(sessionId); - } - registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable { - if (this._authenticationProviders.get(id)) { - throw new Error(`An authentication provider with id '${id}' is already registered.`); - } - - this._authenticationProviders.set(id, { label, provider, options: options ?? { supportsMultipleAccounts: false } }); - const listener = provider.onDidChangeSessions(e => this._proxy.$sendDidChangeSessions(id, e)); - this._proxy.$registerAuthenticationProvider(id, label, options?.supportsMultipleAccounts ?? false, options?.supportedAuthorizationServers); + // register + void this._providerOperations.queue(id, async () => { + // This use to be synchronous, but that wasn't an accurate representation because the main thread + // may have unregistered the provider in the meantime. I don't see how this could really be done + // synchronously, so we just say first one wins. + if (this._authenticationProviders.get(id)) { + this._logService.error(`An authentication provider with id '${id}' is already registered. The existing provider will not be replaced.`); + return; + } + const listener = provider.onDidChangeSessions(e => this._proxy.$sendDidChangeSessions(id, e)); + this._authenticationProviders.set(id, { label, provider, disposable: listener, options: options ?? { supportsMultipleAccounts: false } }); + await this._proxy.$registerAuthenticationProvider(id, label, options?.supportsMultipleAccounts ?? false, options?.supportedAuthorizationServers); + }); + // unregister return new Disposable(() => { - listener.dispose(); - this._authenticationProviders.delete(id); - this._proxy.$unregisterAuthenticationProvider(id); + void this._providerOperations.queue(id, async () => { + const providerData = this._authenticationProviders.get(id); + if (providerData) { + providerData.disposable?.dispose(); + this._authenticationProviders.delete(id); + await this._proxy.$unregisterAuthenticationProvider(id); + } + }); }); } - async $createSession(providerId: string, scopes: string[], options: vscode.AuthenticationProviderSessionOptions): Promise { - const providerData = this._authenticationProviders.get(providerId); - if (providerData) { - options.authorizationServer = URI.revive(options.authorizationServer); - return await providerData.provider.createSession(scopes, options); - } + $createSession(providerId: string, scopes: string[], options: vscode.AuthenticationProviderSessionOptions): Promise { + return this._providerOperations.queue(providerId, async () => { + const providerData = this._authenticationProviders.get(providerId); + if (providerData) { + options.authorizationServer = URI.revive(options.authorizationServer); + return await providerData.provider.createSession(scopes, options); + } - throw new Error(`Unable to find authentication provider with handle: ${providerId}`); + throw new Error(`Unable to find authentication provider with handle: ${providerId}`); + }); } - async $removeSession(providerId: string, sessionId: string): Promise { - const providerData = this._authenticationProviders.get(providerId); - if (providerData) { - return await providerData.provider.removeSession(sessionId); - } + $removeSession(providerId: string, sessionId: string): Promise { + return this._providerOperations.queue(providerId, async () => { + const providerData = this._authenticationProviders.get(providerId); + if (providerData) { + return await providerData.provider.removeSession(sessionId); + } - throw new Error(`Unable to find authentication provider with handle: ${providerId}`); + throw new Error(`Unable to find authentication provider with handle: ${providerId}`); + }); } - async $getSessions(providerId: string, scopes: ReadonlyArray | undefined, options: vscode.AuthenticationProviderSessionOptions): Promise> { - const providerData = this._authenticationProviders.get(providerId); - if (providerData) { - options.authorizationServer = URI.revive(options.authorizationServer); - return await providerData.provider.getSessions(scopes, options); - } + $getSessions(providerId: string, scopes: ReadonlyArray | undefined, options: vscode.AuthenticationProviderSessionOptions): Promise> { + return this._providerOperations.queue(providerId, async () => { + const providerData = this._authenticationProviders.get(providerId); + if (providerData) { + options.authorizationServer = URI.revive(options.authorizationServer); + return await providerData.provider.getSessions(scopes, options); + } - throw new Error(`Unable to find authentication provider with handle: ${providerId}`); + throw new Error(`Unable to find authentication provider with handle: ${providerId}`); + }); } $onDidChangeAuthenticationSessions(id: string, label: string, extensionIdFilter?: string[]) { @@ -160,18 +171,14 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { return Promise.resolve(); } - // Today, this only handles unregistering extensions that have disposables... - // so basiscally just the dynmaic ones. This was done to fix a bug where - // there was a racecondition between this event and re-registering a provider - // with the same id. (https://github.com/microsoft/vscode-copilot/issues/18045) - // This works for now, but should be cleaned up so theres one flow for register/unregister $onDidUnregisterAuthenticationProvider(id: string): Promise { - const providerData = this._authenticationProviders.get(id); - if (providerData?.disposable) { - providerData.disposable.dispose(); - this._authenticationProviders.delete(id); - } - return Promise.resolve(); + return this._providerOperations.queue(id, async () => { + const providerData = this._authenticationProviders.get(id); + if (providerData) { + providerData.disposable?.dispose(); + this._authenticationProviders.delete(id); + } + }); } async $registerDynamicAuthProvider( @@ -206,17 +213,22 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { this._onDidDynamicAuthProviderTokensChange, initialTokens || [] ); - const disposable = provider.onDidChangeSessions(e => this._proxy.$sendDidChangeSessions(provider.id, e)); - this._authenticationProviders.set( - provider.id, - { - label: provider.label, - provider, - disposable: Disposable.from(provider, disposable), - options: { supportsMultipleAccounts: false } - } - ); - await this._proxy.$registerDynamicAuthenticationProvider(provider.id, provider.label, provider.authorizationServer, provider.clientId); + + // Use the sequencer to ensure dynamic provider registration is serialized + await this._providerOperations.queue(provider.id, async () => { + const disposable = provider.onDidChangeSessions(e => this._proxy.$sendDidChangeSessions(provider.id, e)); + this._authenticationProviders.set( + provider.id, + { + label: provider.label, + provider, + disposable: Disposable.from(provider, disposable), + options: { supportsMultipleAccounts: false } + } + ); + await this._proxy.$registerDynamicAuthenticationProvider(provider.id, provider.label, provider.authorizationServer, provider.clientId); + }); + return provider.id; } diff --git a/src/vs/workbench/api/node/extHostAuthentication.ts b/src/vs/workbench/api/node/extHostAuthentication.ts index 995e04e316e..c71a8b4736b 100644 --- a/src/vs/workbench/api/node/extHostAuthentication.ts +++ b/src/vs/workbench/api/node/extHostAuthentication.ts @@ -13,7 +13,7 @@ import { IExtHostRpcService } from '../common/extHostRpcService.js'; import { IExtHostInitDataService } from '../common/extHostInitDataService.js'; import { IExtHostWindow } from '../common/extHostWindow.js'; import { IExtHostUrlsService } from '../common/extHostUrls.js'; -import { ILogger, ILoggerService } from '../../../platform/log/common/log.js'; +import { ILogger, ILoggerService, ILogService } from '../../../platform/log/common/log.js'; import { MainThreadAuthenticationShape } from '../common/extHost.protocol.js'; import { IAuthorizationServerMetadata, IAuthorizationProtectedResourceMetadata, IAuthorizationTokenResponse, DEFAULT_AUTH_FLOW_PORT, IAuthorizationDeviceResponse, isAuthorizationDeviceResponse, isAuthorizationTokenResponse, IAuthorizationDeviceTokenErrorResponse } from '../../../base/common/oauth.js'; import { Emitter } from '../../../base/common/event.js'; @@ -476,8 +476,9 @@ export class NodeExtHostAuthentication extends ExtHostAuthentication implements extHostUrls: IExtHostUrlsService, extHostProgress: IExtHostProgress, extHostLoggerService: ILoggerService, + extHostLogService: ILogService ) { - super(extHostRpc, initData, extHostWindow, extHostUrls, extHostProgress, extHostLoggerService); + super(extHostRpc, initData, extHostWindow, extHostUrls, extHostProgress, extHostLoggerService, extHostLogService); } } diff --git a/src/vs/workbench/api/test/browser/extHostAuthentication.integrationTest.ts b/src/vs/workbench/api/test/browser/extHostAuthentication.integrationTest.ts index 21668a51aa0..004ba6dbe2e 100644 --- a/src/vs/workbench/api/test/browser/extHostAuthentication.integrationTest.ts +++ b/src/vs/workbench/api/test/browser/extHostAuthentication.integrationTest.ts @@ -4,13 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { DisposableStore } from '../../../../base/common/lifecycle.js'; import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { TestDialogService } from '../../../../platform/dialogs/test/common/testDialogService.js'; import { TestInstantiationService } from '../../../../platform/instantiation/test/common/instantiationServiceMock.js'; import { INotificationService } from '../../../../platform/notification/common/notification.js'; import { TestNotificationService } from '../../../../platform/notification/test/common/testNotificationService.js'; -import { IQuickInputHideEvent, IQuickInputService, IQuickPickDidAcceptEvent } from '../../../../platform/quickinput/common/quickInput.js'; +import { IQuickInputHideEvent, IQuickInputService, IQuickPickDidAcceptEvent, IQuickPickItem, QuickInputHideReason } from '../../../../platform/quickinput/common/quickInput.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { NullTelemetryService } from '../../../../platform/telemetry/common/telemetryUtils.js'; @@ -44,27 +43,31 @@ import { TestSecretStorageService } from '../../../../platform/secrets/test/comm import { IDynamicAuthenticationProviderStorageService } from '../../../services/authentication/common/dynamicAuthenticationProviderStorage.js'; import { DynamicAuthenticationProviderStorageService } from '../../../services/authentication/browser/dynamicAuthenticationProviderStorageService.js'; import { ExtHostProgress } from '../../common/extHostProgress.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; +import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js'; +import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js'; class AuthQuickPick { - private listener: ((e: IQuickPickDidAcceptEvent) => any) | undefined; + private accept: ((e: IQuickPickDidAcceptEvent) => any) | undefined; + private hide: ((e: IQuickInputHideEvent) => any) | undefined; public items = []; - public get selectedItems(): string[] { + public get selectedItems(): IQuickPickItem[] { return this.items; } onDidAccept(listener: (e: IQuickPickDidAcceptEvent) => any) { - this.listener = listener; + this.accept = listener; } onDidHide(listener: (e: IQuickInputHideEvent) => any) { - + this.hide = listener; } + dispose() { } show() { - this.listener!({ - inBackground: false - }); + this.accept?.({ inBackground: false }); + this.hide?.({ reason: QuickInputHideReason.Other }); } } class AuthTestQuickInputService extends TestQuickInputService { @@ -111,39 +114,43 @@ class TestAuthProvider implements AuthenticationProvider { } suite('ExtHostAuthentication', () => { - let disposables: DisposableStore; + const disposables = ensureNoDisposablesAreLeakedInTestSuite(); let extHostAuthentication: ExtHostAuthentication; - let instantiationService: TestInstantiationService; + let mainInstantiationService: TestInstantiationService; - suiteSetup(async () => { - instantiationService = new TestInstantiationService(); - instantiationService.stub(ILogService, new NullLogService()); - instantiationService.stub(IDialogService, new TestDialogService({ confirmed: true })); - instantiationService.stub(IStorageService, new TestStorageService()); - instantiationService.stub(ISecretStorageService, new TestSecretStorageService()); - instantiationService.stub(IDynamicAuthenticationProviderStorageService, instantiationService.createInstance(DynamicAuthenticationProviderStorageService)); - instantiationService.stub(IQuickInputService, new AuthTestQuickInputService()); - instantiationService.stub(IExtensionService, new TestExtensionService()); + setup(async () => { + // services + const services = new ServiceCollection(); + services.set(ILogService, new SyncDescriptor(NullLogService)); + services.set(IDialogService, new SyncDescriptor(TestDialogService, [{ confirmed: true }])); + services.set(IStorageService, new SyncDescriptor(TestStorageService)); + services.set(ISecretStorageService, new SyncDescriptor(TestSecretStorageService)); + services.set(IDynamicAuthenticationProviderStorageService, new SyncDescriptor(DynamicAuthenticationProviderStorageService)); + services.set(IQuickInputService, new SyncDescriptor(AuthTestQuickInputService)); + services.set(IExtensionService, new SyncDescriptor(TestExtensionService)); + services.set(IActivityService, new SyncDescriptor(TestActivityService)); + services.set(IRemoteAgentService, new SyncDescriptor(TestRemoteAgentService)); + services.set(INotificationService, new SyncDescriptor(TestNotificationService)); + services.set(IHostService, new SyncDescriptor(TestHostService)); + services.set(IUserActivityService, new SyncDescriptor(UserActivityService)); + services.set(IAuthenticationAccessService, new SyncDescriptor(AuthenticationAccessService)); + services.set(IAuthenticationService, new SyncDescriptor(AuthenticationService)); + services.set(IAuthenticationUsageService, new SyncDescriptor(AuthenticationUsageService)); + services.set(IAuthenticationExtensionsService, new SyncDescriptor(AuthenticationExtensionsService)); + mainInstantiationService = disposables.add(new TestInstantiationService(services, undefined, undefined, true)); - instantiationService.stub(IActivityService, new TestActivityService()); - instantiationService.stub(IRemoteAgentService, new TestRemoteAgentService()); - instantiationService.stub(INotificationService, new TestNotificationService()); - instantiationService.stub(IHostService, new TestHostService()); + // stubs // eslint-disable-next-line local/code-no-dangerous-type-assertions - instantiationService.stub(IOpenerService, {} as Partial); - instantiationService.stub(IUserActivityService, new UserActivityService(instantiationService)); - instantiationService.stub(ITelemetryService, NullTelemetryService); - instantiationService.stub(IBrowserWorkbenchEnvironmentService, TestEnvironmentService); - instantiationService.stub(IProductService, TestProductService); - instantiationService.stub(IAuthenticationAccessService, instantiationService.createInstance(AuthenticationAccessService)); - instantiationService.stub(IAuthenticationService, instantiationService.createInstance(AuthenticationService)); - instantiationService.stub(IAuthenticationUsageService, instantiationService.createInstance(AuthenticationUsageService)); - const rpcProtocol = new TestRPCProtocol(); + mainInstantiationService.stub(IOpenerService, {} as Partial); + mainInstantiationService.stub(ITelemetryService, NullTelemetryService); + mainInstantiationService.stub(IBrowserWorkbenchEnvironmentService, TestEnvironmentService); + mainInstantiationService.stub(IProductService, TestProductService); - instantiationService.stub(IAuthenticationExtensionsService, instantiationService.createInstance(AuthenticationExtensionsService)); - rpcProtocol.set(MainContext.MainThreadAuthentication, instantiationService.createInstance(MainThreadAuthentication, rpcProtocol)); - rpcProtocol.set(MainContext.MainThreadWindow, instantiationService.createInstance(MainThreadWindow, rpcProtocol)); + const rpcProtocol = disposables.add(new TestRPCProtocol()); + + rpcProtocol.set(MainContext.MainThreadAuthentication, disposables.add(mainInstantiationService.createInstance(MainThreadAuthentication, rpcProtocol))); + rpcProtocol.set(MainContext.MainThreadWindow, disposables.add(mainInstantiationService.createInstance(MainThreadWindow, rpcProtocol))); const initData: IExtHostInitDataService = { environment: { appUriScheme: 'test', @@ -161,13 +168,10 @@ suite('ExtHostAuthentication', () => { new ExtHostWindow(initData, rpcProtocol), new ExtHostUrls(rpcProtocol), new ExtHostProgress(rpcProtocol), - new TestLoggerService(), + disposables.add(new TestLoggerService()), + new NullLogService() ); rpcProtocol.set(ExtHostContext.ExtHostAuthentication, extHostAuthentication); - }); - - setup(async () => { - disposables = new DisposableStore(); disposables.add(extHostAuthentication.registerAuthenticationProvider('test', 'test provider', new TestAuthProvider('test'))); disposables.add(extHostAuthentication.registerAuthenticationProvider( 'test-multiple', @@ -176,14 +180,6 @@ suite('ExtHostAuthentication', () => { { supportsMultipleAccounts: true })); }); - suiteTeardown(() => { - instantiationService.dispose(); - }); - - teardown(() => { - disposables.dispose(); - }); - test('createIfNone - true', async () => { const scopes = ['foo']; const session = await extHostAuthentication.getSession( @@ -553,5 +549,215 @@ suite('ExtHostAuthentication', () => { }); + //#endregion + + //#region Race Condition and Sequencing Tests + + test('concurrent operations on same provider are serialized', async () => { + const provider = new TestAuthProvider('concurrent-test'); + const operationOrder: string[] = []; + + // Mock the provider methods to track operation order + const originalCreateSession = provider.createSession.bind(provider); + const originalGetSessions = provider.getSessions.bind(provider); + + provider.createSession = async (scopes) => { + operationOrder.push(`create-start-${scopes[0]}`); + await new Promise(resolve => setTimeout(resolve, 20)); // Simulate async work + const result = await originalCreateSession(scopes); + operationOrder.push(`create-end-${scopes[0]}`); + return result; + }; + + provider.getSessions = async (scopes) => { + const scopeKey = scopes ? scopes[0] : 'all'; + operationOrder.push(`get-start-${scopeKey}`); + await new Promise(resolve => setTimeout(resolve, 10)); // Simulate async work + const result = await originalGetSessions(scopes); + operationOrder.push(`get-end-${scopeKey}`); + return result; + }; + + const disposable = extHostAuthentication.registerAuthenticationProvider('concurrent-test', 'Concurrent Test', provider); + disposables.add(disposable); + + // Start multiple operations simultaneously on the same provider + const promises = [ + extHostAuthentication.getSession(extensionDescription, 'concurrent-test', ['scope1'], { createIfNone: true }), + extHostAuthentication.getSession(extensionDescription, 'concurrent-test', ['scope2'], { createIfNone: true }), + extHostAuthentication.getSession(extensionDescription, 'concurrent-test', ['scope1'], {}) // This should get the existing session + ]; + + await Promise.all(promises); + + // Verify that operations were serialized - no overlapping operations + // Build a map of operation starts to their corresponding ends + const operationPairs: Array<{ start: number; end: number; operation: string }> = []; + + for (let i = 0; i < operationOrder.length; i++) { + const current = operationOrder[i]; + if (current.includes('-start-')) { + const scope = current.split('-start-')[1]; + const operationType = current.split('-start-')[0]; + const endOperation = `${operationType}-end-${scope}`; + const endIndex = operationOrder.indexOf(endOperation, i + 1); + + if (endIndex !== -1) { + operationPairs.push({ + start: i, + end: endIndex, + operation: `${operationType}-${scope}` + }); + } + } + } + + // Verify no operations overlap (serialization) + for (let i = 0; i < operationPairs.length; i++) { + for (let j = i + 1; j < operationPairs.length; j++) { + const op1 = operationPairs[i]; + const op2 = operationPairs[j]; + + // Operations should not overlap - one should completely finish before the other starts + const op1EndsBeforeOp2Starts = op1.end < op2.start; + const op2EndsBeforeOp1Starts = op2.end < op1.start; + + assert.ok(op1EndsBeforeOp2Starts || op2EndsBeforeOp1Starts, + `Operations ${op1.operation} and ${op2.operation} should not overlap. ` + + `Op1: ${op1.start}-${op1.end}, Op2: ${op2.start}-${op2.end}. ` + + `Order: [${operationOrder.join(', ')}]`); + } + } + + // Verify we have the expected operations + assert.ok(operationOrder.includes('create-start-scope1'), 'Should have created session for scope1'); + assert.ok(operationOrder.includes('create-end-scope1'), 'Should have completed creating session for scope1'); + assert.ok(operationOrder.includes('create-start-scope2'), 'Should have created session for scope2'); + assert.ok(operationOrder.includes('create-end-scope2'), 'Should have completed creating session for scope2'); + + // The third call should use getSessions to find the existing scope1 session + assert.ok(operationOrder.includes('get-start-scope1'), 'Should have called getSessions for existing scope1 session'); + assert.ok(operationOrder.includes('get-end-scope1'), 'Should have completed getSessions for existing scope1 session'); + }); + + test('provider registration and immediate disposal race condition', async () => { + const provider = new TestAuthProvider('race-test'); + + // Register and immediately dispose + const disposable = extHostAuthentication.registerAuthenticationProvider('race-test', 'Race Test', provider); + disposable.dispose(); + + // Try to use the provider after disposal - should fail gracefully + try { + await extHostAuthentication.getSession(extensionDescription, 'race-test', ['scope'], { createIfNone: true }); + assert.fail('Should have thrown an error for non-existent provider'); + } catch (error) { + // Expected - provider should be unavailable + assert.ok(error); + } + }); + + test('provider re-registration after proper disposal', async () => { + const provider1 = new TestAuthProvider('reregister-test-1'); + const provider2 = new TestAuthProvider('reregister-test-2'); + + // First registration + const disposable1 = extHostAuthentication.registerAuthenticationProvider('reregister-test', 'Provider 1', provider1); + + // Create a session with first provider + const session1 = await extHostAuthentication.getSession(extensionDescription, 'reregister-test', ['scope'], { createIfNone: true }); + assert.strictEqual(session1?.account.label, 'reregister-test-1'); + + // Dispose first provider + disposable1.dispose(); + + // Re-register with different provider + const disposable2 = extHostAuthentication.registerAuthenticationProvider('reregister-test', 'Provider 2', provider2); + disposables.add(disposable2); + + // Create session with second provider + const session2 = await extHostAuthentication.getSession(extensionDescription, 'reregister-test', ['scope'], { createIfNone: true }); + assert.strictEqual(session2?.account.label, 'reregister-test-2'); + assert.notStrictEqual(session1?.accessToken, session2?.accessToken); + }); + + test('session operations during provider lifecycle changes', async () => { + const provider = new TestAuthProvider('lifecycle-test'); + const disposable = extHostAuthentication.registerAuthenticationProvider('lifecycle-test', 'Lifecycle Test', provider); + + // Start a session creation + const sessionPromise = extHostAuthentication.getSession(extensionDescription, 'lifecycle-test', ['scope'], { createIfNone: true }); + + // Don't dispose immediately - let the session creation start + await new Promise(resolve => setTimeout(resolve, 5)); + + // Dispose the provider while the session creation is likely still in progress + disposable.dispose(); + + // The session creation should complete successfully even if we dispose during the operation + const session = await sessionPromise; + assert.ok(session); + assert.strictEqual(session.account.label, 'lifecycle-test'); + }); + + test('operations on different providers run concurrently', async () => { + const provider1 = new TestAuthProvider('concurrent-1'); + const provider2 = new TestAuthProvider('concurrent-2'); + + let provider1Started = false; + let provider2Started = false; + let provider1Finished = false; + let provider2Finished = false; + let concurrencyVerified = false; + + // Override createSession to track timing + const originalCreate1 = provider1.createSession.bind(provider1); + const originalCreate2 = provider2.createSession.bind(provider2); + + provider1.createSession = async (scopes) => { + provider1Started = true; + await new Promise(resolve => setTimeout(resolve, 20)); + const result = await originalCreate1(scopes); + provider1Finished = true; + return result; + }; + + provider2.createSession = async (scopes) => { + provider2Started = true; + // Provider 2 should start before provider 1 finishes (concurrent execution) + if (provider1Started && !provider1Finished) { + concurrencyVerified = true; + } + await new Promise(resolve => setTimeout(resolve, 10)); + const result = await originalCreate2(scopes); + provider2Finished = true; + return result; + }; + + const disposable1 = extHostAuthentication.registerAuthenticationProvider('concurrent-1', 'Concurrent 1', provider1); + const disposable2 = extHostAuthentication.registerAuthenticationProvider('concurrent-2', 'Concurrent 2', provider2); + disposables.add(disposable1); + disposables.add(disposable2); + + // Start operations on both providers simultaneously + const [session1, session2] = await Promise.all([ + extHostAuthentication.getSession(extensionDescription, 'concurrent-1', ['scope'], { createIfNone: true }), + extHostAuthentication.getSession(extensionDescription, 'concurrent-2', ['scope'], { createIfNone: true }) + ]); + + // Verify both operations completed successfully + assert.ok(session1); + assert.ok(session2); + assert.ok(provider1Started, 'Provider 1 should have started'); + assert.ok(provider2Started, 'Provider 2 should have started'); + assert.ok(provider1Finished, 'Provider 1 should have finished'); + assert.ok(provider2Finished, 'Provider 2 should have finished'); + assert.strictEqual(session1.account.label, 'concurrent-1'); + assert.strictEqual(session2.account.label, 'concurrent-2'); + + // Verify that operations ran concurrently (provider 2 started while provider 1 was still running) + assert.ok(concurrencyVerified, 'Operations should have run concurrently - provider 2 should start while provider 1 is still running'); + }); + //#endregion }); diff --git a/src/vs/workbench/api/test/browser/mainThreadAuthentication.integrationTest.ts b/src/vs/workbench/api/test/browser/mainThreadAuthentication.integrationTest.ts new file mode 100644 index 00000000000..09a9a75c1b8 --- /dev/null +++ b/src/vs/workbench/api/test/browser/mainThreadAuthentication.integrationTest.ts @@ -0,0 +1,151 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; +import { TestDialogService } from '../../../../platform/dialogs/test/common/testDialogService.js'; +import { TestInstantiationService } from '../../../../platform/instantiation/test/common/instantiationServiceMock.js'; +import { INotificationService } from '../../../../platform/notification/common/notification.js'; +import { TestNotificationService } from '../../../../platform/notification/test/common/testNotificationService.js'; +import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.js'; +import { IStorageService } from '../../../../platform/storage/common/storage.js'; +import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; +import { NullTelemetryService } from '../../../../platform/telemetry/common/telemetryUtils.js'; +import { MainThreadAuthentication } from '../../browser/mainThreadAuthentication.js'; +import { ExtHostContext, MainContext } from '../../common/extHost.protocol.js'; +import { IActivityService } from '../../../services/activity/common/activity.js'; +import { AuthenticationService } from '../../../services/authentication/browser/authenticationService.js'; +import { IAuthenticationExtensionsService, IAuthenticationService } from '../../../services/authentication/common/authentication.js'; +import { IExtensionService } from '../../../services/extensions/common/extensions.js'; +import { IRemoteAgentService } from '../../../services/remote/common/remoteAgentService.js'; +import { TestRPCProtocol } from '../common/testRPCProtocol.js'; +import { TestEnvironmentService, TestHostService, TestQuickInputService, TestRemoteAgentService } from '../../../test/browser/workbenchTestServices.js'; +import { TestActivityService, TestExtensionService, TestProductService, TestStorageService } from '../../../test/common/workbenchTestServices.js'; +import { IBrowserWorkbenchEnvironmentService } from '../../../services/environment/browser/environmentService.js'; +import { IProductService } from '../../../../platform/product/common/productService.js'; +import { AuthenticationAccessService, IAuthenticationAccessService } from '../../../services/authentication/browser/authenticationAccessService.js'; +import { AuthenticationUsageService, IAuthenticationUsageService } from '../../../services/authentication/browser/authenticationUsageService.js'; +import { AuthenticationExtensionsService } from '../../../services/authentication/browser/authenticationExtensionsService.js'; +import { ILogService, NullLogService } from '../../../../platform/log/common/log.js'; +import { IHostService } from '../../../services/host/browser/host.js'; +import { IOpenerService } from '../../../../platform/opener/common/opener.js'; +import { IUserActivityService, UserActivityService } from '../../../services/userActivity/common/userActivityService.js'; +import { ISecretStorageService } from '../../../../platform/secrets/common/secrets.js'; +import { TestSecretStorageService } from '../../../../platform/secrets/test/common/testSecretStorageService.js'; +import { IDynamicAuthenticationProviderStorageService } from '../../../services/authentication/common/dynamicAuthenticationProviderStorage.js'; +import { DynamicAuthenticationProviderStorageService } from '../../../services/authentication/browser/dynamicAuthenticationProviderStorageService.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; +import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js'; +import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js'; + +suite('MainThreadAuthentication', () => { + const disposables = ensureNoDisposablesAreLeakedInTestSuite(); + + let mainThreadAuthentication: MainThreadAuthentication; + let instantiationService: TestInstantiationService; + let rpcProtocol: TestRPCProtocol; + + setup(async () => { + // services + const services = new ServiceCollection(); + services.set(ILogService, new SyncDescriptor(NullLogService)); + services.set(IDialogService, new SyncDescriptor(TestDialogService, [{ confirmed: true }])); + services.set(IStorageService, new SyncDescriptor(TestStorageService)); + services.set(ISecretStorageService, new SyncDescriptor(TestSecretStorageService)); + services.set(IDynamicAuthenticationProviderStorageService, new SyncDescriptor(DynamicAuthenticationProviderStorageService)); + services.set(IQuickInputService, new SyncDescriptor(TestQuickInputService)); + services.set(IExtensionService, new SyncDescriptor(TestExtensionService)); + services.set(IActivityService, new SyncDescriptor(TestActivityService)); + services.set(IRemoteAgentService, new SyncDescriptor(TestRemoteAgentService)); + services.set(INotificationService, new SyncDescriptor(TestNotificationService)); + services.set(IHostService, new SyncDescriptor(TestHostService)); + services.set(IUserActivityService, new SyncDescriptor(UserActivityService)); + services.set(IAuthenticationAccessService, new SyncDescriptor(AuthenticationAccessService)); + services.set(IAuthenticationService, new SyncDescriptor(AuthenticationService)); + services.set(IAuthenticationUsageService, new SyncDescriptor(AuthenticationUsageService)); + services.set(IAuthenticationExtensionsService, new SyncDescriptor(AuthenticationExtensionsService)); + instantiationService = disposables.add(new TestInstantiationService(services, undefined, undefined, true)); + + // stubs + // eslint-disable-next-line local/code-no-dangerous-type-assertions + instantiationService.stub(IOpenerService, {} as Partial); + instantiationService.stub(ITelemetryService, NullTelemetryService); + instantiationService.stub(IBrowserWorkbenchEnvironmentService, TestEnvironmentService); + instantiationService.stub(IProductService, TestProductService); + + rpcProtocol = disposables.add(new TestRPCProtocol()); + mainThreadAuthentication = disposables.add(instantiationService.createInstance(MainThreadAuthentication, rpcProtocol)); + rpcProtocol.set(MainContext.MainThreadAuthentication, mainThreadAuthentication); + }); + + test('provider registration completes without errors', async () => { + // Test basic registration - this should complete without throwing + await mainThreadAuthentication.$registerAuthenticationProvider('test-provider', 'Test Provider', false); + + // Test unregistration - this should also complete without throwing + await mainThreadAuthentication.$unregisterAuthenticationProvider('test-provider'); + + // Success if we reach here without timeout + assert.ok(true, 'Registration and unregistration completed successfully'); + }); + + test('event suppression during explicit unregistration', async () => { + let unregisterEventFired = false; + let eventProviderId: string | undefined; + + // Mock the ext host to capture unregister events + const mockExtHost = { + $onDidUnregisterAuthenticationProvider: (id: string) => { + unregisterEventFired = true; + eventProviderId = id; + return Promise.resolve(); + }, + $getSessions: () => Promise.resolve([]), + $createSession: () => Promise.resolve({} as any), + $removeSession: () => Promise.resolve(), + $onDidChangeAuthenticationSessions: () => Promise.resolve(), + $registerDynamicAuthProvider: () => Promise.resolve('test'), + $onDidChangeDynamicAuthProviderTokens: () => Promise.resolve() + }; + rpcProtocol.set(ExtHostContext.ExtHostAuthentication, mockExtHost); + + // Register a provider + await mainThreadAuthentication.$registerAuthenticationProvider('test-suppress', 'Test Suppress', false); + + // Reset the flag + unregisterEventFired = false; + eventProviderId = undefined; + + // Unregister the provider - this should NOT fire the event due to suppression + await mainThreadAuthentication.$unregisterAuthenticationProvider('test-suppress'); + + // Verify the event was suppressed + assert.strictEqual(unregisterEventFired, false, 'Unregister event should be suppressed during explicit unregistration'); + assert.strictEqual(eventProviderId, undefined, 'No provider ID should be captured from suppressed event'); + }); + + test('concurrent provider registrations complete without errors', async () => { + // Register multiple providers simultaneously + const registrationPromises = [ + mainThreadAuthentication.$registerAuthenticationProvider('concurrent-1', 'Concurrent 1', false), + mainThreadAuthentication.$registerAuthenticationProvider('concurrent-2', 'Concurrent 2', false), + mainThreadAuthentication.$registerAuthenticationProvider('concurrent-3', 'Concurrent 3', false) + ]; + + await Promise.all(registrationPromises); + + // Unregister all providers + const unregistrationPromises = [ + mainThreadAuthentication.$unregisterAuthenticationProvider('concurrent-1'), + mainThreadAuthentication.$unregisterAuthenticationProvider('concurrent-2'), + mainThreadAuthentication.$unregisterAuthenticationProvider('concurrent-3') + ]; + + await Promise.all(unregistrationPromises); + + // Success if we reach here without timeout + assert.ok(true, 'Concurrent registrations and unregistrations completed successfully'); + }); +}); diff --git a/src/vs/workbench/api/test/common/testRPCProtocol.ts b/src/vs/workbench/api/test/common/testRPCProtocol.ts index 16a9af44f91..a85d08e4082 100644 --- a/src/vs/workbench/api/test/common/testRPCProtocol.ts +++ b/src/vs/workbench/api/test/common/testRPCProtocol.ts @@ -146,9 +146,7 @@ export class TestRPCProtocol implements IExtHostContext, IExtHostRpcService { }); } - public dispose() { - throw new Error('Not implemented!'); - } + public dispose() { } public assertRegistered(identifiers: ProxyIdentifier[]): void { throw new Error('Not implemented!'); diff --git a/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts index 731d8da9cb8..719ddc454c9 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -21,6 +21,7 @@ import { ExtensionsRegistry } from '../../extensions/common/extensionsRegistry.j import { match } from '../../../../base/common/glob.js'; import { URI } from '../../../../base/common/uri.js'; import { IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata } from '../../../../base/common/oauth.js'; +import { raceTimeout } from '../../../../base/common/async.js'; export function getAuthenticationProviderActivationEvent(id: string): string { return `onAuthenticationRequest:${id}`; } @@ -108,6 +109,8 @@ export class AuthenticationService extends Disposable implements IAuthentication private readonly _delegates: IAuthenticationProviderHostDelegate[] = []; + private _isDisposable: boolean = false; + constructor( @IExtensionService private readonly _extensionService: IExtensionService, @IAuthenticationAccessService authenticationAccessService: IAuthenticationAccessService, @@ -115,7 +118,7 @@ export class AuthenticationService extends Disposable implements IAuthentication @ILogService private readonly _logService: ILogService ) { super(); - + this._register(toDisposable(() => this._isDisposable = true)); this._register(authenticationAccessService.onDidChangeExtensionSessionAccess(e => { // The access has changed, not the actual session itself but extensions depend on this event firing // when they have gained access to an account so this fires that event. @@ -264,6 +267,10 @@ export class AuthenticationService extends Disposable implements IAuthentication } async getSessions(id: string, scopes?: string[], options?: IAuthenticationGetSessionsOptions, activateImmediate: boolean = false): Promise> { + if (this._isDisposable) { + return []; + } + const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); if (authProvider) { // Check if the authorization server is in the list of supported authorization servers @@ -281,6 +288,10 @@ export class AuthenticationService extends Disposable implements IAuthentication } async createSession(id: string, scopes: string[], options?: IAuthenticationCreateSessionOptions): Promise { + if (this._isDisposable) { + throw new Error('Authentication service is disposed.'); + } + const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, !!options?.activateImmediate); if (authProvider) { return await authProvider.createSession(scopes, { @@ -293,6 +304,10 @@ export class AuthenticationService extends Disposable implements IAuthentication } async removeSession(id: string, sessionId: string): Promise { + if (this._isDisposable) { + throw new Error('Authentication service is disposed.'); + } + const authProvider = this._authenticationProviders.get(id); if (authProvider) { return authProvider.removeSession(sessionId); @@ -361,32 +376,30 @@ export class AuthenticationService extends Disposable implements IAuthentication return provider; } - const store = new DisposableStore(); - - // When activate has completed, the extension has made the call to `registerAuthenticationProvider`. - // However, activate cannot block on this, so the renderer may not have gotten the event yet. - const didRegister: Promise = new Promise((resolve, _) => { - store.add(Event.once(this.onDidRegisterAuthenticationProvider)(e => { - if (e.id === providerId) { - provider = this._authenticationProviders.get(providerId); - if (provider) { - resolve(provider); - } else { - throw new Error(`No authentication provider '${providerId}' is currently registered.`); - } - } - })); - }); - - const didTimeout: Promise = new Promise((_, reject) => { - const handle = setTimeout(() => { - reject('Timed out waiting for authentication provider to register'); - }, 5000); - - store.add(toDisposable(() => clearTimeout(handle))); - }); - - return Promise.race([didRegister, didTimeout]).finally(() => store.dispose()); + const store = this._register(new DisposableStore()); + try { + const result = await raceTimeout( + Event.toPromise( + Event.filter( + this.onDidRegisterAuthenticationProvider, + e => e.id === providerId, + store + ), + store + ), + 5000 + ); + if (!result) { + throw new Error(`Timed out waiting for authentication provider '${providerId}' to register.`); + } + provider = this._authenticationProviders.get(result.id); + if (provider) { + return provider; + } + throw new Error(`No authentication provider '${providerId}' is currently registered.`); + } finally { + store.dispose(); + } } } From 8ece07a028f7e5f0e9f41031828f60a2a36d7411 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Jun 2025 06:27:34 +0200 Subject: [PATCH 210/236] chat - when setup without dialog is done, show welcome (#251230) --- src/vs/workbench/contrib/chat/browser/chatSetup.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup.ts b/src/vs/workbench/contrib/chat/browser/chatSetup.ts index 1b504e9e195..6afc01477e5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup.ts @@ -390,7 +390,8 @@ class SetupAgent extends Disposable implements IChatAgentImplementation { private async doInvokeWithSetup(request: IChatAgentRequest, progress: (part: IChatProgress) => void, chatService: IChatService, languageModelsService: ILanguageModelsService, chatWidgetService: IChatWidgetService, chatAgentService: IChatAgentService, languageModelToolsService: ILanguageModelToolsService): Promise { this.telemetryService.publicLog2('workbenchActionExecuted', { id: CHAT_SETUP_ACTION_ID, from: 'chat' }); - const requestModel = chatWidgetService.getWidgetBySessionId(request.sessionId)?.viewModel?.model.getRequests().at(-1); + const widget = chatWidgetService.getWidgetBySessionId(request.sessionId); + const requestModel = widget?.viewModel?.model.getRequests().at(-1); const setupListener = Event.runAndSubscribe(this.controller.value.onDidChange, (() => { switch (this.controller.value.step) { @@ -422,10 +423,7 @@ class SetupAgent extends Disposable implements IChatAgentImplementation { if (typeof result?.success === 'boolean') { if (result.success) { if (result.dialogSkipped) { - progress({ - kind: 'markdownContent', - content: new MarkdownString(localize('copilotSetupSuccess', "Copilot setup finished successfully.")) - }); + widget?.clear(); // make room for the Chat welcome experience } else if (requestModel) { let newRequest = this.replaceAgentInRequestModel(requestModel, chatAgentService); // Replace agent part with the actual Copilot agent... newRequest = this.replaceToolInRequestModel(newRequest); // ...then replace any tool parts with the actual Copilot tools From 74430769757679c680f4679b617a3e428ac8fe1d Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 12 Jun 2025 15:07:41 +1000 Subject: [PATCH 211/236] Refactor ChatEditingDocument and Cell Entries to reuse code (#251050) * Refactor ChatEditingDocument and Cell Entries to reuse code * Updates * wip * Updates * Updates * Address code review * make test diffing a little more realistic * * have one method that sets/resets the content of modified and orginal * have the method also compute the edit object * hence, remove `originalToCurrentEdit` from snapshot data * same naming nit (keep over accept, undo over discard) * Register disposables * Avoid computing diff if disposed * Fix leaks --------- Co-authored-by: Johannes --- .../chatEditingModifiedDocumentEntry.ts | 386 ++--------------- .../chatEditingModifiedFileEntry.ts | 4 +- .../chatEditingModifiedNotebookEntry.ts | 27 +- .../browser/chatEditing/chatEditingSession.ts | 4 +- .../chatEditing/chatEditingSessionStorage.ts | 4 - .../chatEditingTextModelChangeService.ts | 396 ++++++++++++++++++ .../notebook/chatEditingNotebookCellEntry.ts | 301 ++----------- .../contrib/chat/common/chatEditingService.ts | 2 - .../test/browser/chatEditingService.test.ts | 1 + .../browser/chatEditingSessionStorage.test.ts | 4 +- .../test/browser/inlineChatController.test.ts | 1 + .../test/browser/inlineChatSession.test.ts | 1 + .../test/browser/testWorkerService.ts | 14 +- 13 files changed, 494 insertions(+), 651 deletions(-) create mode 100644 src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelChangeService.ts diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts index a42e9b3ce6f..7526326abc2 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.ts @@ -3,39 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { addDisposableListener, getWindow } from '../../../../../base/browser/dom.js'; -import { assert } from '../../../../../base/common/assert.js'; -import { DeferredPromise, RunOnceScheduler, timeout } from '../../../../../base/common/async.js'; -import { IReference, MutableDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; -import { ITransaction, autorun, observableValue, transaction } from '../../../../../base/common/observable.js'; -import { isEqual } from '../../../../../base/common/resources.js'; -import { themeColorFromId } from '../../../../../base/common/themables.js'; +import { IReference, MutableDisposable } from '../../../../../base/common/lifecycle.js'; +import { ITransaction, autorun, transaction } from '../../../../../base/common/observable.js'; import { assertType } from '../../../../../base/common/types.js'; import { URI } from '../../../../../base/common/uri.js'; import { getCodeEditor } from '../../../../../editor/browser/editorBrowser.js'; -import { EditOperation, ISingleEditOperation } from '../../../../../editor/common/core/editOperation.js'; -import { StringEdit } from '../../../../../editor/common/core/edits/stringEdit.js'; -import { Range } from '../../../../../editor/common/core/range.js'; -import { IDocumentDiff, nullDocumentDiff } from '../../../../../editor/common/diff/documentDiffProvider.js'; -import { DetailedLineRangeMapping } from '../../../../../editor/common/diff/rangeMapping.js'; import { TextEdit } from '../../../../../editor/common/languages.js'; import { ILanguageService } from '../../../../../editor/common/languages/language.js'; -import { IModelDeltaDecoration, ITextModel, MinimapPosition, OverviewRulerLane } from '../../../../../editor/common/model.js'; +import { ITextModel } from '../../../../../editor/common/model.js'; import { SingleModelEditStackElement } from '../../../../../editor/common/model/editStack.js'; -import { ModelDecorationOptions, createTextBufferFactoryFromSnapshot } from '../../../../../editor/common/model/textModel.js'; -import { offsetEditFromContentChanges, offsetEditFromLineRangeMapping, offsetEditToEditOperations } from '../../../../../editor/common/model/textModelStringEdit.js'; -import { IEditorWorkerService } from '../../../../../editor/common/services/editorWorker.js'; +import { createTextBufferFactoryFromSnapshot } from '../../../../../editor/common/model/textModel.js'; import { IModelService } from '../../../../../editor/common/services/model.js'; import { IResolvedTextEditorModel, ITextModelService } from '../../../../../editor/common/services/resolverService.js'; -import { TextModelEditReason } from '../../../../../editor/common/textModelEditReason.js'; -import { IModelContentChangedEvent } from '../../../../../editor/common/textModelEvents.js'; import { localize } from '../../../../../nls.js'; -import { AccessibilitySignal, IAccessibilitySignalService } from '../../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { IFileService } from '../../../../../platform/files/common/files.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { IMarkerService } from '../../../../../platform/markers/common/markers.js'; -import { editorSelectionBackground } from '../../../../../platform/theme/common/colorRegistry.js'; import { IUndoRedoElement, IUndoRedoService } from '../../../../../platform/undoRedo/common/undoRedo.js'; import { IEditorPane, SaveReason } from '../../../../common/editor.js'; import { IFilesConfigurationService } from '../../../../services/filesConfiguration/common/filesConfigurationService.js'; @@ -44,44 +28,14 @@ import { ICellEditOperation } from '../../../notebook/common/notebookCommon.js'; import { ChatEditKind, IModifiedEntryTelemetryInfo, IModifiedFileEntry, IModifiedFileEntryEditorIntegration, ISnapshotEntry, ModifiedFileEntryState } from '../../common/chatEditingService.js'; import { IChatResponseModel } from '../../common/chatModel.js'; import { IChatService } from '../../common/chatService.js'; -import { ChatEditingCodeEditorIntegration, IDocumentDiff2 } from './chatEditingCodeEditorIntegration.js'; -import { AbstractChatEditingModifiedFileEntry, pendingRewriteMinimap } from './chatEditingModifiedFileEntry.js'; +import { ChatEditingCodeEditorIntegration } from './chatEditingCodeEditorIntegration.js'; +import { AbstractChatEditingModifiedFileEntry } from './chatEditingModifiedFileEntry.js'; +import { ChatEditingTextModelChangeService } from './chatEditingTextModelChangeService.js'; import { ChatEditingSnapshotTextModelContentProvider, ChatEditingTextModelContentProvider } from './chatEditingTextModelContentProviders.js'; export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifiedFileEntry implements IModifiedFileEntry { - private static readonly _lastEditDecorationOptions = ModelDecorationOptions.register({ - isWholeLine: true, - description: 'chat-last-edit', - className: 'chat-editing-last-edit-line', - marginClassName: 'chat-editing-last-edit', - overviewRuler: { - position: OverviewRulerLane.Full, - color: themeColorFromId(editorSelectionBackground) - }, - }); - - private static readonly _pendingEditDecorationOptions = ModelDecorationOptions.register({ - isWholeLine: true, - description: 'chat-pending-edit', - className: 'chat-editing-pending-edit', - minimap: { - position: MinimapPosition.Inline, - color: themeColorFromId(pendingRewriteMinimap) - } - }); - - private static readonly _atomicEditDecorationOptions = ModelDecorationOptions.register({ - isWholeLine: true, - description: 'chat-atomic-edit', - className: 'chat-editing-atomic-edit', - minimap: { - position: MinimapPosition.Inline, - color: themeColorFromId(pendingRewriteMinimap) - } - }); - readonly initialContent: string; private readonly originalModel: ITextModel; @@ -89,20 +43,12 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie private readonly _docFileEditorModel: IResolvedTextEditorModel; - private _edit: StringEdit = StringEdit.empty; - private _isEditFromUs: boolean = false; - private _allEditsAreFromUs: boolean = true; - private _diffOperation: Promise | undefined; - private _diffOperationIds: number = 0; - - private readonly _diffInfo = observableValue(this, nullDocumentDiff); - - readonly changesCount = this._diffInfo.map(diff => diff.changes.length); - - private readonly _editDecorationClear = this._register(new RunOnceScheduler(() => { this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, []); }, 500)); - private _editDecorations: string[] = []; + override get changesCount() { + return this._textModelChangeService.diffInfo.map(diff => diff.changes.length); + } readonly originalURI: URI; + private readonly _textModelChangeService: ChatEditingTextModelChangeService; constructor( resourceRef: IReference, @@ -117,12 +63,10 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie @IConfigurationService configService: IConfigurationService, @IFilesConfigurationService fileConfigService: IFilesConfigurationService, @IChatService chatService: IChatService, - @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService, @ITextFileService private readonly _textFileService: ITextFileService, @IFileService fileService: IFileService, @IUndoRedoService undoRedoService: IUndoRedoService, - @IInstantiationService instantiationService: IInstantiationService, - @IAccessibilitySignalService private readonly _accessibilitySignalService: IAccessibilitySignalService, + @IInstantiationService instantiationService: IInstantiationService ) { super( resourceRef.object.textEditorModel.uri, @@ -150,6 +94,14 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie ) ); + this._textModelChangeService = this._register(instantiationService.createInstance(ChatEditingTextModelChangeService, + this.originalModel, this.modifiedModel, this._stateObs)); + + this._register(this._textModelChangeService.onDidAcceptOrRejectAllHunks(action => { + this._stateObs.set(action, undefined); + this._notifyAction(action === ModifiedFileEntryState.Accepted ? 'accepted' : 'rejected'); + })); + // Create a reference to this model to avoid it being disposed from under our nose (async () => { const reference = await textModelService.createModelReference(docSnapshot.uri); @@ -161,10 +113,12 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie })(); - this._register(this.modifiedModel.onDidChangeContent(e => this._mirrorEdits(e))); - - this._register(toDisposable(() => { - this._clearCurrentEditLineDecoration(); + this._register(this._textModelChangeService.onDidUserEditModel(() => { + this._userEditScheduler.schedule(); + const didResetToOriginalContent = this.modifiedModel.getValue() === this.initialContent; + if (this._stateObs.get() === ModifiedFileEntryState.Modified && didResetToOriginalContent) { + this._stateObs.set(ModifiedFileEntryState.Rejected, undefined); + } })); const resourceFilter = this._register(new MutableDisposable()); @@ -180,17 +134,12 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie })); } - private _clearCurrentEditLineDecoration() { - this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, []); - } - equalsSnapshot(snapshot: ISnapshotEntry | undefined): boolean { return !!snapshot && this.modifiedURI.toString() === snapshot.resource.toString() && this.modifiedModel.getLanguageId() === snapshot.languageId && this.originalModel.getValue() === snapshot.original && this.modifiedModel.getValue() === snapshot.current && - this._edit.equals(snapshot.originalToCurrentEdit) && this.state.get() === snapshot.state; } @@ -201,88 +150,27 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie snapshotUri: ChatEditingSnapshotTextModelContentProvider.getSnapshotFileURI(this._telemetryInfo.sessionId, requestId, undoStop, this.modifiedURI.path), original: this.originalModel.getValue(), current: this.modifiedModel.getValue(), - originalToCurrentEdit: this._edit, state: this.state.get(), telemetryInfo: this._telemetryInfo }; } - restoreFromSnapshot(snapshot: ISnapshotEntry, restoreToDisk = true) { + async restoreFromSnapshot(snapshot: ISnapshotEntry, restoreToDisk = true) { this._stateObs.set(snapshot.state, undefined); - this.originalModel.setValue(snapshot.original); - if (restoreToDisk) { - this._setDocValue(snapshot.current); - } - this._edit = snapshot.originalToCurrentEdit; - this._updateDiffInfoSeq(); + await this._textModelChangeService.resetDocumentValues(snapshot.original, restoreToDisk ? snapshot.current : undefined); } - resetToInitialContent() { - this._setDocValue(this.initialContent); + async resetToInitialContent() { + await this._textModelChangeService.resetDocumentValues(undefined, this.initialContent); } protected override async _areOriginalAndModifiedIdentical(): Promise { - const diff = await this._diffOperation; - return diff ? diff.identical : false; + return this._textModelChangeService.areOriginalAndModifiedIdentical(); } protected override _resetEditsState(tx: ITransaction): void { super._resetEditsState(tx); - this._clearCurrentEditLineDecoration(); - } - - private _mirrorEdits(event: IModelContentChangedEvent) { - const edit = offsetEditFromContentChanges(event.changes); - - if (this._isEditFromUs) { - const e_sum = this._edit; - const e_ai = edit; - this._edit = e_sum.compose(e_ai); - } else { - - // e_ai - // d0 ---------------> s0 - // | | - // | | - // | e_user_r | e_user - // | | - // | | - // v e_ai_r v - /// d1 ---------------> s1 - // - // d0 - document snapshot - // s0 - document - // e_ai - ai edits - // e_user - user edits - // - const e_ai = this._edit; - const e_user = edit; - - const e_user_r = e_user.tryRebase(e_ai.inverse(this.originalModel.getValue()), true); - - if (e_user_r === undefined) { - // user edits overlaps/conflicts with AI edits - this._edit = e_ai.compose(e_user); - } else { - const edits = offsetEditToEditOperations(e_user_r, this.originalModel); - this.originalModel.applyEdits(edits); - this._edit = e_ai.tryRebase(e_user_r); - } - - this._allEditsAreFromUs = false; - this._userEditScheduler.schedule(); - this._updateDiffInfoSeq(); - - const didResetToOriginalContent = this.modifiedModel.getValue() === this.initialContent; - const currentState = this._stateObs.get(); - switch (currentState) { - case ModifiedFileEntryState.Modified: - if (didResetToOriginalContent) { - this._stateObs.set(ModifiedFileEntryState.Rejected, undefined); - break; - } - } - } + this._textModelChangeService.clearCurrentEditLineDecoration(); } protected override _createUndoRedoElement(response: IChatResponseModel): IUndoRedoElement { @@ -293,75 +181,7 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie async acceptAgentEdits(resource: URI, textEdits: (TextEdit | ICellEditOperation)[], isLastEdits: boolean, responseModel: IChatResponseModel): Promise { - assertType(textEdits.every(TextEdit.isTextEdit), 'INVALID args, can only handle text edits'); - assert(isEqual(resource, this.modifiedURI), ' INVALID args, can only edit THIS document'); - - const isAtomicEdits = textEdits.length > 0 && isLastEdits; - - let rewriteRatio = 0; - - if (isAtomicEdits) { - // EDIT and DONE - const minimalEdits = await this._editorWorkerService.computeMoreMinimalEdits(this.modifiedModel.uri, textEdits) ?? textEdits; - const ops = minimalEdits.map(TextEdit.asEditOperation); - const undoEdits = this._applyEdits(ops); - - if (undoEdits.length > 0) { - let range: Range | undefined; - for (let i = 0; i < undoEdits.length; i++) { - const op = undoEdits[i]; - if (!range) { - range = Range.lift(op.range); - } else { - range = Range.plusRange(range, op.range); - } - } - if (range) { - - const defer = new DeferredPromise(); - const listener = addDisposableListener(getWindow(undefined), 'animationend', e => { - if (e.animationName === 'kf-chat-editing-atomic-edit') { // CHECK with chat.css - defer.complete(); - listener.dispose(); - } - }); - - this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, [{ - options: ChatEditingModifiedDocumentEntry._atomicEditDecorationOptions, - range - }]); - - await Promise.any([defer.p, timeout(500)]); // wait for animation to finish but also time-cap it - listener.dispose(); - } - } - - - } else { - // EDIT a bit, then DONE - const ops = textEdits.map(TextEdit.asEditOperation); - const undoEdits = this._applyEdits(ops); - const maxLineNumber = undoEdits.reduce((max, op) => Math.max(max, op.range.startLineNumber), 0); - rewriteRatio = Math.min(1, maxLineNumber / this.modifiedModel.getLineCount()); - - const newDecorations: IModelDeltaDecoration[] = [ - // decorate pending edit (region) - { - options: ChatEditingModifiedDocumentEntry._pendingEditDecorationOptions, - range: new Range(maxLineNumber + 1, 1, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER) - } - ]; - - if (maxLineNumber > 0) { - // decorate last edit - newDecorations.push({ - options: ChatEditingModifiedDocumentEntry._lastEditDecorationOptions, - range: new Range(maxLineNumber, 1, maxLineNumber, Number.MAX_SAFE_INTEGER) - }); - } - this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, newDecorations); - - } + const result = await this._textModelChangeService.acceptAgentEdits(resource, textEdits, isLastEdits); transaction((tx) => { this._waitsForLastEdits.set(!isLastEdits, tx); @@ -369,13 +189,10 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie if (!isLastEdits) { this._isCurrentlyBeingModifiedByObs.set(responseModel, tx); - this._rewriteRatioObs.set(rewriteRatio, tx); - + this._rewriteRatioObs.set(result.rewriteRatio, tx); } else { this._resetEditsState(tx); - this._updateDiffInfoSeq(); this._rewriteRatioObs.set(1, tx); - this._editDecorationClear.schedule(); } }); if (isLastEdits) { @@ -386,115 +203,9 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie } } - private async _acceptHunk(change: DetailedLineRangeMapping): Promise { - if (!this._diffInfo.get().changes.includes(change)) { - // diffInfo should have model version ids and check them (instead of the caller doing that) - return false; - } - const edits: ISingleEditOperation[] = []; - for (const edit of change.innerChanges ?? []) { - const newText = this.modifiedModel.getValueInRange(edit.modifiedRange); - edits.push(EditOperation.replace(edit.originalRange, newText)); - } - this.originalModel.pushEditOperations(null, edits, _ => null); - await this._updateDiffInfoSeq(); - if (this._diffInfo.get().identical) { - this._stateObs.set(ModifiedFileEntryState.Accepted, undefined); - this._notifyAction('accepted'); - } - this._accessibilitySignalService.playSignal(AccessibilitySignal.editsKept, { allowManyInParallel: true }); - return true; - } - - private async _rejectHunk(change: DetailedLineRangeMapping): Promise { - if (!this._diffInfo.get().changes.includes(change)) { - return false; - } - const edits: ISingleEditOperation[] = []; - for (const edit of change.innerChanges ?? []) { - const newText = this.originalModel.getValueInRange(edit.originalRange); - edits.push(EditOperation.replace(edit.modifiedRange, newText)); - } - this.modifiedModel.pushEditOperations(null, edits, _ => null); - await this._updateDiffInfoSeq(); - if (this._diffInfo.get().identical) { - this._stateObs.set(ModifiedFileEntryState.Rejected, undefined); - this._notifyAction('rejected'); - } - this._accessibilitySignalService.playSignal(AccessibilitySignal.editsUndone, { allowManyInParallel: true }); - return true; - } - - private _applyEdits(edits: ISingleEditOperation[]) { - // make the actual edit - this._isEditFromUs = true; - try { - let result: ISingleEditOperation[] = []; - TextModelEditReason.editWithReason(new TextModelEditReason({ source: 'Chat.applyEdits' }), () => { - this.modifiedModel.pushEditOperations(null, edits, (undoEdits) => { - result = undoEdits; - return null; - }); - }); - return result; - } finally { - this._isEditFromUs = false; - } - } - - private async _updateDiffInfoSeq() { - const myDiffOperationId = ++this._diffOperationIds; - await Promise.resolve(this._diffOperation); - if (this._diffOperationIds === myDiffOperationId) { - const thisDiffOperation = this._updateDiffInfo(); - this._diffOperation = thisDiffOperation; - await thisDiffOperation; - } - } - - private async _updateDiffInfo(): Promise { - - if (this.originalModel.isDisposed() || this.modifiedModel.isDisposed()) { - return undefined; - } - - if (this.state.get() !== ModifiedFileEntryState.Modified) { - this._diffInfo.set(nullDocumentDiff, undefined); - return nullDocumentDiff; - } - - const docVersionNow = this.modifiedModel.getVersionId(); - const snapshotVersionNow = this.originalModel.getVersionId(); - - const diff = await this._editorWorkerService.computeDiff( - this.originalModel.uri, - this.modifiedModel.uri, - { - ignoreTrimWhitespace: false, // NEVER ignore whitespace so that undo/accept edits are correct and so that all changes (1 of 2) are spelled out - computeMoves: false, - maxComputationTimeMs: 3000 - }, - 'advanced' - ); - - if (this.originalModel.isDisposed() || this.modifiedModel.isDisposed()) { - return undefined; - } - - // only update the diff if the documents didn't change in the meantime - if (this.modifiedModel.getVersionId() === docVersionNow && this.originalModel.getVersionId() === snapshotVersionNow) { - const diff2 = diff ?? nullDocumentDiff; - this._diffInfo.set(diff2, undefined); - this._edit = offsetEditFromLineRangeMapping(this.originalModel, this.modifiedModel, diff2.changes); - return diff2; - } - return undefined; - } protected override async _doAccept(): Promise { - this.originalModel.setValue(this.modifiedModel.createSnapshot()); - this._diffInfo.set(nullDocumentDiff, undefined); - this._edit = StringEdit.empty; + this._textModelChangeService.keep(); this._multiDiffEntryDelegate.collapse(undefined); const config = this._fileConfigService.getAutoSaveConfiguration(this.modifiedURI); @@ -521,8 +232,8 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie } this._onDidDelete.fire(); } else { - this._setDocValue(this.originalModel.getValue()); - if (this._allEditsAreFromUs && isTextFileEditorModel(this._docFileEditorModel)) { + this._textModelChangeService.undo(); + if (this._textModelChangeService.allEditsAreFromUs && isTextFileEditorModel(this._docFileEditorModel)) { // save the file after discarding so that the dirty indicator goes away // and so that an intermediate saved state gets reverted await this._docFileEditorModel.save({ reason: SaveReason.EXPLICIT, skipSaveParticipants: true }); @@ -531,32 +242,11 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie } } - private _setDocValue(value: string): void { - if (this.modifiedModel.getValue() !== value) { - - this.modifiedModel.pushStackElement(); - const edit = EditOperation.replace(this.modifiedModel.getFullModelRange(), value); - - this._applyEdits([edit]); - this._updateDiffInfoSeq(); - this.modifiedModel.pushStackElement(); - } - } - - protected _createEditorIntegration(editor: IEditorPane): IModifiedFileEntryEditorIntegration { const codeEditor = getCodeEditor(editor.getControl()); assertType(codeEditor); - const diffInfo = this._diffInfo.map(value => { - return { - ...value, - originalModel: this.originalModel, - modifiedModel: this.modifiedModel, - keep: changes => this._acceptHunk(changes), - undo: changes => this._rejectHunk(changes) - } satisfies IDocumentDiff2; - }); + const diffInfo = this._textModelChangeService.diffInfo; return this._instantiationService.createInstance(ChatEditingCodeEditorIntegration, this, codeEditor, diffInfo, false); } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts index ac4474ae213..9b32f06f85a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts @@ -308,11 +308,11 @@ export abstract class AbstractChatEditingModifiedFileEntry extends Disposable im abstract equalsSnapshot(snapshot: ISnapshotEntry | undefined): boolean; - abstract restoreFromSnapshot(snapshot: ISnapshotEntry, restoreToDisk?: boolean): void; + abstract restoreFromSnapshot(snapshot: ISnapshotEntry, restoreToDisk?: boolean): Promise; // --- inital content - abstract resetToInitialContent(): void; + abstract resetToInitialContent(): Promise; abstract initialContent: string; } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts index d5616bc8221..6d5f1d8d23a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts @@ -15,7 +15,6 @@ import { assertType } from '../../../../../base/common/types.js'; import { URI } from '../../../../../base/common/uri.js'; import { generateUuid } from '../../../../../base/common/uuid.js'; import { LineRange } from '../../../../../editor/common/core/ranges/lineRange.js'; -import { StringEdit } from '../../../../../editor/common/core/edits/stringEdit.js'; import { Range } from '../../../../../editor/common/core/range.js'; import { nullDocumentDiff } from '../../../../../editor/common/diff/documentDiffProvider.js'; import { DetailedLineRangeMapping, RangeMapping } from '../../../../../editor/common/diff/rangeMapping.js'; @@ -554,17 +553,17 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie } // For all cells that were edited, send the `isLastEdits` flag. - const finishPreviousCells = () => { - this.editedCells.forEach(uri => { + const finishPreviousCells = async () => { + await Promise.all(Array.from(this.editedCells).map(async (uri) => { const cell = this.modifiedModel.cells.find(cell => isEqual(cell.uri, uri)); const cellEntry = cell && this.cellEntryMap.get(cell.uri); - cellEntry?.acceptAgentEdits([], true, responseModel); - }); + await cellEntry?.acceptAgentEdits([], true, responseModel); + })); this.editedCells.clear(); }; - this._applyEditsSync(async () => { - edits.map((edit, idx) => { + this._applyEdits(async () => { + await Promise.all(edits.map(async (edit, idx) => { const last = isLastEdits && idx === edits.length - 1; if (TextEdit.isTextEdit(edit)) { // Possible we're getting the raw content for the notebook. @@ -575,22 +574,22 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie // If we get cell edits, its impossible to get text edits for the notebook uri. this.newNotebookEditGenerator = undefined; if (!this.editedCells.has(resource)) { - finishPreviousCells(); + await finishPreviousCells(); this.editedCells.add(resource); } - cellEntry?.acceptAgentEdits([edit], last, responseModel); + await cellEntry?.acceptAgentEdits([edit], last, responseModel); } } else { // If we notebook edits, its impossible to get text edits for the notebook uri. this.newNotebookEditGenerator = undefined; this.acceptNotebookEdit(edit); } - }); + })); }); // If the last edit for a cell was sent, then handle it if (isLastEdits) { - finishPreviousCells(); + await finishPreviousCells(); } // isLastEdits can be true for cell Uris, but when its true for Cells edits. @@ -612,7 +611,6 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie const newRewriteRation = Math.max(this._rewriteRatioObs.get(), calculateNotebookRewriteRatio(this._cellsDiffInfo.get(), this.originalModel, this.modifiedModel)); this._rewriteRatioObs.set(Math.min(1, newRewriteRation), tx); } else { - finishPreviousCells(); this.editedCells.clear(); this._resetEditsState(tx); this._rewriteRatioObs.set(1, tx); @@ -918,7 +916,6 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie snapshotUri: getNotebookSnapshotFileURI(this._telemetryInfo.sessionId, requestId, undoStop, this.modifiedURI.path, this.modifiedModel.viewType), original: createSnapshot(this.originalModel, this.transientOptions, this.configurationService), current: createSnapshot(this.modifiedModel, this.transientOptions, this.configurationService), - originalToCurrentEdit: StringEdit.empty, state: this.state.get(), telemetryInfo: this.telemetryInfo, }; @@ -933,7 +930,7 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie } - override restoreFromSnapshot(snapshot: ISnapshotEntry, restoreToDisk = true): void { + override async restoreFromSnapshot(snapshot: ISnapshotEntry, restoreToDisk = true): Promise { this.updateCellDiffInfo([], undefined); this._stateObs.set(snapshot.state, undefined); restoreSnapshot(this.originalModel, snapshot.original); @@ -943,7 +940,7 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie this.initializeModelsFromDiff(); } - override resetToInitialContent(): void { + override async resetToInitialContent(): Promise { this.updateCellDiffInfo([], undefined); this.restoreSnapshotInModifiedModel(this.initialContent); this.initializeModelsFromDiff(); diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts index 422c4045c42..2aca28634ef 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts @@ -512,7 +512,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio for (const entry of this._entriesObs.get()) { const snapshotEntry = entries.get(entry.modifiedURI); if (!snapshotEntry) { - entry.resetToInitialContent(); + await entry.resetToInitialContent(); entry.dispose(); } } @@ -522,7 +522,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio for (const snapshotEntry of entries.values()) { const entry = await this._getOrCreateModifiedFileEntry(snapshotEntry.resource, snapshotEntry.telemetryInfo); const restoreToDisk = snapshotEntry.state === ModifiedFileEntryState.Modified || restoreResolvedToDisk; - entry.restoreFromSnapshot(snapshotEntry, restoreToDisk); + await entry.restoreFromSnapshot(snapshotEntry, restoreToDisk); entriesArr.push(entry); } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts index 93b386d4fb4..d755618c797 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts @@ -8,7 +8,6 @@ import { StringSHA1 } from '../../../../../base/common/hash.js'; import { ResourceMap } from '../../../../../base/common/map.js'; import { joinPath } from '../../../../../base/common/resources.js'; import { URI } from '../../../../../base/common/uri.js'; -import { StringEdit, ISerializedStringEdit } from '../../../../../editor/common/core/edits/stringEdit.js'; import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js'; import { IFileService } from '../../../../../platform/files/common/files.js'; import { ILogService } from '../../../../../platform/log/common/log.js'; @@ -79,7 +78,6 @@ export class ChatEditingSessionStorage { languageId: entry.languageId, original: await getFileContent(entry.originalHash), current: await getFileContent(entry.currentHash), - originalToCurrentEdit: StringEdit.fromJson(entry.originalToCurrentEdit), state: entry.state, snapshotUri: URI.parse(entry.snapshotUri), telemetryInfo: { requestId: entry.telemetryInfo.requestId, agentId: entry.telemetryInfo.agentId, command: entry.telemetryInfo.command, sessionId: this.chatSessionId, result: undefined } @@ -179,7 +177,6 @@ export class ChatEditingSessionStorage { languageId: entry.languageId, originalHash: addFileContent(entry.original), currentHash: addFileContent(entry.current), - originalToCurrentEdit: entry.originalToCurrentEdit.toJson(), state: entry.state, snapshotUri: entry.snapshotUri.toString(), telemetryInfo: { requestId: entry.telemetryInfo.requestId, agentId: entry.telemetryInfo.agentId, command: entry.telemetryInfo.command } @@ -274,7 +271,6 @@ interface ISnapshotEntryDTO { readonly languageId: string; readonly originalHash: string; readonly currentHash: string; - readonly originalToCurrentEdit: ISerializedStringEdit; readonly state: ModifiedFileEntryState; readonly snapshotUri: string; readonly telemetryInfo: IModifiedEntryTelemetryInfoDTO; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelChangeService.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelChangeService.ts new file mode 100644 index 00000000000..d4d42d87356 --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingTextModelChangeService.ts @@ -0,0 +1,396 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { addDisposableListener, getWindow } from '../../../../../base/browser/dom.js'; +import { assert } from '../../../../../base/common/assert.js'; +import { DeferredPromise, RunOnceScheduler, timeout } from '../../../../../base/common/async.js'; +import { Emitter } from '../../../../../base/common/event.js'; +import { Disposable, toDisposable } from '../../../../../base/common/lifecycle.js'; +import { IObservable, observableValue } from '../../../../../base/common/observable.js'; +import { isEqual } from '../../../../../base/common/resources.js'; +import { themeColorFromId } from '../../../../../base/common/themables.js'; +import { assertType } from '../../../../../base/common/types.js'; +import { URI } from '../../../../../base/common/uri.js'; +import { EditOperation, ISingleEditOperation } from '../../../../../editor/common/core/editOperation.js'; +import { StringEdit } from '../../../../../editor/common/core/edits/stringEdit.js'; +import { Range } from '../../../../../editor/common/core/range.js'; +import { IDocumentDiff, nullDocumentDiff } from '../../../../../editor/common/diff/documentDiffProvider.js'; +import { DetailedLineRangeMapping } from '../../../../../editor/common/diff/rangeMapping.js'; +import { TextEdit } from '../../../../../editor/common/languages.js'; +import { IModelDeltaDecoration, ITextModel, ITextSnapshot, MinimapPosition, OverviewRulerLane } from '../../../../../editor/common/model.js'; +import { ModelDecorationOptions } from '../../../../../editor/common/model/textModel.js'; +import { offsetEditFromContentChanges, offsetEditFromLineRangeMapping, offsetEditToEditOperations } from '../../../../../editor/common/model/textModelStringEdit.js'; +import { IEditorWorkerService } from '../../../../../editor/common/services/editorWorker.js'; +import { TextModelEditReason } from '../../../../../editor/common/textModelEditReason.js'; +import { IModelContentChangedEvent } from '../../../../../editor/common/textModelEvents.js'; +import { AccessibilitySignal, IAccessibilitySignalService } from '../../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js'; +import { editorSelectionBackground } from '../../../../../platform/theme/common/colorRegistry.js'; +import { ICellEditOperation } from '../../../notebook/common/notebookCommon.js'; +import { ModifiedFileEntryState } from '../../common/chatEditingService.js'; +import { IDocumentDiff2 } from './chatEditingCodeEditorIntegration.js'; +import { pendingRewriteMinimap } from './chatEditingModifiedFileEntry.js'; + + +export class ChatEditingTextModelChangeService extends Disposable { + + private static readonly _lastEditDecorationOptions = ModelDecorationOptions.register({ + isWholeLine: true, + description: 'chat-last-edit', + className: 'chat-editing-last-edit-line', + marginClassName: 'chat-editing-last-edit', + overviewRuler: { + position: OverviewRulerLane.Full, + color: themeColorFromId(editorSelectionBackground) + }, + }); + + private static readonly _pendingEditDecorationOptions = ModelDecorationOptions.register({ + isWholeLine: true, + description: 'chat-pending-edit', + className: 'chat-editing-pending-edit', + minimap: { + position: MinimapPosition.Inline, + color: themeColorFromId(pendingRewriteMinimap) + } + }); + + private static readonly _atomicEditDecorationOptions = ModelDecorationOptions.register({ + isWholeLine: true, + description: 'chat-atomic-edit', + className: 'chat-editing-atomic-edit', + minimap: { + position: MinimapPosition.Inline, + color: themeColorFromId(pendingRewriteMinimap) + } + }); + + private _isEditFromUs: boolean = false; + public get isEditFromUs() { + return this._isEditFromUs; + } + private _allEditsAreFromUs: boolean = true; + public get allEditsAreFromUs() { + return this._allEditsAreFromUs; + } + private _diffOperation: Promise | undefined; + private _diffOperationIds: number = 0; + + private readonly _diffInfo = observableValue(this, nullDocumentDiff); + public get diffInfo() { + return this._diffInfo.map(value => { + return { + ...value, + originalModel: this.originalModel, + modifiedModel: this.modifiedModel, + keep: changes => this._keepHunk(changes), + undo: changes => this._undoHunk(changes) + } satisfies IDocumentDiff2; + }); + } + + private readonly _editDecorationClear = this._register(new RunOnceScheduler(() => { this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, []); }, 500)); + private _editDecorations: string[] = []; + + private readonly _didAcceptOrRejectAllHunks = this._register(new Emitter()); + public readonly onDidAcceptOrRejectAllHunks = this._didAcceptOrRejectAllHunks.event; + + private readonly _didUserEditModel = this._register(new Emitter()); + public readonly onDidUserEditModel = this._didUserEditModel.event; + + private _originalToModifiedEdit: StringEdit = StringEdit.empty; + + constructor( + private readonly originalModel: ITextModel, + private readonly modifiedModel: ITextModel, + private readonly state: IObservable, + @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService, + @IAccessibilitySignalService private readonly _accessibilitySignalService: IAccessibilitySignalService, + ) { + super(); + this._register(this.modifiedModel.onDidChangeContent(e => { + this._mirrorEdits(e); + })); + + this._register(toDisposable(() => { + this.clearCurrentEditLineDecoration(); + })); + } + + public clearCurrentEditLineDecoration() { + this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, []); + } + + public async areOriginalAndModifiedIdentical(): Promise { + const diff = await this._diffOperation; + return diff ? diff.identical : false; + } + + async acceptAgentEdits(resource: URI, textEdits: (TextEdit | ICellEditOperation)[], isLastEdits: boolean): Promise<{ rewriteRatio: number; maxLineNumber: number }> { + + assertType(textEdits.every(TextEdit.isTextEdit), 'INVALID args, can only handle text edits'); + assert(isEqual(resource, this.modifiedModel.uri), ' INVALID args, can only edit THIS document'); + + const isAtomicEdits = textEdits.length > 0 && isLastEdits; + let maxLineNumber = 0; + let rewriteRatio = 0; + + if (isAtomicEdits) { + // EDIT and DONE + const minimalEdits = await this._editorWorkerService.computeMoreMinimalEdits(this.modifiedModel.uri, textEdits) ?? textEdits; + const ops = minimalEdits.map(TextEdit.asEditOperation); + const undoEdits = this._applyEdits(ops); + + if (undoEdits.length > 0) { + let range: Range | undefined; + for (let i = 0; i < undoEdits.length; i++) { + const op = undoEdits[i]; + if (!range) { + range = Range.lift(op.range); + } else { + range = Range.plusRange(range, op.range); + } + } + if (range) { + + const defer = new DeferredPromise(); + const listener = addDisposableListener(getWindow(undefined), 'animationend', e => { + if (e.animationName === 'kf-chat-editing-atomic-edit') { // CHECK with chat.css + defer.complete(); + listener.dispose(); + } + }); + + this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, [{ + options: ChatEditingTextModelChangeService._atomicEditDecorationOptions, + range + }]); + + await Promise.any([defer.p, timeout(500)]); // wait for animation to finish but also time-cap it + listener.dispose(); + } + } + + + } else { + // EDIT a bit, then DONE + const ops = textEdits.map(TextEdit.asEditOperation); + const undoEdits = this._applyEdits(ops); + maxLineNumber = undoEdits.reduce((max, op) => Math.max(max, op.range.startLineNumber), 0); + rewriteRatio = Math.min(1, maxLineNumber / this.modifiedModel.getLineCount()); + + const newDecorations: IModelDeltaDecoration[] = [ + // decorate pending edit (region) + { + options: ChatEditingTextModelChangeService._pendingEditDecorationOptions, + range: new Range(maxLineNumber + 1, 1, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER) + } + ]; + + if (maxLineNumber > 0) { + // decorate last edit + newDecorations.push({ + options: ChatEditingTextModelChangeService._lastEditDecorationOptions, + range: new Range(maxLineNumber, 1, maxLineNumber, Number.MAX_SAFE_INTEGER) + }); + } + this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, newDecorations); + + } + + if (isLastEdits) { + this._updateDiffInfoSeq(); + this._editDecorationClear.schedule(); + } + + return { rewriteRatio, maxLineNumber }; + } + + private _applyEdits(edits: ISingleEditOperation[]) { + try { + this._isEditFromUs = true; + // make the actual edit + let result: ISingleEditOperation[] = []; + TextModelEditReason.editWithReason(new TextModelEditReason({ source: 'Chat.applyEdits' }), () => { + this.modifiedModel.pushEditOperations(null, edits, (undoEdits) => { + result = undoEdits; + return null; + }); + }); + return result; + } finally { + this._isEditFromUs = false; + } + } + + /** + * Keeps the current modified document as the final contents. + */ + public keep() { + this.originalModel.setValue(this.modifiedModel.createSnapshot()); + this._diffInfo.set(nullDocumentDiff, undefined); + this._originalToModifiedEdit = StringEdit.empty; + } + + /** + * Undoes the current modified document as the final contents. + */ + public undo() { + this.modifiedModel.pushStackElement(); + this._applyEdits([(EditOperation.replace(this.modifiedModel.getFullModelRange(), this.originalModel.getValue()))]); + this.modifiedModel.pushStackElement(); + this._originalToModifiedEdit = StringEdit.empty; + this._diffInfo.set(nullDocumentDiff, undefined); + } + + public async resetDocumentValues(newOriginal: string | ITextSnapshot | undefined, newModified: string | undefined): Promise { + let didChange = false; + if (newOriginal !== undefined) { + this.originalModel.setValue(newOriginal); + didChange = true; + } + if (newModified !== undefined && this.modifiedModel.getValue() !== newModified) { + // NOTE that this isn't done via `setValue` so that the undo stack is preserved + this.modifiedModel.pushStackElement(); + this._applyEdits([(EditOperation.replace(this.modifiedModel.getFullModelRange(), newModified))]); + this.modifiedModel.pushStackElement(); + didChange = true; + } + if (didChange) { + await this._updateDiffInfoSeq(); + } + } + + private _mirrorEdits(event: IModelContentChangedEvent) { + const edit = offsetEditFromContentChanges(event.changes); + + if (this._isEditFromUs) { + const e_sum = this._originalToModifiedEdit; + const e_ai = edit; + this._originalToModifiedEdit = e_sum.compose(e_ai); + } else { + + // e_ai + // d0 ---------------> s0 + // | | + // | | + // | e_user_r | e_user + // | | + // | | + // v e_ai_r v + /// d1 ---------------> s1 + // + // d0 - document snapshot + // s0 - document + // e_ai - ai edits + // e_user - user edits + // + const e_ai = this._originalToModifiedEdit; + const e_user = edit; + + const e_user_r = e_user.tryRebase(e_ai.inverse(this.originalModel.getValue()), true); + + if (e_user_r === undefined) { + // user edits overlaps/conflicts with AI edits + this._originalToModifiedEdit = e_ai.compose(e_user); + } else { + const edits = offsetEditToEditOperations(e_user_r, this.originalModel); + this.originalModel.applyEdits(edits); + this._originalToModifiedEdit = e_ai.tryRebase(e_user_r); + } + + this._allEditsAreFromUs = false; + this._updateDiffInfoSeq(); + this._didUserEditModel.fire(); + } + } + + private async _keepHunk(change: DetailedLineRangeMapping): Promise { + if (!this._diffInfo.get().changes.includes(change)) { + // diffInfo should have model version ids and check them (instead of the caller doing that) + return false; + } + const edits: ISingleEditOperation[] = []; + for (const edit of change.innerChanges ?? []) { + const newText = this.modifiedModel.getValueInRange(edit.modifiedRange); + edits.push(EditOperation.replace(edit.originalRange, newText)); + } + this.originalModel.pushEditOperations(null, edits, _ => null); + await this._updateDiffInfoSeq(); + if (this._diffInfo.get().identical) { + this._didAcceptOrRejectAllHunks.fire(ModifiedFileEntryState.Accepted); + } + this._accessibilitySignalService.playSignal(AccessibilitySignal.editsKept, { allowManyInParallel: true }); + return true; + } + + private async _undoHunk(change: DetailedLineRangeMapping): Promise { + if (!this._diffInfo.get().changes.includes(change)) { + return false; + } + const edits: ISingleEditOperation[] = []; + for (const edit of change.innerChanges ?? []) { + const newText = this.originalModel.getValueInRange(edit.originalRange); + edits.push(EditOperation.replace(edit.modifiedRange, newText)); + } + this.modifiedModel.pushEditOperations(null, edits, _ => null); + await this._updateDiffInfoSeq(); + if (this._diffInfo.get().identical) { + this._didAcceptOrRejectAllHunks.fire(ModifiedFileEntryState.Rejected); + } + this._accessibilitySignalService.playSignal(AccessibilitySignal.editsUndone, { allowManyInParallel: true }); + return true; + } + + + private async _updateDiffInfoSeq() { + const myDiffOperationId = ++this._diffOperationIds; + await Promise.resolve(this._diffOperation); + if (this._diffOperationIds === myDiffOperationId) { + const thisDiffOperation = this._updateDiffInfo(); + this._diffOperation = thisDiffOperation; + await thisDiffOperation; + } + } + + private async _updateDiffInfo(): Promise { + + if (this.originalModel.isDisposed() || this.modifiedModel.isDisposed() || this._store.isDisposed) { + return undefined; + } + + if (this.state.get() !== ModifiedFileEntryState.Modified) { + this._diffInfo.set(nullDocumentDiff, undefined); + this._originalToModifiedEdit = StringEdit.empty; + return nullDocumentDiff; + } + + const docVersionNow = this.modifiedModel.getVersionId(); + const snapshotVersionNow = this.originalModel.getVersionId(); + + const diff = await this._editorWorkerService.computeDiff( + this.originalModel.uri, + this.modifiedModel.uri, + { + ignoreTrimWhitespace: false, // NEVER ignore whitespace so that undo/accept edits are correct and so that all changes (1 of 2) are spelled out + computeMoves: false, + maxComputationTimeMs: 3000 + }, + 'advanced' + ); + + if (this.originalModel.isDisposed() || this.modifiedModel.isDisposed() || this._store.isDisposed) { + return undefined; + } + + // only update the diff if the documents didn't change in the meantime + if (this.modifiedModel.getVersionId() === docVersionNow && this.originalModel.getVersionId() === snapshotVersionNow) { + const diff2 = diff ?? nullDocumentDiff; + this._diffInfo.set(diff2, undefined); + this._originalToModifiedEdit = offsetEditFromLineRangeMapping(this.originalModel, this.modifiedModel, diff2.changes); + return diff2; + } + return undefined; + } +} diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts index 96359ead4e5..b5f099d2a95 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookCellEntry.ts @@ -3,32 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { RunOnceScheduler } from '../../../../../../base/common/async.js'; -import { Disposable, DisposableStore, toDisposable } from '../../../../../../base/common/lifecycle.js'; -import { ITransaction, IObservable, observableValue, autorun, transaction } from '../../../../../../base/common/observable.js'; -import { themeColorFromId } from '../../../../../../base/common/themables.js'; +import { Disposable, DisposableStore } from '../../../../../../base/common/lifecycle.js'; +import { IObservable, observableValue, transaction } from '../../../../../../base/common/observable.js'; import { URI } from '../../../../../../base/common/uri.js'; -import { EditOperation, ISingleEditOperation } from '../../../../../../editor/common/core/editOperation.js'; -import { StringEdit } from '../../../../../../editor/common/core/edits/stringEdit.js'; -import { Range } from '../../../../../../editor/common/core/range.js'; -import { IDocumentDiff, nullDocumentDiff } from '../../../../../../editor/common/diff/documentDiffProvider.js'; +import { IDocumentDiff } from '../../../../../../editor/common/diff/documentDiffProvider.js'; import { DetailedLineRangeMapping } from '../../../../../../editor/common/diff/rangeMapping.js'; import { TextEdit } from '../../../../../../editor/common/languages.js'; -import { IModelDeltaDecoration, ITextModel, MinimapPosition, OverviewRulerLane } from '../../../../../../editor/common/model.js'; -import { ModelDecorationOptions } from '../../../../../../editor/common/model/textModel.js'; -import { offsetEditFromContentChanges, offsetEditFromLineRangeMapping, offsetEditToEditOperations } from '../../../../../../editor/common/model/textModelStringEdit.js'; -import { IEditorWorkerService } from '../../../../../../editor/common/services/editorWorker.js'; -import { IModelContentChangedEvent } from '../../../../../../editor/common/textModelEvents.js'; -import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; -import { observableConfigValue } from '../../../../../../platform/observable/common/platformObservableUtils.js'; -import { editorSelectionBackground } from '../../../../../../platform/theme/common/colorRegistry.js'; +import { ITextModel } from '../../../../../../editor/common/model.js'; +import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { CellEditState } from '../../../../notebook/browser/notebookBrowser.js'; import { INotebookEditorService } from '../../../../notebook/browser/services/notebookEditorService.js'; import { NotebookCellTextModel } from '../../../../notebook/common/model/notebookCellTextModel.js'; import { CellKind } from '../../../../notebook/common/notebookCommon.js'; import { ModifiedFileEntryState } from '../../../common/chatEditingService.js'; import { IChatResponseModel } from '../../../common/chatModel.js'; -import { pendingRewriteMinimap } from '../chatEditingModifiedFileEntry.js'; +import { ChatEditingTextModelChangeService } from '../chatEditingTextModelChangeService.js'; /** @@ -37,202 +26,76 @@ import { pendingRewriteMinimap } from '../chatEditingModifiedFileEntry.js'; * Hence most of the same functionality applies. */ export class ChatEditingNotebookCellEntry extends Disposable { - private static readonly _lastEditDecorationOptions = ModelDecorationOptions.register({ - isWholeLine: true, - description: 'chat-last-edit', - className: 'chat-editing-last-edit-line', - marginClassName: 'chat-editing-last-edit', - overviewRuler: { - position: OverviewRulerLane.Full, - color: themeColorFromId(editorSelectionBackground) - }, - }); - - private static readonly _pendingEditDecorationOptions = ModelDecorationOptions.register({ - isWholeLine: true, - description: 'chat-pending-edit', - className: 'chat-editing-pending-edit', - minimap: { - position: MinimapPosition.Inline, - color: themeColorFromId(pendingRewriteMinimap) - } - }); - - public get isDisposed(): boolean { return this._store.isDisposed; } - private _edit: StringEdit = StringEdit.empty; - private _isEditFromUs: boolean = false; public get isEditFromUs(): boolean { - return this._isEditFromUs; + return this._textModelChangeService.isEditFromUs; } - private _allEditsAreFromUs: boolean = true; public get allEditsAreFromUs(): boolean { - return this._allEditsAreFromUs; + return this._textModelChangeService.allEditsAreFromUs; } - private _diffOperation: Promise | undefined; - private _diffOperationIds: number = 0; - - private readonly _diffInfo = observableValue(this, nullDocumentDiff); public get diffInfo(): IObservable { - return this._diffInfo; + return this._textModelChangeService.diffInfo; } private readonly _maxModifiedLineNumber = observableValue(this, 0); readonly maxModifiedLineNumber = this._maxModifiedLineNumber; - private readonly _editDecorationClear = this._register(new RunOnceScheduler(() => { this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, []); }, 500)); - private _editDecorations: string[] = []; - - private readonly _diffTrimWhitespace: IObservable; protected readonly _stateObs = observableValue(this, ModifiedFileEntryState.Modified); readonly state: IObservable = this._stateObs; - protected readonly _isCurrentlyBeingModifiedByObs = observableValue(this, undefined); - readonly isCurrentlyBeingModifiedBy: IObservable = this._isCurrentlyBeingModifiedByObs; private readonly initialContent: string; - + private readonly _textModelChangeService: ChatEditingTextModelChangeService; constructor( public readonly notebookUri: URI, public readonly cell: NotebookCellTextModel, private readonly modifiedModel: ITextModel, private readonly originalModel: ITextModel, disposables: DisposableStore, - @IConfigurationService configService: IConfigurationService, - @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService, - @INotebookEditorService private readonly notebookEditorService: INotebookEditorService + @INotebookEditorService private readonly notebookEditorService: INotebookEditorService, + @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); this.initialContent = this.originalModel.getValue(); this._register(disposables); - this._register(this.modifiedModel.onDidChangeContent(e => { - this._mirrorEdits(e); - })); - this._register(toDisposable(() => { - this.clearCurrentEditLineDecoration(); + this._textModelChangeService = this._register(this.instantiationService.createInstance(ChatEditingTextModelChangeService, this.originalModel, this.modifiedModel, this.state)); + + this._register(this._textModelChangeService.onDidAcceptOrRejectAllHunks(action => { + this.revertMarkdownPreviewState(); + this._stateObs.set(action, undefined); })); - this._diffTrimWhitespace = observableConfigValue('diffEditor.ignoreTrimWhitespace', true, configService); - this._register(autorun(r => { - this._diffTrimWhitespace.read(r); - this._updateDiffInfoSeq(); + this._register(this._textModelChangeService.onDidUserEditModel(() => { + const didResetToOriginalContent = this.modifiedModel.getValue() === this.initialContent; + if (this._stateObs.get() === ModifiedFileEntryState.Modified && didResetToOriginalContent) { + this._stateObs.set(ModifiedFileEntryState.Rejected, undefined); + } })); + } public clearCurrentEditLineDecoration() { if (this.modifiedModel.isDisposed()) { return; } - this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, []); + this._textModelChangeService.clearCurrentEditLineDecoration(); } - - private _mirrorEdits(event: IModelContentChangedEvent) { - const edit = offsetEditFromContentChanges(event.changes); - - if (this._isEditFromUs) { - const e_sum = this._edit; - const e_ai = edit; - this._edit = e_sum.compose(e_ai); - - } else { - - // e_ai - // d0 ---------------> s0 - // | | - // | | - // | e_user_r | e_user - // | | - // | | - // v e_ai_r v - /// d1 ---------------> s1 - // - // d0 - document snapshot - // s0 - document - // e_ai - ai edits - // e_user - user edits - // - const e_ai = this._edit; - const e_user = edit; - - const e_user_r = e_user.tryRebase(e_ai.inverse(this.originalModel.getValue()), true); - - if (e_user_r === undefined) { - // user edits overlaps/conflicts with AI edits - this._edit = e_ai.compose(e_user); - } else { - const edits = offsetEditToEditOperations(e_user_r, this.originalModel); - this.originalModel.applyEdits(edits); - this._edit = e_ai.tryRebase(e_user_r); - } - - this._allEditsAreFromUs = false; - this._updateDiffInfoSeq(); - - const didResetToOriginalContent = this.modifiedModel.getValue() === this.initialContent; - const currentState = this._stateObs.get(); - switch (currentState) { - case ModifiedFileEntryState.Modified: - if (didResetToOriginalContent) { - this._stateObs.set(ModifiedFileEntryState.Rejected, undefined); - break; - } - } - - } - } - - acceptAgentEdits(textEdits: TextEdit[], isLastEdits: boolean, responseModel: IChatResponseModel): void { - const notebookEditor = this.notebookEditorService.retrieveExistingWidgetFromURI(this.notebookUri)?.value; - if (notebookEditor) { - const vm = notebookEditor.getCellByHandle(this.cell.handle); - vm?.updateEditState(CellEditState.Editing, 'chatEdit'); - } - - const ops = textEdits.map(TextEdit.asEditOperation); - const undoEdits = this._applyEdits(ops); - - const maxLineNumber = undoEdits.reduce((max, op) => Math.max(max, op.range.startLineNumber), 0); - - const newDecorations: IModelDeltaDecoration[] = [ - // decorate pending edit (region) - { - options: ChatEditingNotebookCellEntry._pendingEditDecorationOptions, - range: new Range(maxLineNumber + 1, 1, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER) - } - ]; - - if (maxLineNumber > 0) { - // decorate last edit - newDecorations.push({ - options: ChatEditingNotebookCellEntry._lastEditDecorationOptions, - range: new Range(maxLineNumber, 1, maxLineNumber, Number.MAX_SAFE_INTEGER) - }); - } - - this._editDecorations = this.modifiedModel.deltaDecorations(this._editDecorations, newDecorations); - + async acceptAgentEdits(textEdits: TextEdit[], isLastEdits: boolean, responseModel: IChatResponseModel): Promise { + const { maxLineNumber } = await this._textModelChangeService.acceptAgentEdits(this.modifiedModel.uri, textEdits, isLastEdits); transaction((tx) => { if (!isLastEdits) { this._stateObs.set(ModifiedFileEntryState.Modified, tx); - this._isCurrentlyBeingModifiedByObs.set(responseModel, tx); this._maxModifiedLineNumber.set(maxLineNumber, tx); } else { - this._resetEditsState(tx); - this._updateDiffInfoSeq(); this._maxModifiedLineNumber.set(0, tx); - this._editDecorationClear.schedule(); } }); } - scheduleEditDecorations() { - this._editDecorationClear.schedule(); - } - revertMarkdownPreviewState(): void { if (this.cell.cellKind !== CellKind.Markup) { return; @@ -248,119 +111,11 @@ export class ChatEditingNotebookCellEntry extends Disposable { } } - protected _resetEditsState(tx: ITransaction): void { - this._isCurrentlyBeingModifiedByObs.set(undefined, tx); - this._maxModifiedLineNumber.set(0, tx); - } - public async keep(change: DetailedLineRangeMapping): Promise { - return this._acceptHunk(change); - } - - private async _acceptHunk(change: DetailedLineRangeMapping): Promise { - this._isEditFromUs = true; - try { - if (!this._diffInfo.get().changes.filter(c => c.modified.equals(change.modified) && c.original.equals(change.original)).length) { - // diffInfo should have model version ids and check them (instead of the caller doing that) - return false; - } - const edits: ISingleEditOperation[] = []; - for (const edit of change.innerChanges ?? []) { - const newText = this.modifiedModel.getValueInRange(edit.modifiedRange); - edits.push(EditOperation.replace(edit.originalRange, newText)); - } - this.originalModel.pushEditOperations(null, edits, _ => null); - } - finally { - this._isEditFromUs = false; - } - await this._updateDiffInfoSeq(); - if (this._diffInfo.get().identical) { - this.revertMarkdownPreviewState(); - this._stateObs.set(ModifiedFileEntryState.Accepted, undefined); - } - return true; + return this._textModelChangeService.diffInfo.get().keep(change); } public async undo(change: DetailedLineRangeMapping): Promise { - return this._rejectHunk(change); - } - - private async _rejectHunk(change: DetailedLineRangeMapping): Promise { - this._isEditFromUs = true; - try { - if (!this._diffInfo.get().changes.includes(change)) { - return false; - } - const edits: ISingleEditOperation[] = []; - for (const edit of change.innerChanges ?? []) { - const newText = this.originalModel.getValueInRange(edit.originalRange); - edits.push(EditOperation.replace(edit.modifiedRange, newText)); - } - this.modifiedModel.pushEditOperations(null, edits, _ => null); - } finally { - this._isEditFromUs = false; - } - await this._updateDiffInfoSeq(); - if (this._diffInfo.get().identical) { - this.revertMarkdownPreviewState(); - this._stateObs.set(ModifiedFileEntryState.Rejected, undefined); - } - return true; - } - - private _applyEdits(edits: ISingleEditOperation[]) { - // make the actual edit - this._isEditFromUs = true; - try { - let result: ISingleEditOperation[] = []; - this.modifiedModel.pushEditOperations(null, edits, (undoEdits) => { - result = undoEdits; - return null; - }); - return result; - } finally { - this._isEditFromUs = false; - } - } - - private async _updateDiffInfoSeq() { - const myDiffOperationId = ++this._diffOperationIds; - await Promise.resolve(this._diffOperation); - if (this._diffOperationIds === myDiffOperationId) { - const thisDiffOperation = this._updateDiffInfo(); - this._diffOperation = thisDiffOperation; - await thisDiffOperation; - } - } - - private async _updateDiffInfo(): Promise { - - if (this.originalModel.isDisposed() || this.modifiedModel.isDisposed()) { - return; - } - - const docVersionNow = this.modifiedModel.getVersionId(); - const snapshotVersionNow = this.originalModel.getVersionId(); - - const ignoreTrimWhitespace = this._diffTrimWhitespace.get(); - - const diff = await this._editorWorkerService.computeDiff( - this.originalModel.uri, - this.modifiedModel.uri, - { ignoreTrimWhitespace, computeMoves: false, maxComputationTimeMs: 3000 }, - 'advanced' - ); - - if (this.originalModel.isDisposed() || this.modifiedModel.isDisposed()) { - return; - } - - // only update the diff if the documents didn't change in the meantime - if (this.modifiedModel.getVersionId() === docVersionNow && this.originalModel.getVersionId() === snapshotVersionNow) { - const diff2 = diff ?? nullDocumentDiff; - this._diffInfo.set(diff2, undefined); - this._edit = offsetEditFromLineRangeMapping(this.originalModel, this.modifiedModel, diff2.changes); - } + return this._textModelChangeService.diffInfo.get().undo(change); } } diff --git a/src/vs/workbench/contrib/chat/common/chatEditingService.ts b/src/vs/workbench/contrib/chat/common/chatEditingService.ts index 97a3f3a499f..e28eaa47ecf 100644 --- a/src/vs/workbench/contrib/chat/common/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/common/chatEditingService.ts @@ -8,7 +8,6 @@ import { Event } from '../../../../base/common/event.js'; import { IDisposable } from '../../../../base/common/lifecycle.js'; import { IObservable, IReader } from '../../../../base/common/observable.js'; import { URI } from '../../../../base/common/uri.js'; -import { StringEdit } from '../../../../editor/common/core/edits/stringEdit.js'; import { TextEdit } from '../../../../editor/common/languages.js'; import { ITextModel } from '../../../../editor/common/model.js'; import { localize } from '../../../../nls.js'; @@ -96,7 +95,6 @@ export interface ISnapshotEntry { readonly snapshotUri: URI; readonly original: string; readonly current: string; - readonly originalToCurrentEdit: StringEdit; readonly state: ModifiedFileEntryState; telemetryInfo: IModifiedEntryTelemetryInfo; } diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts index 49b0907a665..9e65f6630a2 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts @@ -91,6 +91,7 @@ suite('ChatEditingService', function () { } }); const insta = store.add(store.add(workbenchInstantiationService(undefined, store)).createChild(collection)); + store.add(insta.get(IEditorWorkerService) as TestWorkerService); const value = insta.get(IChatEditingService); assert.ok(value instanceof ChatEditingService); editingService = value; diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts index c2b24bcfaeb..7777341548b 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingSessionStorage.test.ts @@ -9,8 +9,6 @@ import { cloneAndChange } from '../../../../../base/common/objects.js'; import { URI } from '../../../../../base/common/uri.js'; import { generateUuid } from '../../../../../base/common/uuid.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { StringEdit } from '../../../../../editor/common/core/edits/stringEdit.js'; -import { OffsetRange } from '../../../../../editor/common/core/ranges/offsetRange.js'; import { FileService } from '../../../../../platform/files/common/fileService.js'; import { InMemoryFileSystemProvider } from '../../../../../platform/files/common/inMemoryFilesystemProvider.js'; import { NullLogService } from '../../../../../platform/log/common/log.js'; @@ -50,7 +48,7 @@ suite('ChatEditingSessionStorage', () => { return { stopId, entries: new ResourceMap([ - [resource, { resource, languageId: 'javascript', snapshotUri: ChatEditingSnapshotTextModelContentProvider.getSnapshotFileURI(sessionId, requestId, stopId, resource.path), original: `contents${before}}`, current: `contents${after}`, originalToCurrentEdit: StringEdit.replace(OffsetRange.ofLength(42), 'newtext'), state: ModifiedFileEntryState.Modified, telemetryInfo: { agentId: 'agentId', command: 'cmd', requestId: generateUuid(), result: undefined, sessionId } } satisfies ISnapshotEntry], + [resource, { resource, languageId: 'javascript', snapshotUri: ChatEditingSnapshotTextModelContentProvider.getSnapshotFileURI(sessionId, requestId, stopId, resource.path), original: `contents${before}}`, current: `contents${after}`, state: ModifiedFileEntryState.Modified, telemetryInfo: { agentId: 'agentId', command: 'cmd', requestId: generateUuid(), result: undefined, sessionId } } satisfies ISnapshotEntry], ]), }; } diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts index 1605df163d4..b7cb3635c48 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts @@ -224,6 +224,7 @@ suite('InlineChatController', function () { inlineChatSessionService = store.add(instaService.get(IInlineChatSessionService)); store.add(instaService.get(ILanguageModelsService) as LanguageModelsService); + store.add(instaService.get(IEditorWorkerService) as TestWorkerService); store.add(instaService.createInstance(ChatInputBoxContentProvider)); diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts index e9bbdebabd9..ac49a111cd3 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts @@ -155,6 +155,7 @@ suite('InlineChatSession', function () { }); + store.add(instaService.get(IEditorWorkerService) as TestWorkerService); model = store.add(instaService.get(IModelService).createModel('one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven', null)); editor = store.add(instantiateTestCodeEditor(instaService, model)); }); diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/testWorkerService.ts b/src/vs/workbench/contrib/inlineChat/test/browser/testWorkerService.ts index edfa6e50429..2a6ea9759da 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/testWorkerService.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/testWorkerService.ts @@ -14,21 +14,31 @@ import { LineRange } from '../../../../../editor/common/core/ranges/lineRange.js import { MovedText } from '../../../../../editor/common/diff/linesDiffComputer.js'; import { LineRangeMapping, DetailedLineRangeMapping, RangeMapping } from '../../../../../editor/common/diff/rangeMapping.js'; import { TextEdit } from '../../../../../editor/common/languages.js'; +import { disposableTimeout } from '../../../../../base/common/async.js'; +import { DisposableStore, IDisposable } from '../../../../../base/common/lifecycle.js'; -export class TestWorkerService extends mock() { +export class TestWorkerService extends mock() implements IDisposable { - private readonly _worker = new EditorWorker(); + private readonly _store = new DisposableStore(); + private readonly _worker = this._store.add(new EditorWorker()); constructor(@IModelService private readonly _modelService: IModelService) { super(); } + dispose(): void { + this._store.dispose(); + } override async computeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined, pretty?: boolean | undefined): Promise { return undefined; } override async computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise { + await new Promise(resolve => disposableTimeout(() => resolve(), 0, this._store)); + if (this._store.isDisposed) { + return null; + } const originalModel = this._modelService.getModel(original); const modifiedModel = this._modelService.getModel(modified); From cfa7c4d2eff738f23bcdcb83df91770126b2ca76 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Jun 2025 11:16:54 +0200 Subject: [PATCH 212/236] more API notes (#251215) * more API notes https://github.com/microsoft/vscode/issues/250007 * fix compile error --- .vscode/notebooks/api.github-issues | 2 +- .../vscode.proposed.chatProvider.d.ts | 96 +++++++++++++++++-- ...vscode.proposed.languageModelDataPart.d.ts | 1 + 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index cc9420281ed..ed5ae1cf8a2 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"May 2025\"" + "value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"June 2025\"" }, { "kind": 1, diff --git a/src/vscode-dts/vscode.proposed.chatProvider.d.ts b/src/vscode-dts/vscode.proposed.chatProvider.d.ts index 47eb21e54f9..3dfb05984ae 100644 --- a/src/vscode-dts/vscode.proposed.chatProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.chatProvider.d.ts @@ -14,7 +14,7 @@ declare module 'vscode' { // TODO@API name scheme - export interface LanguageModelChatResponseOptions { + export interface LanguageModelChatRequestHandleOptions { // initiator readonly extensionId: string; @@ -44,17 +44,99 @@ declare module 'vscode' { toolMode?: LanguageModelChatToolMode; } - export interface LanguageModelChatData { - // like ChatResponseProviderMetadata + // TODO@API names: LanguageModelChatMetadata, LanguageModelChatItem + export interface LanguageModelChatInformation { + + // TODO@API IMPLICT from package-json registration + // readonly vendor: string; + + readonly id: string; + + /** + * Human-readable name of the language model. + */ + readonly name: string; + /** + * Opaque family-name of the language model. Values might be `gpt-3.5-turbo`, `gpt4`, `phi2`, or `llama` + * but they are defined by extensions contributing languages and subject to change. + */ + readonly family: string; + + /** + * An optional, human-readable description of the language model. + */ + readonly description?: string; + + /** + * An optional, human-readable string representing the cost of using the language model. + */ + readonly cost?: string; + + /** + * Opaque version string of the model. This is defined by the extension contributing the language model + * and subject to change while the identifier is stable. + */ + readonly version: string; + + readonly maxInputTokens: number; + + readonly maxOutputTokens: number; + + /** + * When present, this gates the use of `requestLanguageModelAccess` behind an authorization flow where + * the user must approve of another extension accessing the models contributed by this extension. + * Additionally, the extension can provide a label that will be shown in the UI. + */ + auth?: true | { label: string }; + + // TODO@API maybe an enum, LanguageModelChatProviderPickerAvailability? + // TODO@API isPreselected proposed + readonly isDefault?: boolean; + + // TODO@API nuke + readonly isUserSelectable?: boolean; + + readonly capabilities?: { + + // TODO@API have mimeTypes that you support + readonly vision?: boolean; + + // TODO@API should be `boolean | number` so extensions can express how many tools they support + readonly toolCalling?: boolean | number; + + // TODO@API DO NOT SUPPORT THIS + // readonly agentMode?: boolean; + + // TODO@API support prompt TSX style messages, MAYBE leave it out for now + readonly promptTsx?: boolean; + }; + + /** + * Optional category to group models by in the model picker. + * The lower the order, the higher the category appears in the list. + * Has no effect if `isUserSelectable` is `false`. + * If not specified, the model will appear in the "Other Models" category. + */ + readonly category?: { label: string; order: number }; } - export interface LanguageModelChatProvider2 { + export interface LanguageModelChatProvider2 { - provideLanguageModelChatData(options: { force: boolean }, token: CancellationToken): ProviderResult; + // signals a change from the provider to the editor so that prepareLanguageModelChat is called again + onDidChange?: Event; - provideResponse(model: LanguageModelChatData, messages: Array, options: LanguageModelChatResponseOptions, progress: Progress, token: CancellationToken): Thenable; + // NOT cacheable (between reloads) + prepareLanguageModelChat(options: { silent: boolean }, token: CancellationToken): ProviderResult; - provideTokenCount(model: LanguageModelChatData, text: string | LanguageModelChatMessage | LanguageModelChatMessage2, token: CancellationToken): Thenable; + provideLanguageModelChatResponse(model: T, messages: Array, options: LanguageModelChatRequestHandleOptions, progress: Progress, token: CancellationToken): Thenable; + + provideTokenCount(model: T, text: string | LanguageModelChatMessage | LanguageModelChatMessage2, token: CancellationToken): Thenable; + } + + export namespace lm { + + // + // export function registerChatModelProvider(vendor: string, provider: LanguageModelChatProvider2): Disposable; } diff --git a/src/vscode-dts/vscode.proposed.languageModelDataPart.d.ts b/src/vscode-dts/vscode.proposed.languageModelDataPart.d.ts index 902ed64ec97..d2cd676400a 100644 --- a/src/vscode-dts/vscode.proposed.languageModelDataPart.d.ts +++ b/src/vscode-dts/vscode.proposed.languageModelDataPart.d.ts @@ -68,6 +68,7 @@ declare module 'vscode' { * @param data Binary image data * @param mimeType The MIME type of the image */ + // TODO@API just use string, no enum required static image(data: Uint8Array, mimeType: ChatImageMimeType): LanguageModelDataPart; static json(value: any, mime?: string): LanguageModelDataPart; From 2eed3660840296db310b05be2aa3629f1bb759a3 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 6 Jun 2025 15:43:49 +0200 Subject: [PATCH 213/236] Fixes https://github.com/microsoft/vscode-copilot/issues/10610 --- src/vs/editor/common/core/text/abstractText.ts | 4 ++++ .../defaultLinesDiffComputer/defaultLinesDiffComputer.ts | 5 ++++- .../contrib/mergeEditor/browser/model/diffComputer.ts | 6 +++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/core/text/abstractText.ts b/src/vs/editor/common/core/text/abstractText.ts index fe1d35213e6..bfdc1677e02 100644 --- a/src/vs/editor/common/core/text/abstractText.ts +++ b/src/vs/editor/common/core/text/abstractText.ts @@ -48,6 +48,10 @@ export abstract class AbstractText { const value = this.getValue(); return splitLines(value); } + + getLinesOfRange(range: LineRange): string[] { + return range.mapToLineArray(lineNumber => this.getLineAt(lineNumber)); + } } export class LineBasedText extends AbstractText { diff --git a/src/vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer.ts b/src/vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer.ts index cd07eae5b0a..0da7983fc6c 100644 --- a/src/vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer.ts +++ b/src/vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer.ts @@ -141,7 +141,10 @@ export class DefaultLinesDiffComputer implements ILinesDiffComputer { scanForWhitespaceChanges(originalLines.length - seq1LastStart); - const changes = lineRangeMappingFromRangeMappings(alignments, new ArrayText(originalLines), new ArrayText(modifiedLines)); + const original = new ArrayText(originalLines); + const modified = new ArrayText(modifiedLines); + + const changes = lineRangeMappingFromRangeMappings(alignments, original, modified); let moves: MovedText[] = []; if (options.computeMoves) { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts index e6a51aed0c0..9cb565cdd61 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts @@ -76,6 +76,10 @@ export class MergeDiffComputer implements IMergeDiffComputer { } assertFn(() => { + /* + // This does not hold (see https://github.com/microsoft/vscode-copilot/issues/10610) + // TODO@hediet the diff algorithm should just use compute a string edit that transforms the input to the output, nothing else + for (const c of changes) { const inputRange = c.inputRange; const outputRange = c.outputRange; @@ -105,7 +109,7 @@ export class MergeDiffComputer implements IMergeDiffComputer { return false; } } - } + }*/ return changes.length === 0 || (changes[0].inputRange.startLineNumber === changes[0].outputRange.startLineNumber && checkAdjacentItems(changes, From 9913e0238a3f8677129fbdcd65a3566c38f48705 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:41:33 +0200 Subject: [PATCH 214/236] GitHub - cleanup octokit auth (#251266) Refactor auth --- extensions/github/src/auth.ts | 78 ++++++++++++------- extensions/github/src/branchProtection.ts | 34 +++++--- extensions/github/src/extension.ts | 12 ++- .../github/src/historyItemDetailsProvider.ts | 21 ++--- 4 files changed, 93 insertions(+), 52 deletions(-) diff --git a/extensions/github/src/auth.ts b/extensions/github/src/auth.ts index d5487643823..56d68e287ee 100644 --- a/extensions/github/src/auth.ts +++ b/extensions/github/src/auth.ts @@ -3,12 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AuthenticationSession, authentication, window } from 'vscode'; +import { AuthenticationSession, EventEmitter, authentication, window } from 'vscode'; import { Agent, globalAgent } from 'https'; import { graphql } from '@octokit/graphql/types'; import { Octokit } from '@octokit/rest'; import { httpsOverHttp } from 'tunnel'; import { URL } from 'url'; +import { DisposableStore, sequentialize } from './util.js'; export class AuthenticationError extends Error { } @@ -57,35 +58,58 @@ export function getOctokit(): Promise { return _octokit; } -let _octokitGraphql: graphql | undefined; +export class OctokitService { + private _octokitGraphql: graphql | undefined; -export async function getOctokitGraphql(): Promise { - if (!_octokitGraphql) { - try { - const session = await authentication.getSession('github', scopes, { silent: true }); + private readonly _onDidChangeSessions = new EventEmitter(); + readonly onDidChangeSessions = this._onDidChangeSessions.event; - if (!session) { - throw new AuthenticationError('No GitHub authentication session available.'); + private readonly _disposables = new DisposableStore(); + + constructor() { + this._disposables.add(this._onDidChangeSessions); + this._disposables.add(authentication.onDidChangeSessions(e => { + if (e.provider.id === 'github') { + this._octokitGraphql = undefined; + this._onDidChangeSessions.fire(); } - - const token = session.accessToken; - const { graphql } = await import('@octokit/graphql'); - - _octokitGraphql = graphql.defaults({ - headers: { - authorization: `token ${token}` - }, - request: { - agent: getAgent() - } - }); - - return _octokitGraphql; - } catch (err) { - _octokitGraphql = undefined; - throw new AuthenticationError(err.message); - } + })); } - return _octokitGraphql; + @sequentialize + public async getOctokitGraphql(): Promise { + if (!this._octokitGraphql) { + try { + const session = await authentication.getSession('github', scopes, { silent: true }); + + if (!session) { + throw new AuthenticationError('No GitHub authentication session available.'); + } + + const token = session.accessToken; + const { graphql } = await import('@octokit/graphql'); + + this._octokitGraphql = graphql.defaults({ + headers: { + authorization: `token ${token}` + }, + request: { + agent: getAgent() + } + }); + + return this._octokitGraphql; + } catch (err) { + this._octokitGraphql = undefined; + throw new AuthenticationError(err.message); + } + } + + return this._octokitGraphql; + } + + dispose(): void { + this._octokitGraphql = undefined; + this._disposables.dispose(); + } } diff --git a/extensions/github/src/branchProtection.ts b/extensions/github/src/branchProtection.ts index 7b56f5aab40..5cd1f2f89fa 100644 --- a/extensions/github/src/branchProtection.ts +++ b/extensions/github/src/branchProtection.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { authentication, EventEmitter, LogOutputChannel, Memento, Uri, workspace } from 'vscode'; +import { EventEmitter, LogOutputChannel, Memento, Uri, workspace } from 'vscode'; import { Repository as GitHubRepository, RepositoryRuleset } from '@octokit/graphql-schema'; -import { AuthenticationError, getOctokitGraphql } from './auth.js'; +import { AuthenticationError, OctokitService } from './auth.js'; import { API, BranchProtection, BranchProtectionProvider, BranchProtectionRule, Repository } from './typings/git.js'; import { DisposableStore, getRepositoryFromUrl } from './util.js'; import { TelemetryReporter } from '@vscode/extension-telemetry'; @@ -61,7 +61,7 @@ export class GitHubBranchProtectionProviderManager { if (enabled) { for (const repository of this.gitAPI.repositories) { - this.providerDisposables.add(this.gitAPI.registerBranchProtectionProvider(repository.rootUri, new GitHubBranchProtectionProvider(repository, this.globalState, this.logger, this.telemetryReporter))); + this.providerDisposables.add(this.gitAPI.registerBranchProtectionProvider(repository.rootUri, new GitHubBranchProtectionProvider(repository, this.globalState, this.octokitService, this.logger, this.telemetryReporter))); } } else { this.providerDisposables.dispose(); @@ -73,11 +73,13 @@ export class GitHubBranchProtectionProviderManager { constructor( private readonly gitAPI: API, private readonly globalState: Memento, + private readonly octokitService: OctokitService, private readonly logger: LogOutputChannel, private readonly telemetryReporter: TelemetryReporter) { this.disposables.add(this.gitAPI.onDidOpenRepository(repository => { if (this._enabled) { - this.providerDisposables.add(gitAPI.registerBranchProtectionProvider(repository.rootUri, new GitHubBranchProtectionProvider(repository, this.globalState, this.logger, this.telemetryReporter))); + this.providerDisposables.add(gitAPI.registerBranchProtectionProvider(repository.rootUri, + new GitHubBranchProtectionProvider(repository, this.globalState, this.octokitService, this.logger, this.telemetryReporter))); } })); @@ -109,20 +111,24 @@ export class GitHubBranchProtectionProvider implements BranchProtectionProvider private branchProtection: BranchProtection[]; private readonly globalStateKey = `branchProtection:${this.repository.rootUri.toString()}`; + private readonly disposables = new DisposableStore(); + constructor( private readonly repository: Repository, private readonly globalState: Memento, + private readonly octokitService: OctokitService, private readonly logger: LogOutputChannel, - private readonly telemetryReporter: TelemetryReporter) { + private readonly telemetryReporter: TelemetryReporter + ) { + this.disposables.add(this._onDidChangeBranchProtection); + // Restore branch protection from global state this.branchProtection = this.globalState.get(this.globalStateKey, []); repository.status().then(() => { - authentication.onDidChangeSessions(e => { - if (e.provider.id === 'github') { - this.updateRepositoryBranchProtection(); - } - }); + this.disposables.add(this.octokitService.onDidChangeSessions(() => { + this.updateRepositoryBranchProtection(); + })); this.updateRepositoryBranchProtection(); }); } @@ -132,7 +138,7 @@ export class GitHubBranchProtectionProvider implements BranchProtectionProvider } private async getRepositoryDetails(owner: string, repo: string): Promise { - const graphql = await getOctokitGraphql(); + const graphql = await this.octokitService.getOctokitGraphql(); const { repository } = await graphql<{ repository: GitHubRepository }>(REPOSITORY_QUERY, { owner, repo }); return repository; @@ -142,7 +148,7 @@ export class GitHubBranchProtectionProvider implements BranchProtectionProvider const rulesets: RepositoryRuleset[] = []; let cursor: string | undefined = undefined; - const graphql = await getOctokitGraphql(); + const graphql = await this.octokitService.getOctokitGraphql(); while (true) { const { repository } = await graphql<{ repository: GitHubRepository }>(REPOSITORY_RULESETS_QUERY, { owner, repo, cursor }); @@ -241,4 +247,8 @@ export class GitHubBranchProtectionProvider implements BranchProtectionProvider return refName; } } + + dispose(): void { + this.disposables.dispose(); + } } diff --git a/extensions/github/src/extension.ts b/extensions/github/src/extension.ts index bf07a0b9278..17906c57d44 100644 --- a/extensions/github/src/extension.ts +++ b/extensions/github/src/extension.ts @@ -17,6 +17,7 @@ import { GitHubBranchProtectionProviderManager } from './branchProtection.js'; import { GitHubCanonicalUriProvider } from './canonicalUriProvider.js'; import { VscodeDevShareProvider } from './shareProviders.js'; import { GitHubSourceControlHistoryItemDetailsProvider } from './historyItemDetailsProvider.js'; +import { OctokitService } from './auth.js'; export function activate(context: ExtensionContext): void { const disposables: Disposable[] = []; @@ -35,8 +36,11 @@ export function activate(context: ExtensionContext): void { const telemetryReporter = new TelemetryReporter(aiKey); disposables.push(telemetryReporter); + const octokitService = new OctokitService(); + disposables.push(octokitService); + disposables.push(initializeGitBaseExtension()); - disposables.push(initializeGitExtension(context, telemetryReporter, logger)); + disposables.push(initializeGitExtension(context, octokitService, telemetryReporter, logger)); } function initializeGitBaseExtension(): Disposable { @@ -84,7 +88,7 @@ function setGitHubContext(gitAPI: API, disposables: DisposableStore) { } } -function initializeGitExtension(context: ExtensionContext, telemetryReporter: TelemetryReporter, logger: LogOutputChannel): Disposable { +function initializeGitExtension(context: ExtensionContext, octokitService: OctokitService, telemetryReporter: TelemetryReporter, logger: LogOutputChannel): Disposable { const disposables = new DisposableStore(); let gitExtension = extensions.getExtension('vscode.git'); @@ -98,10 +102,10 @@ function initializeGitExtension(context: ExtensionContext, telemetryReporter: Te disposables.add(registerCommands(gitAPI)); disposables.add(new GithubCredentialProviderManager(gitAPI)); - disposables.add(new GitHubBranchProtectionProviderManager(gitAPI, context.globalState, logger, telemetryReporter)); + disposables.add(new GitHubBranchProtectionProviderManager(gitAPI, context.globalState, octokitService, logger, telemetryReporter)); disposables.add(gitAPI.registerPushErrorHandler(new GithubPushErrorHandler(telemetryReporter))); disposables.add(gitAPI.registerRemoteSourcePublisher(new GithubRemoteSourcePublisher(gitAPI))); - disposables.add(gitAPI.registerSourceControlHistoryItemDetailsProvider(new GitHubSourceControlHistoryItemDetailsProvider(gitAPI, logger))); + disposables.add(gitAPI.registerSourceControlHistoryItemDetailsProvider(new GitHubSourceControlHistoryItemDetailsProvider(gitAPI, octokitService, logger))); disposables.add(new GitHubCanonicalUriProvider(gitAPI)); disposables.add(new VscodeDevShareProvider(gitAPI)); setGitHubContext(gitAPI, disposables); diff --git a/extensions/github/src/historyItemDetailsProvider.ts b/extensions/github/src/historyItemDetailsProvider.ts index 6d3a414036c..1a5d58a1c52 100644 --- a/extensions/github/src/historyItemDetailsProvider.ts +++ b/extensions/github/src/historyItemDetailsProvider.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { authentication, Command, l10n, LogOutputChannel, workspace } from 'vscode'; +import { Command, l10n, LogOutputChannel, workspace } from 'vscode'; import { Commit, Repository as GitHubRepository, Maybe } from '@octokit/graphql-schema'; import { API, AvatarQuery, AvatarQueryCommit, Repository, SourceControlHistoryItemDetailsProvider } from './typings/git.js'; import { DisposableStore, getRepositoryDefaultRemote, getRepositoryDefaultRemoteUrl, getRepositoryFromUrl, groupBy, sequentialize } from './util.js'; -import { AuthenticationError, getOctokitGraphql } from './auth.js'; +import { AuthenticationError, OctokitService } from './auth.js'; import { getAvatarLink } from './links.js'; const ISSUE_EXPRESSION = /(([A-Za-z0-9_.\-]+)\/([A-Za-z0-9_.\-]+))?(#|GH-)([1-9][0-9]*)($|\b)/g; @@ -82,13 +82,16 @@ export class GitHubSourceControlHistoryItemDetailsProvider implements SourceCont private readonly _store = new Map(); private readonly _disposables = new DisposableStore(); - constructor(private readonly _gitAPI: API, private readonly _logger: LogOutputChannel) { + constructor( + private readonly _gitAPI: API, + private readonly _octokitService: OctokitService, + private readonly _logger: LogOutputChannel + ) { this._disposables.add(this._gitAPI.onDidCloseRepository(repository => this._onDidCloseRepository(repository))); - this._disposables.add(authentication.onDidChangeSessions(e => { - if (e.provider.id === 'github') { - this._isUserAuthenticated = true; - } + this._disposables.add(this._octokitService.onDidChangeSessions(() => { + this._isUserAuthenticated = true; + this._store.clear(); })); this._disposables.add(workspace.onDidChangeConfiguration(e => { @@ -264,7 +267,7 @@ export class GitHubSourceControlHistoryItemDetailsProvider implements SourceCont this._logger.trace(`[GitHubSourceControlHistoryItemDetailsProvider][_loadAssignableUsers] Querying assignable user(s) for ${descriptor.owner}/${descriptor.repo}.`); try { - const graphql = await getOctokitGraphql(); + const graphql = await this._octokitService.getOctokitGraphql(); const { repository } = await graphql<{ repository: GitHubRepository }>(ASSIGNABLE_USERS_QUERY, descriptor); const users: GitHubUser[] = []; @@ -294,7 +297,7 @@ export class GitHubSourceControlHistoryItemDetailsProvider implements SourceCont this._logger.trace(`[GitHubSourceControlHistoryItemDetailsProvider][_getCommitAuthor] Querying commit author for ${descriptor.owner}/${descriptor.repo}/${commit}.`); try { - const graphql = await getOctokitGraphql(); + const graphql = await this._octokitService.getOctokitGraphql(); const { repository } = await graphql<{ repository: GitHubRepository }>(COMMIT_AUTHOR_QUERY, { ...descriptor, commit }); const commitAuthor = (repository.object as Commit).author; From 8b35fd3b888ecd9d183b372e42aa46395df2d9c4 Mon Sep 17 00:00:00 2001 From: lemurra_microsoft Date: Thu, 12 Jun 2025 12:33:22 +0100 Subject: [PATCH 215/236] update `sync` and `sync-ignored` icons --- .../browser/ui/codicons/codicon/codicon.ttf | Bin 86368 -> 86384 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf index 4c099bd92715d1d3f7ce0a43206438c07f390271..88916fe998c0c1da2849f7d4f4b9b84fef6be994 100644 GIT binary patch delta 465 zcmaE`i1ouF)(H+gAJ@!CXJF9GVPNF8ndoD}(lhmJ*u)lP!4(V)j6VwUi%SG`#pW_F znk|^P!+>RGxnC>R&Zqbzb$l>UT93HFY)bY9(sZYTwj#)a|I}s<)}Hs6W>r z&=Av5)9|j*sIjE+T;sbYou-JUO-&b?r?jxNENhi(O=_LTz{0@r|39P7<`PZ+NA+5a zd<=pNstlS84Cd-)Mskee=Hl$i>gM8lOiJQPdW`Dg=IYAq;^uNpM&{~l${=nwpR|p! z9HSVoDxWH^7^9Syfw-iW6r3+-Y$MGlB3}NG_u)%E0XZXCQC?M5UQtO+i9HgUk`RuZ zp_~98_lbwR^$!^sm>7V7QHznCL6|`U=nQdob)ao#=Hh&eAP2Ck+cToNi;Z2~j?oNa zx1lDlfPj$|#65X(DDHyDt%q1HCc-5lC2J@LbU*~qdZ?q=H6=h2(%X0NFs^U`01%^p Ad;kCd delta 457 zcmeyci1ooD)(H+g=GMnN7#K8j7#O*ACi>HnBxna0UYdu{#XM? zLr6nO!?Q-M#+=4ujnA4?ngW_uHJxbgY5vnPuT`uys&yIz3j@Rd|BO1DOEmo-)oU|y zFbFazGpI8#n5)|{$}x(Yi?b`Mn~Uo)vB@*C=`pFZtD75(v#ZN70|nXB`K4^l6d1+% z)cMu<#Tlh^3?2BTtc-x#_|^F|_{Eqc)b%Fu-sgSJE66NkEHB2VuE8fRp(Vk%nU{}I z)=(CxQG-uRTwR=bAMXV|2BvxjAYjyH Date: Thu, 12 Jun 2025 17:18:03 +0200 Subject: [PATCH 216/236] ignore prompt files for implicit context --- .../attachments/implicitContextAttachment.ts | 13 +- .../chat/browser/chatAttachmentResolve.ts | 9 +- .../chat/browser/chatAttachmentWidgets.ts | 3 +- .../chatAttachmentsContentPart.ts | 6 +- .../contrib/chat/browser/chatInputPart.ts | 19 +-- .../browser/contrib/chatImplicitContext.ts | 122 ++---------------- .../contrib/chat/browser/media/chat.css | 57 +------- .../chat/common/chatVariableEntries.ts | 1 - .../chat/common/promptSyntax/promptTypes.ts | 19 ++- 9 files changed, 52 insertions(+), 197 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts b/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts index c4e5e14c583..884b4e2aee2 100644 --- a/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts +++ b/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.ts @@ -6,12 +6,10 @@ import * as dom from '../../../../../base/browser/dom.js'; import { StandardKeyboardEvent } from '../../../../../base/browser/keyboardEvent.js'; import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js'; -import { Codicon } from '../../../../../base/common/codicons.js'; import { KeyCode } from '../../../../../base/common/keyCodes.js'; import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../../base/common/network.js'; import { basename, dirname } from '../../../../../base/common/resources.js'; -import { ThemeIcon } from '../../../../../base/common/themables.js'; import { URI } from '../../../../../base/common/uri.js'; import { ILanguageService } from '../../../../../editor/common/languages/language.js'; import { IModelService } from '../../../../../editor/common/services/model.js'; @@ -61,9 +59,7 @@ export class ImplicitContextAttachmentWidget extends Disposable { const file = URI.isUri(this.attachment.value) ? this.attachment.value : this.attachment.value!.uri; const range = undefined; - const attachmentTypeName = (this.attachment.isPromptFile === false) - ? file.scheme === Schemas.vscodeNotebookCell ? localize('cell.lowercase', "cell") : localize('file.lowercase', "file") - : localize('prompt.lowercase', "prompt"); + const attachmentTypeName = file.scheme === Schemas.vscodeNotebookCell ? localize('cell.lowercase', "cell") : localize('file.lowercase', "file"); const fileBasename = basename(file); const fileDirname = dirname(file); @@ -74,16 +70,11 @@ export class ImplicitContextAttachmentWidget extends Disposable { const currentFile = localize('openEditor', "Suggested context (current file)"); const title = `${currentFile}\n${uriLabel}`; - const icon = this.attachment.isPromptFile - ? ThemeIcon.fromId(Codicon.bookmark.id) - : undefined; - label.setFile(file, { fileKind: FileKind.FILE, hidePath: true, range, - title, - icon, + title }); this.domNode.ariaLabel = ariaLabel; this.domNode.tabIndex = 0; diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts index 934e20d3c5e..ff3de42cd29 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentResolve.ts @@ -25,7 +25,8 @@ import { createNotebookOutputVariableEntry, NOTEBOOK_CELL_OUTPUT_MIME_TYPE_LIST_ import { getOutputViewModelFromId } from '../../notebook/browser/controller/cellOutputActions.js'; import { getNotebookEditorFromEditorPane } from '../../notebook/browser/notebookBrowser.js'; import { CHAT_ATTACHABLE_IMAGE_MIME_TYPES, getAttachableImageExtension } from '../common/chatModel.js'; -import { IChatRequestVariableEntry, OmittedState, IDiagnosticVariableEntry, IDiagnosticVariableEntryFilterData, ISymbolVariableEntry } from '../common/chatVariableEntries.js'; +import { IChatRequestVariableEntry, OmittedState, IDiagnosticVariableEntry, IDiagnosticVariableEntryFilterData, ISymbolVariableEntry, toPromptFileVariableEntry } from '../common/chatVariableEntries.js'; +import { getPromptsTypeForLanguageId } from '../common/promptSyntax/promptTypes.js'; import { imageToHash } from './chatPasteProviders.js'; import { resizeImage } from './imageUtils.js'; @@ -83,8 +84,11 @@ export async function resolveResourceAttachContext(resource: URI, isDirectory: b let omittedState = OmittedState.NotOmitted; if (!isDirectory) { + + let languageId: string | undefined; try { const createdModel = await textModelService.createModelReference(resource); + languageId = createdModel.object.getLanguageId(); createdModel.dispose(); } catch { omittedState = OmittedState.Full; @@ -93,6 +97,9 @@ export async function resolveResourceAttachContext(resource: URI, isDirectory: b if (/\.(svg)$/i.test(resource.path)) { omittedState = OmittedState.Full; } + if (languageId && getPromptsTypeForLanguageId(languageId)) { + return toPromptFileVariableEntry(resource, true); + } } return { diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts index 6e1e378ceaa..ffda839a0a2 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentWidgets.ts @@ -482,7 +482,6 @@ export class PromptFileAttachmentWidget extends AbstractChatAttachmentWidget { constructor( resource: URI, attachment: IChatRequestVariableEntry, - correspondingContentReference: IChatContentReference | undefined, currentLanguageModel: ILanguageModelChatMetadataAndIdentifier | undefined, options: { shouldFocusClearButton: boolean; supportsDeletion: boolean }, container: HTMLElement, @@ -497,7 +496,7 @@ export class PromptFileAttachmentWidget extends AbstractChatAttachmentWidget { super(attachment, options, container, contextResourceLabels, hoverDelegate, currentLanguageModel, commandService, openerService); - this.hintElement = dom.append(this.element, dom.$('span.chat-implicit-hint')); + this.hintElement = dom.append(this.element, dom.$('span.prompt-type')); this.updateLabel(resource); diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts index 3482a2296c2..17f3494cd2f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts @@ -12,9 +12,9 @@ import { URI } from '../../../../../base/common/uri.js'; import { Range } from '../../../../../editor/common/core/range.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { ResourceLabels } from '../../../../browser/labels.js'; -import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isSCMHistoryItemVariableEntry, OmittedState } from '../../common/chatVariableEntries.js'; +import { IChatRequestVariableEntry, isElementVariableEntry, isImageVariableEntry, isNotebookOutputVariableEntry, isPasteVariableEntry, isPromptFileVariableEntry, isSCMHistoryItemVariableEntry, OmittedState } from '../../common/chatVariableEntries.js'; import { ChatResponseReferencePartStatusKind, IChatContentReference } from '../../common/chatService.js'; -import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../chatAttachmentWidgets.js'; +import { DefaultChatAttachmentWidget, ElementChatAttachmentWidget, FileAttachmentWidget, ImageAttachmentWidget, NotebookCellOutputChatAttachmentWidget, PasteAttachmentWidget, PromptFileAttachmentWidget, SCMHistoryItemAttachmentWidget, ToolSetOrToolItemAttachmentWidget } from '../chatAttachmentWidgets.js'; export class ChatAttachmentsContentPart extends Disposable { private readonly attachedContextDisposables = this._register(new DisposableStore()); @@ -59,6 +59,8 @@ export class ChatAttachmentsContentPart extends Disposable { } else if (isImageVariableEntry(attachment)) { attachment.omittedState = isAttachmentPartialOrOmitted ? OmittedState.Full : attachment.omittedState; widget = this.instantiationService.createInstance(ImageAttachmentWidget, resource, attachment, undefined, { shouldFocusClearButton: false, supportsDeletion: false }, container, this._contextResourceLabels, hoverDelegate); + } else if (resource && isPromptFileVariableEntry(attachment)) { + widget = this.instantiationService.createInstance(PromptFileAttachmentWidget, resource, attachment, undefined, { shouldFocusClearButton: false, supportsDeletion: false }, container, this._contextResourceLabels, hoverDelegate); } else if (resource && (attachment.kind === 'file' || attachment.kind === 'directory')) { widget = this.instantiationService.createInstance(FileAttachmentWidget, resource, range, attachment, correspondingContentReference, undefined, { shouldFocusClearButton: false, supportsDeletion: false }, container, this._contextResourceLabels, hoverDelegate); } else if (isPasteVariableEntry(attachment)) { diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 353bf4d9b8c..5b35510a14f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -203,16 +203,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge */ get hasPromptFileAttachments(): boolean { // if prompt attached explicitly as a "prompt" attachment - if (this._attachmentModel.hasPromptFiles(PROMPT_LANGUAGE_ID)) { - return true; - } - - if (this.implicitContext === undefined) { - return false; - } - - // if prompt attached as an implicit "current file" context - return (this.implicitContext.isPromptFile && this.implicitContext.enabled); + return this._attachmentModel.hasPromptFiles(PROMPT_LANGUAGE_ID); } private _indexOfLastAttachedContextDeletedWithKeyboard: number; @@ -459,12 +450,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this._hasFileAttachmentContextKey = ChatContextKeys.hasFileAttachments.bindTo(contextKeyService); - // trigger re-layout of chat input when number of instruction attachment changes - // this._register(this._attachmentModel.promptInstructions.onUpdate(() => { - // this._handleAttachedContextChange(); - // this._onDidChangeHeight.fire(); - // })); - this.initSelectedModel(); this._register(this.onDidChangeCurrentChatMode(() => this.accessibilityService.alert(this._currentMode.kind))); @@ -1299,7 +1284,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } else if (resource && isNotebookOutputVariableEntry(attachment)) { attachmentWidget = this.instantiationService.createInstance(NotebookCellOutputChatAttachmentWidget, resource, attachment, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); } else if (resource && isPromptFileVariableEntry(attachment)) { - attachmentWidget = this.instantiationService.createInstance(PromptFileAttachmentWidget, resource, attachment, undefined, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); + attachmentWidget = this.instantiationService.createInstance(PromptFileAttachmentWidget, resource, attachment, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); } else if (resource && (attachment.kind === 'file' || attachment.kind === 'directory')) { attachmentWidget = this.instantiationService.createInstance(FileAttachmentWidget, resource, range, attachment, undefined, this._currentLanguageModel, options, container, this._contextResourceLabels, hoverDelegate); } else if (isImageVariableEntry(attachment)) { diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts index 7f3d50eb1ce..6ede7942f8f 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts @@ -13,20 +13,17 @@ import { URI } from '../../../../../base/common/uri.js'; import { getCodeEditor, ICodeEditor } from '../../../../../editor/browser/editorBrowser.js'; import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; import { Location } from '../../../../../editor/common/languages.js'; -import { IModelService } from '../../../../../editor/common/services/model.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; -import { ILogService } from '../../../../../platform/log/common/log.js'; import { IWorkbenchContribution } from '../../../../common/contributions.js'; import { EditorsOrder } from '../../../../common/editor.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { getNotebookEditorFromEditorPane, INotebookEditor } from '../../../notebook/browser/notebookBrowser.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { IChatRequestImplicitVariableEntry, IChatRequestVariableEntry, toPromptFileVariableEntry } from '../../common/chatVariableEntries.js'; +import { IChatRequestImplicitVariableEntry, IChatRequestVariableEntry } from '../../common/chatVariableEntries.js'; import { IChatService } from '../../common/chatService.js'; import { ChatAgentLocation } from '../../common/constants.js'; import { ILanguageModelIgnoredFilesService } from '../../common/ignoredFiles.js'; -import { PROMPT_LANGUAGE_ID } from '../../common/promptSyntax/promptTypes.js'; -import { IPromptsService, TSharedPrompt } from '../../common/promptSyntax/service/promptsService.js'; +import { getPromptsTypeForLanguageId } from '../../common/promptSyntax/promptTypes.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; export class ChatImplicitContextContribution extends Disposable implements IWorkbenchContribution { @@ -155,6 +152,7 @@ export class ChatImplicitContextContribution extends Disposable implements IWork let languageId: string | undefined; if (model) { newValue = model.uri; + languageId = model.getLanguageId(); } const notebookEditor = this.findActiveNotebookEditor(); @@ -174,6 +172,8 @@ export class ChatImplicitContextContribution extends Disposable implements IWork return; } + const isPromptFile = languageId && getPromptsTypeForLanguageId(languageId) !== undefined; + const widgets = updateWidget ? [updateWidget] : [...this.chatWidgetService.getWidgetsByLocations(ChatAgentLocation.Panel), ...this.chatWidgetService.getWidgetsByLocations(ChatAgentLocation.Editor)]; for (const widget of widgets) { if (!widget.input.implicitContext) { @@ -181,11 +181,9 @@ export class ChatImplicitContextContribution extends Disposable implements IWork } const setting = this._implicitContextEnablement[widget.location]; const isFirstInteraction = widget.viewModel?.getItems().length === 0; - if (setting === 'first' && !isFirstInteraction) { - widget.input.implicitContext.setValue(undefined, false, undefined); - } else if (setting === 'always' || setting === 'first' && isFirstInteraction) { + if ((setting === 'always' || setting === 'first' && isFirstInteraction) && !isPromptFile) { // disable implicit context for prompt files widget.input.implicitContext.setValue(newValue, isSelection, languageId); - } else if (setting === 'never') { + } else { widget.input.implicitContext.setValue(undefined, false, undefined); } } @@ -193,18 +191,8 @@ export class ChatImplicitContextContribution extends Disposable implements IWork } export class ChatImplicitContext extends Disposable implements IChatRequestImplicitVariableEntry { - /** - * If the implicit context references a prompt file, this field - * holds a reference to an associated prompt parser instance. - */ - private prompt: TSharedPrompt | undefined; get id() { - if (this.prompt !== undefined) { - const variable = toPromptFileVariableEntry(this.prompt.uri, true); - return variable.id; - } - if (URI.isUri(this.value)) { return 'vscode.implicit.file'; } else if (this.value) { @@ -219,12 +207,6 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli } get name(): string { - if (this.prompt !== undefined) { - const variable = toPromptFileVariableEntry(this.prompt.uri, true); - - return variable.name; - } - if (URI.isUri(this.value)) { return `file:${basename(this.value)}`; } else if (this.value) { @@ -237,12 +219,6 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli readonly kind = 'implicit'; get modelDescription(): string { - if (this.prompt !== undefined) { - const variable = toPromptFileVariableEntry(this.prompt.uri, true); - - return variable.modelDescription; - } - if (URI.isUri(this.value)) { return `User's active file`; } else if (this._isSelection) { @@ -277,90 +253,20 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli this._onDidChangeValue.fire(); } - constructor( - @IPromptsService private readonly promptsService: IPromptsService, - @IModelService private readonly modelService: IModelService, - @ILogService private readonly logService: ILogService, - ) { - super(); - } - setValue(value: Location | URI | undefined, isSelection: boolean, languageId?: string): void { this._value = value; this._isSelection = isSelection; - - // remove and dispose existent prompt parser instance - this.removePrompt(); - // if language ID is a 'prompt' language, create a prompt parser instance - if (value && (languageId === PROMPT_LANGUAGE_ID)) { - this.addPrompt(value); - } this._onDidChangeValue.fire(); } public async toBaseEntries(): Promise { - // chat variable for non-prompt file attachment - if (this.prompt === undefined) { - return [{ - kind: 'file', - id: this.id, - name: this.name, - value: this.value, - modelDescription: this.modelDescription, - }]; - - } - - // prompt can have any number of nested references, hence - // collect all of valid ones and return the entire list - await this.prompt.allSettled(); - return [ - // add all valid child references in the prompt - ...this.prompt.allValidReferences.map((link) => { - return toPromptFileVariableEntry(link.uri, false); - }), - // and then the root prompt reference itself - toPromptFileVariableEntry(this.prompt.uri, true) - ]; + return [{ + kind: 'file', + id: this.id, + name: this.name, + value: this.value, + modelDescription: this.modelDescription, + }]; } - /** - * Whether the implicit context references a prompt file. - */ - public get isPromptFile() { - return (this.prompt !== undefined); - } - - /** - * Add prompt parser instance for the provided value. - */ - private addPrompt( - value: URI | Location, - ): void { - const uri = URI.isUri(value) - ? value - : value.uri; - - const model = this.modelService.getModel(uri); - const modelExists = (model !== null); - if ((modelExists === false) || model.isDisposed()) { - return this.logService.warn( - `cannot create prompt parser instance for ${uri.path} (model exists: ${modelExists})`, - ); - } - - this.prompt = this.promptsService.getSyntaxParserFor(model); - } - - /** - * Remove and dispose prompt parser instance. - */ - private removePrompt(): void { - delete this.prompt; - } - - public override dispose(): void { - this.removePrompt(); - super.dispose(); - } } diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 62b35fbac51..a240ca48262 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1121,66 +1121,17 @@ have to be updated for changes to the rules above, or to support more deeply nes /** * Styles for the `reusable prompts` attachment widget. */ -.chat-attached-context .chat-prompt-attachment { - display: flex; - gap: 4px; -} -.chat-attached-context .chat-prompt-attachment .codicon { - color: inherit; - text-decoration: none; -} -.chat-attached-context-attachment .chat-implicit-hint { +.chat-attached-context-attachment .prompt-type { opacity: 0.7; font-size: .9em; - margin-top: -0.5px; + margin-left: 0.5px; } -.chat-attached-context .chat-prompt-attachment.warning { +.chat-attached-context-attachment.warning { color: var(--vscode-notificationsWarningIcon-foreground); } -.chat-attached-context .chat-prompt-attachment.error { +.chat-attached-context-attachment.error { color: var(--vscode-notificationsErrorIcon-foreground); } -.chat-attached-context .chat-prompt-attachment.disabled { - border-style: dashed; - opacity: 0.75; -} -.chat-attached-context .chat-prompt-attachment:focus .monaco-button { - border-color: var(--vscode-focusBorder); -} -.chat-attached-context .chat-prompt-attachment .monaco-icon-label-container { - margin-top: -0.1em; -} -.chat-attached-context .chat-prompt-attachment.warning.implicit { - border: 1px solid currentColor; -} -.chat-attached-context .chat-prompt-attachment.implicit .monaco-button { - padding-left: 2px; - padding-right: 2px; -} -/* - * If in one of the non-normal states, make sure the `main icon` of - * the component has the same color as the component itself - */ -.chat-attached-context .chat-prompt-attachment.error .monaco-icon-label::before, -.chat-attached-context .chat-prompt-attachment.warning .monaco-icon-label::before, -.chat-attached-context .chat-prompt-attachment.disabled .monaco-icon-label::before { - color: inherit; -} -.chat-attached-context .chat-prompt-attachment.disabled .monaco-icon-label::before { - font-style: italic; -} -.chat-attached-context .chat-prompt-attachment.disabled:hover { - opacity: 1; -} -.chat-attached-context .chat-prompt-attachment.disabled .chat-implicit-hint, -.chat-attached-context .chat-prompt-attachment.disabled .label-name { - font-style: italic; - text-decoration: line-through; -} -.chat-attached-context .chat-prompt-attachment.disabled:focus { - outline: none; - border-color: var(--vscode-focusBorder); -} .chat-attached-context-attachment .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-suffix-container > .label-suffix { color: var(--vscode-peekViewTitleDescription-foreground); diff --git a/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts b/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts index 7176b07846d..530a3530850 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariableEntries.ts @@ -67,7 +67,6 @@ export interface IChatRequestImplicitVariableEntry extends IBaseChatRequestVaria readonly isFile: true; readonly value: URI | Location | undefined; readonly isSelection: boolean; - readonly isPromptFile: boolean; readonly enabled: boolean; } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts index 3bfee9a5261..a1f2f9c8569 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts @@ -46,10 +46,25 @@ export function getLanguageIdForPromptsType(type: PromptsType): string { default: throw new Error(`Unknown prompt type: ${type}`); } -}/** +} + +export function getPromptsTypeForLanguageId(languageId: string): PromptsType | undefined { + switch (languageId) { + case PROMPT_LANGUAGE_ID: + return PromptsType.prompt; + case INSTRUCTIONS_LANGUAGE_ID: + return PromptsType.instructions; + case MODE_LANGUAGE_ID: + return PromptsType.mode; + default: + return undefined; + } +} + + +/** * What the prompt is used for. */ - export enum PromptsType { instructions = 'instructions', prompt = 'prompt', From e680d2347c1844c109e4b1e5b439004ad825d8ab Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 12 Jun 2025 08:43:31 -0700 Subject: [PATCH 217/236] mcp: avoid spamming invalid streamable http GET handlers (#251288) --- src/vs/workbench/api/common/extHostMcp.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostMcp.ts b/src/vs/workbench/api/common/extHostMcp.ts index d81edad5172..4f8b7e44edd 100644 --- a/src/vs/workbench/api/common/extHostMcp.ts +++ b/src/vs/workbench/api/common/extHostMcp.ts @@ -517,7 +517,11 @@ class McpHTTPHandle extends Disposable { return; } - retry = 0; + // Only reset the retry counter if we definitely get an event stream to avoid + // spamming servers that (incorrectly) don't return one from this endpoint. + if (res.headers.get('content-type')?.toLowerCase().includes('text/event-stream')) { + retry = 0; + } const parser = new SSEParser(event => { if (event.type === 'message') { From 89ba12c3b56e219d7dbad17cb117d0c494f86b43 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Jun 2025 17:47:19 +0200 Subject: [PATCH 218/236] simplify dynamic variables, no more unused chat file reference fyi @aeschli (#251273) --- .../browser/contrib/chatDynamicVariables.ts | 42 ++++--------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts index 476653ffe4f..b8319a31247 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts @@ -12,28 +12,23 @@ import { IDecorationOptions } from '../../../../../editor/common/editorCommon.js import { Command, isLocation } from '../../../../../editor/common/languages.js'; import { Action2, registerAction2 } from '../../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; -import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; -import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; +import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; import { IChatRequestVariableValue, IDynamicVariable } from '../../common/chatVariables.js'; -import { PromptsConfig } from '../../common/promptSyntax/config/config.js'; import { IChatWidget } from '../chat.js'; import { IChatWidgetContrib } from '../chatWidget.js'; import { ChatFileReference } from './chatDynamicVariables/chatFileReference.js'; export const dynamicVariableDecorationType = 'chat-dynamic-variable'; -/** - * Type of dynamic variables. Can be either a file reference or - * another dynamic variable (e.g., a `#sym`, `#kb`, etc.). - */ -type TDynamicVariable = IDynamicVariable | ChatFileReference; + export class ChatDynamicVariableModel extends Disposable implements IChatWidgetContrib { public static readonly ID = 'chatDynamicVariableModel'; - private _variables: TDynamicVariable[] = []; - get variables(): ReadonlyArray { + private _variables: IDynamicVariable[] = []; + + get variables(): ReadonlyArray { return [...this._variables]; } @@ -46,18 +41,16 @@ export class ChatDynamicVariableModel extends Disposable implements IChatWidgetC constructor( private readonly widget: IChatWidget, @ILabelService private readonly labelService: ILabelService, - @IConfigurationService private readonly configService: IConfigurationService, - @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); this._register(widget.inputEditor.onDidChangeModelContent(e => { - const removed: TDynamicVariable[] = []; + const removed: IDynamicVariable[] = []; let didChange = false; // Don't mutate entries in _variables, since they will be returned from the getter - this._variables = coalesce(this._variables.map((ref, idx): TDynamicVariable | null => { + this._variables = coalesce(this._variables.map((ref, idx): IDynamicVariable | null => { const model = widget.inputEditor.getModel(); if (!model) { @@ -115,7 +108,7 @@ export class ChatDynamicVariableModel extends Disposable implements IChatWidgetC getInputState(): any { return this.variables - .map((variable: TDynamicVariable) => { + .map((variable: IDynamicVariable) => { // return underlying `IDynamicVariable` object for file references if (variable instanceof ChatFileReference) { return variable.reference; @@ -143,26 +136,9 @@ export class ChatDynamicVariableModel extends Disposable implements IChatWidgetC } addReference(ref: IDynamicVariable): void { - // use `ChatFileReference` for file references and `IDynamicVariable` for other variables - const promptSnippetsEnabled = PromptsConfig.enabled(this.configService); - const variable = (ref.id === 'vscode.file' && promptSnippetsEnabled) - ? this.instantiationService.createInstance(ChatFileReference, ref) - : ref; - - this._variables.push(variable); + this._variables.push(ref); this.updateDecorations(); this.widget.refreshParsedInput(); - - // if the `prompt snippets` feature is enabled, and file is a `prompt snippet`, - // start resolving nested file references immediately and subscribe to updates - if (variable instanceof ChatFileReference && variable.isPromptFile) { - // subscribe to variable changes - variable.onUpdate(() => { - this.updateDecorations(); - }); - // start resolving the file references - variable.start(); - } } private updateDecorations(): void { From c00b75d57bfca0433083c2ce09c1f86e086b7368 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Jun 2025 18:00:44 +0200 Subject: [PATCH 219/236] also use `Y` and `N` based keybindings for inline chat 2 (#251294) --- .../contrib/inlineChat/browser/inlineChatActions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts index 86c3252e16d..58d7cc83901 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts @@ -625,10 +625,10 @@ class KeepOrUndoSessionAction extends AbstractInline2ChatAction { icon: _keep ? Codicon.check : Codicon.discard, precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE, ctxHasRequestInProgress.negate()), keybinding: [{ - weight: KeybindingWeight.WorkbenchContrib, + weight: KeybindingWeight.WorkbenchContrib + 10, // win over new-window-action primary: _keep - ? KeyMod.CtrlCmd | KeyCode.Enter - : KeyMod.CtrlCmd | KeyCode.Backspace + ? KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyY + : KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyN }], menu: [{ id: MENU_INLINE_CHAT_WIDGET_STATUS, From 0ab638ea0f17ac196b28c815c9246bc607e2e646 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Thu, 12 Jun 2025 09:57:26 -0700 Subject: [PATCH 220/236] fix: try always rendering scrollbar in chat editing file list (#232768) Co-authored-by: Justin Chen <54879025+justschen@users.noreply.github.com> --- .../chat/browser/chatContentParts/chatReferencesContentPart.ts | 3 +++ src/vs/workbench/contrib/chat/browser/chatInputPart.ts | 3 ++- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts index 83ec99a7af8..c546cc5c2b3 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts @@ -5,6 +5,7 @@ import * as dom from '../../../../../base/browser/dom.js'; import { IListRenderer, IListVirtualDelegate } from '../../../../../base/browser/ui/list/list.js'; +import { IListOptions } from '../../../../../base/browser/ui/list/listWidget.js'; import { coalesce } from '../../../../../base/common/arrays.js'; import { Codicon } from '../../../../../base/common/codicons.js'; import { Event } from '../../../../../base/common/event.js'; @@ -184,6 +185,7 @@ export class CollapsibleListPool extends Disposable { constructor( private _onDidChangeVisibility: Event, private readonly menuId: MenuId | undefined, + private readonly listOptions: IListOptions | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @IThemeService private readonly themeService: IThemeService, @ILabelService private readonly labelService: ILabelService, @@ -205,6 +207,7 @@ export class CollapsibleListPool extends Disposable { new CollapsibleListDelegate(), [this.instantiationService.createInstance(CollapsibleListRenderer, resourceLabels, this.menuId)], { + ...this.listOptions, alwaysConsumeMouseWheel: false, accessibilityProvider: { getAriaLabel: (element: IChatCollapsibleListItem) => { diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 5b35510a14f..8d2040ae1fe 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -24,6 +24,7 @@ import { Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposab import { ResourceSet } from '../../../../base/common/map.js'; import { observableFromEvent } from '../../../../base/common/observable.js'; import { isMacintosh } from '../../../../base/common/platform.js'; +import { ScrollbarVisibility } from '../../../../base/common/scrollable.js'; import { isEqual } from '../../../../base/common/resources.js'; import { assertType } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; @@ -446,7 +447,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } })); - this._chatEditsListPool = this._register(this.instantiationService.createInstance(CollapsibleListPool, this._onDidChangeVisibility.event, MenuId.ChatEditingWidgetModifiedFilesToolbar)); + this._chatEditsListPool = this._register(this.instantiationService.createInstance(CollapsibleListPool, this._onDidChangeVisibility.event, MenuId.ChatEditingWidgetModifiedFilesToolbar, { verticalScrollMode: ScrollbarVisibility.Visible })); this._hasFileAttachmentContextKey = ChatContextKeys.hasFileAttachments.bindTo(contextKeyService); diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 6ce39786729..9002a97a38c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -187,7 +187,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer Date: Thu, 12 Jun 2025 20:52:23 +0200 Subject: [PATCH 221/236] move prompt file parser usages to IPromptsService (#251298) --- .../chat/browser/chatAttachmentModel.ts | 2 +- .../chatPromptAttachmentModel.ts | 117 ------------------ ...Collection.ts => chatPromptAttachments.ts} | 80 ++++++------ .../promptToolsCodeLensProvider.ts | 2 +- .../contrib/chat/common/chatModes.ts | 3 +- .../promptContentsProviderBase.ts | 4 +- .../promptSyntax/contentProviders/types.ts | 3 +- .../languageProviders/promptLinkProvider.ts | 2 +- .../promptPathAutocompletion.ts | 2 +- .../promptSyntax/parsers/basePromptParser.ts | 5 +- .../promptSyntax/service/promptsService.ts | 29 +++-- .../service/promptsServiceImpl.ts | 26 +++- .../chat/test/common/mockPromptsService.ts | 8 +- 13 files changed, 95 insertions(+), 188 deletions(-) delete mode 100644 src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts rename src/vs/workbench/contrib/chat/browser/chatAttachmentModel/{chatPromptAttachmentsCollection.ts => chatPromptAttachments.ts} (68%) diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts index 1533fcca6cd..ec2a4e021c6 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts @@ -10,7 +10,7 @@ import { IRange } from '../../../../editor/common/core/range.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { IChatRequestFileEntry, IChatRequestVariableEntry, isPromptFileVariableEntry, toPromptFileVariableEntry } from '../common/chatVariableEntries.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; -import { ChatPromptAttachmentsCollection } from './chatAttachmentModel/chatPromptAttachmentsCollection.js'; +import { ChatPromptAttachmentsCollection } from './chatAttachmentModel/chatPromptAttachments.js'; import { IFileService } from '../../../../platform/files/common/files.js'; import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { ISharedWebContentExtractorService } from '../../../../platform/webContentExtractor/common/webContentExtractor.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts deleted file mode 100644 index b88ab8a540a..00000000000 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentModel.ts +++ /dev/null @@ -1,117 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { URI } from '../../../../../base/common/uri.js'; -import { PromptParser } from '../../common/promptSyntax/parsers/promptParser.js'; -import { BasePromptParser } from '../../common/promptSyntax/parsers/basePromptParser.js'; -import { IPromptContentsProvider } from '../../common/promptSyntax/contentProviders/types.js'; -import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; -import { Disposable } from '../../../../../base/common/lifecycle.js'; - -/** - * Type for a generic prompt parser object. - */ -type TPromptParser = BasePromptParser; - -/** - * Model for a single chat prompt instructions attachment. - */ -export class ChatPromptAttachmentModel extends Disposable { - /** - * Private reference of the underlying prompt instructions - * reference instance. - */ - private readonly _reference: TPromptParser; - - /** - * Get the prompt instructions reference instance. - */ - public get reference(): TPromptParser { - return this._reference; - } - - /** - * Get `URI` for the main reference and `URI`s of all valid child - * references it may contain, including reference of this model itself. - */ - public get references(): readonly URI[] { - const { reference } = this; - const { errorCondition } = reference; - - // return no references if the attachment is disabled - // or if this object itself has an error - if (errorCondition) { - return []; - } - - // otherwise return `URI` for the main reference and - // all valid child `URI` references it may contain - return [ - ...reference.allValidReferences.map(ref => ref.uri), - reference.uri, - ]; - } - - /** - * Get list of all tools associated with the prompt. - * - * Note! This property returns pont-in-time state of the tools metadata - * and does not take into account if the prompt or its nested child - * references are still being resolved. Please use the {@link settled} - * or {@link allSettled} properties if you need to retrieve the final - * list of the tools available. - */ - public get toolsMetadata(): readonly string[] | null { - return this.reference.allToolsMetadata; - } - - /** - * Promise that resolves when the prompt is fully parsed, - * including all its possible nested child references. - */ - public get allSettled(): Promise { - return this.reference.allSettled(); - } - - /** - * Get the top-level error of the prompt instructions - * reference, if any. - */ - public get topError() { - return this.reference.topError; - } - - - constructor( - public readonly uri: URI, - private readonly _onUpdate: () => void, - @IInstantiationService private readonly instantiationService: IInstantiationService, - ) { - super(); - - this._reference = this._register( - this.instantiationService.createInstance( - PromptParser, - this.uri, - // in this case we know that the attached file must have been a - // prompt file, hence we pass the `allowNonPromptFiles` option - // to the provider to allow for non-prompt files to be attached - { allowNonPromptFiles: true }, - ) - ); - - this._register(this._reference.onUpdate(() => this._onUpdate())); - } - - /** - * Start resolving the prompt instructions reference and child references - * that it may contain. - */ - public resolve(): this { - this._reference.start(); - - return this; - } -} diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachments.ts similarity index 68% rename from src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts rename to src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachments.ts index af7381fd783..20e1bb26994 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachmentsCollection.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatPromptAttachments.ts @@ -3,19 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { CancelablePromise, createCancelablePromise } from '../../../../../base/common/async.js'; import { Emitter } from '../../../../../base/common/event.js'; import { Disposable } from '../../../../../base/common/lifecycle.js'; import { ResourceMap } from '../../../../../base/common/map.js'; +import { URI } from '../../../../../base/common/uri.js'; import { ILanguageService } from '../../../../../editor/common/languages/language.js'; import { IModelService } from '../../../../../editor/common/services/model.js'; -import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { IChatRequestVariableEntry, IPromptFileVariableEntry, toPromptFileVariableEntry } from '../../common/chatVariableEntries.js'; - -import { ChatPromptAttachmentModel } from './chatPromptAttachmentModel.js'; +import { IPromptParserResult, IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; /** * Model for a collection of prompt instruction attachments. - * See {@linkcode ChatPromptAttachmentModel} for individual attachment. + * Starts */ export class ChatPromptAttachmentsCollection extends Disposable { /** @@ -24,29 +24,38 @@ export class ChatPromptAttachmentsCollection extends Disposable { * See {@linkcode onUpdate}. */ protected _onUpdate = this._register(new Emitter()); + /** * Subscribe to the `onUpdate` event. */ public onUpdate = this._onUpdate.event; - /** * List of all prompt instruction attachments. */ - private _attachments: ResourceMap = new ResourceMap(); + private _attachments = new ResourceMap>(); + + + constructor( + @ILanguageService private readonly languageService: ILanguageService, + @IModelService private readonly modelService: IModelService, + @IPromptsService private readonly promptsService: IPromptsService, + ) { + super(); + } /** * Check if any of the attachments is a prompt file. */ public hasPromptFiles(promptFileLanguageId: string): boolean { - const hasLanguage = ({ uri }: ChatPromptAttachmentModel) => { + const hasLanguage = (uri: URI) => { const model = this.modelService.getModel(uri); const languageId = model ? model.getLanguageId() : this.languageService.guessLanguageIdByFilepathOrFirstLine(uri); return languageId === promptFileLanguageId; }; - for (const child of this._attachments.values()) { - if (hasLanguage(child)) { + for (const uri of this._attachments.keys()) { + if (hasLanguage(uri)) { return true; } } @@ -58,51 +67,25 @@ export class ChatPromptAttachmentsCollection extends Disposable { * nested child references of each attachment explicitly attached by user. */ public async getAttachments(): Promise { - await this.allSettled(); - const result = []; const attachments = [...this._attachments.values()]; - for (const attachment of attachments) { - const { reference } = attachment; + for (const parseResultPromise of attachments) { + const parseResult = await parseResultPromise; // the usual URIs list of prompt instructions is `bottom-up`, therefore // we do the same here - first add all child references of the model - result.push( - ...reference.allValidReferences.map((link) => { - return toPromptFileVariableEntry(link.uri, false); - }), - ); + for (const uri of parseResult.allValidReferences) { + result.push(toPromptFileVariableEntry(uri, false)); + } // then add the root reference of the model itself - result.push(toPromptFileVariableEntry(reference.uri, true)); + result.push(toPromptFileVariableEntry(parseResult.uri, true)); } return result; } - /** - * Promise that resolves when parsing of all attached prompt instruction - * files completes, including parsing of all its possible child references. - */ - async allSettled(): Promise { - const attachments = [...this._attachments.values()]; - - await Promise.allSettled( - attachments.map((attachment) => { - return attachment.allSettled; - }), - ); - } - - constructor( - @IInstantiationService private readonly instantiationService: IInstantiationService, - @ILanguageService private readonly languageService: ILanguageService, - @IModelService private readonly modelService: IModelService, - ) { - super(); - } - /** * Add prompt instruction attachment instances */ @@ -115,8 +98,15 @@ export class ChatPromptAttachmentsCollection extends Disposable { continue; } - const instruction = this.instantiationService.createInstance(ChatPromptAttachmentModel, uri, () => this._onUpdate.fire(entry)); - this._attachments.set(uri, instruction); + const parseResult = createCancelablePromise(token => this.promptsService.parse(uri, token)); + parseResult.then(() => { + this._onUpdate.fire(entry); + }).catch((error) => { + // if parsing fails, we still create an attachment model + // to allow the user to see the error and fix it + console.error(`Failed to parse prompt file ${uri.toString()}:`, error); + }); + this._attachments.set(uri, parseResult); } } @@ -129,7 +119,7 @@ export class ChatPromptAttachmentsCollection extends Disposable { const attachment = this._attachments.get(uri); if (attachment) { this._attachments.delete(uri); - attachment.dispose(); + attachment.cancel(); } return this; @@ -140,7 +130,7 @@ export class ChatPromptAttachmentsCollection extends Disposable { */ public clear(): this { for (const attachment of this._attachments.values()) { - attachment.dispose(); + attachment.cancel(); } this._attachments.clear(); diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts index 8f359d3c4c5..68edcd52a3a 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts @@ -49,7 +49,7 @@ class PromptToolsCodeLensProvider extends Disposable implements CodeLensProvider const parser = this.promptsService.getSyntaxParserFor(model); const { header } = await parser - .start() + .start(token) .settled(); if ((header === undefined) || token.isCancellationRequested) { diff --git a/src/vs/workbench/contrib/chat/common/chatModes.ts b/src/vs/workbench/contrib/chat/common/chatModes.ts index 1d7812c5245..b4a9d447569 100644 --- a/src/vs/workbench/contrib/chat/common/chatModes.ts +++ b/src/vs/workbench/contrib/chat/common/chatModes.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { localize } from '../../../../nls.js'; @@ -49,7 +50,7 @@ export class ChatModeService extends Disposable implements IChatModeService { private async refreshCustomPromptModes(fireChangeEvent?: boolean): Promise { try { - const modes = await this.promptsService.getCustomChatModes(); + const modes = await this.promptsService.getCustomChatModes(CancellationToken.None); this.latestCustomPromptModes = modes.map(customMode => new CustomChatMode(customMode)); this.hasCustomModes.set(modes.length > 0); if (fireChangeEvent) { diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts index 7d301ad5545..1f90d5ff59d 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/promptContentsProviderBase.ts @@ -179,14 +179,14 @@ export abstract class PromptContentsProviderBase< /** * Start producing the prompt contents data. */ - public start(): this { + public start(token?: CancellationToken): this { assert( !this.isDisposed, 'Cannot start contents provider that was already disposed.', ); // `'full'` means "everything has changed" - this.onContentsChanged('full'); + this.onContentsChanged('full', token); // subscribe to the change event emitted by a child class this._register(this.onChangeEmitter.event(this.onContentsChanged, this)); diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts index be572215a4f..bec215b1d04 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/types.ts @@ -9,6 +9,7 @@ import { ResolveError } from '../../promptFileReferenceErrors.js'; import { IDisposable } from '../../../../../../base/common/lifecycle.js'; import { VSBufferReadableStream } from '../../../../../../base/common/buffer.js'; import { PromptsType } from '../promptTypes.js'; +import { CancellationToken } from '../../../../../../base/common/cancellation.js'; /** * Interface for a prompt contents provider. Prompt contents providers are @@ -56,7 +57,7 @@ export interface IPromptContentsProvider extends IDisposable { /** * Start the contents provider to produce the underlying contents. */ - start(): this; + start(token?: CancellationToken): this; /** * Create a new instance of prompt contents provider. diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkProvider.ts index 275682fdc8b..a92e0695b28 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptLinkProvider.ts @@ -42,7 +42,7 @@ export class PromptLinkProvider implements LinkProvider { // start the parser in case it was not started yet, // and wait for it to settle to a final result const { references } = await parser - .start() + .start(token) .settled(); // validate that the cancellation was not yet requested diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts index 956cd5a6888..8470df895c9 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptPathAutocompletion.ts @@ -138,7 +138,7 @@ export class PromptPathAutocompletion extends Disposable implements CompletionIt // start the parser in case it was not started yet, // and wait for it to settle to a final result const { references } = await parser - .start() + .start(token) .settled(); // validate that the cancellation was not yet requested diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts index c5436bd295e..7be72d8379f 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/basePromptParser.ts @@ -39,6 +39,7 @@ import { isPromptOrInstructionsFile } from '../config/promptFileLocations.js'; import { FrontMatterHeader } from '../codecs/base/markdownExtensionsCodec/tokens/frontMatterHeader.js'; import { OpenFailed, NotPromptFile, RecursiveReference, FolderReference, ResolveError } from '../../promptFileReferenceErrors.js'; import { type IPromptContentsProviderOptions, DEFAULT_OPTIONS as CONTENTS_PROVIDER_DEFAULT_OPTIONS } from '../contentProviders/promptContentsProviderBase.js'; +import { CancellationToken } from '../../../../../../base/common/cancellation.js'; /** * Options of the {@link BasePromptParser} class. @@ -511,7 +512,7 @@ export class BasePromptParser /** * Start the prompt parser. */ - public start(): this { + public start(token?: CancellationToken): this { // if already started, nothing to do if (this.started) { return this; @@ -525,7 +526,7 @@ export class BasePromptParser return this; } - this.promptContentsProvider.start(); + this.promptContentsProvider.start(token); return this; } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index fe706645583..db6bc946c57 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -14,6 +14,7 @@ import { TextModelPromptParser } from '../parsers/textModelPromptParser.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { PromptsType } from '../promptTypes.js'; import { createDecorator } from '../../../../../../platform/instantiation/common/instantiation.js'; +import { ITopError } from '../parsers/types.js'; /** * Provides prompt services. @@ -151,9 +152,7 @@ export interface IPromptsService extends IDisposable { * Get a prompt syntax parser for the provided text model. * See {@link TextModelPromptParser} for more info on the parser API. */ - getSyntaxParserFor( - model: ITextModel, - ): TSharedPrompt & { isDisposed: false }; + getSyntaxParserFor(model: ITextModel): TSharedPrompt & { isDisposed: false }; /** * List all available prompt files. @@ -185,9 +184,7 @@ export interface IPromptsService extends IDisposable { * Find all instruction files which have a glob pattern in their * 'applyTo' metadata record that match the provided list of files. */ - findInstructionFilesFor( - fileUris: readonly URI[], - ): Promise; + findInstructionFilesFor(fileUris: readonly URI[]): Promise; /** * Event that is triggered when the list of custom chat modes changes. @@ -197,7 +194,7 @@ export interface IPromptsService extends IDisposable { /** * Finds all available custom chat modes */ - getCustomChatModes(): Promise; + getCustomChatModes(token: CancellationToken): Promise; /** * Gets the metadata for the given prompt file uri. @@ -212,9 +209,13 @@ export interface IPromptsService extends IDisposable { * each of the provided files, therefore the result is a number * of metadata trees, one for each file. */ - getAllMetadata( - promptUris: readonly URI[], - ): Promise; + getAllMetadata(promptUris: readonly URI[]): Promise; + + /** + * Parses the provided URI + * @param uris + */ + parse(uri: URI, token: CancellationToken): Promise; } export interface IChatPromptSlashCommand { @@ -222,3 +223,11 @@ export interface IChatPromptSlashCommand { readonly detail: string; readonly promptPath?: IPromptPath; } + + +export interface IPromptParserResult { + readonly uri: URI; + readonly metadata: TMetadata | null; + readonly topError: ITopError | undefined; + readonly allValidReferences: readonly URI[]; +} diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts index 2c7dd5e5030..31f3b1d8293 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts @@ -25,7 +25,7 @@ import { IModelService } from '../../../../../../editor/common/services/model.js import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { IUserDataProfileService } from '../../../../../services/userDataProfile/common/userDataProfile.js'; -import type { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptPath, IPromptsService, TPromptsStorage } from './promptsService.js'; +import type { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptParserResult, IPromptPath, IPromptsService, TPromptsStorage } from './promptsService.js'; import { getCleanPromptName, PROMPT_FILE_EXTENSION } from '../config/promptFileLocations.js'; /** @@ -190,8 +190,8 @@ export class PromptsService extends Disposable implements IPromptsService { }); } - public async getCustomChatModes(): Promise { - const modeFiles = (await this.listPromptFiles(PromptsType.mode, CancellationToken.None)) + public async getCustomChatModes(token: CancellationToken): Promise { + const modeFiles = (await this.listPromptFiles(PromptsType.mode, token)) .map(modeFile => modeFile.uri); const metadataList = await Promise.all( @@ -204,7 +204,7 @@ export class PromptsService extends Disposable implements IPromptsService { PromptParser, uri, { allowNonPromptFiles: true }, - ).start(); + ).start(token); await parser.settled(); @@ -230,6 +230,24 @@ export class PromptsService extends Disposable implements IPromptsService { return metadataList; } + public async parse(uri: URI, token: CancellationToken): Promise { + let parser: PromptParser | undefined; + try { + parser = this.instantiationService.createInstance(PromptParser, uri, { allowNonPromptFiles: true }).start(token); + await parser.settled(); + // make a copy, to avoid leaking the parser instance + return { + uri: parser.uri, + metadata: parser.metadata, + topError: parser.topError, + allValidReferences: parser.allValidReferences.map(ref => ref.uri) + }; + } finally { + parser?.dispose(); + } + } + + public async findInstructionFilesFor(files: readonly URI[]): Promise { const instructionFiles = await this.listPromptFiles(PromptsType.instructions, CancellationToken.None); if (instructionFiles.length === 0) { diff --git a/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts b/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts index 1d7162f1154..810e953918e 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockPromptsService.ts @@ -8,7 +8,8 @@ import { URI } from '../../../../../base/common/uri.js'; import { ITextModel } from '../../../../../editor/common/model.js'; import { PromptsType } from '../../common/promptSyntax/promptTypes.js'; import { TextModelPromptParser } from '../../common/promptSyntax/parsers/textModelPromptParser.js'; -import { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptPath, IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; +import { IChatPromptSlashCommand, ICustomChatMode, IMetadata, IPromptParserResult, IPromptPath, IPromptsService } from '../../common/promptSyntax/service/promptsService.js'; +import { CancellationToken } from '../../../../../base/common/cancellation.js'; export class MockPromptsService implements IPromptsService { @@ -42,7 +43,10 @@ export class MockPromptsService implements IPromptsService { throw new Error('Method not implemented.'); } onDidChangeCustomChatModes: Event = Event.None; - getCustomChatModes(): Promise { + getCustomChatModes(token: CancellationToken): Promise { + throw new Error('Method not implemented.'); + } + parse(uri: URI, token: CancellationToken): Promise { throw new Error('Method not implemented.'); } dispose(): void { } From 2f7cd441c0922653a4e8a5913b4079de55d9012b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:58:58 -0700 Subject: [PATCH 222/236] Don't revive URI before sending from ext to main Fixes #235331 --- .../terminal-suggest/src/terminalSuggestMain.ts | 14 +++++++------- .../workbench/api/common/extHostTypeConverters.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/extensions/terminal-suggest/src/terminalSuggestMain.ts b/extensions/terminal-suggest/src/terminalSuggestMain.ts index 95567c16fae..ab0a8f2cbad 100644 --- a/extensions/terminal-suggest/src/terminalSuggestMain.ts +++ b/extensions/terminal-suggest/src/terminalSuggestMain.ts @@ -148,13 +148,13 @@ export async function activate(context: vscode.ExtensionContext) { } if (terminal.shellIntegration?.cwd && (result.filesRequested || result.foldersRequested)) { - let cwd; - if (vscode.env.remoteName) { - cwd = vscode.Uri.file((result.cwd ?? terminal.shellIntegration.cwd).path).with({ authority: vscode.env.remoteName, scheme: 'vscode-remote' }); - } else { - cwd = vscode.Uri.file((result.cwd ?? terminal.shellIntegration.cwd).fsPath); - } - return new vscode.TerminalCompletionList(result.items, { filesRequested: result.filesRequested, foldersRequested: result.foldersRequested, fileExtensions: result.fileExtensions, cwd, env: terminal.shellIntegration?.env?.value, }); + return new vscode.TerminalCompletionList(result.items, { + filesRequested: result.filesRequested, + foldersRequested: result.foldersRequested, + fileExtensions: result.fileExtensions, + cwd: result.cwd ?? terminal.shellIntegration.cwd, + env: terminal.shellIntegration?.env?.value, + }); } return result.items; } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 35e2cc93dea..e4a7378a3ae 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -3205,7 +3205,7 @@ export namespace TerminalResourceRequestConfig { return { ...resourceRequestConfig, pathSeparator, - cwd: resourceRequestConfig.cwd ? URI.revive(resourceRequestConfig.cwd) : undefined, + cwd: resourceRequestConfig.cwd, }; } } From 90da568e3176960275be4a9c07ce93b1db4cb2c6 Mon Sep 17 00:00:00 2001 From: Aaron Munger <2019016+amunger@users.noreply.github.com> Date: Thu, 12 Jun 2025 13:16:55 -0700 Subject: [PATCH 223/236] drop redo entries when writing new snapshots into history (#251299) * drop redo entries when writing new snapshots into history * undo unwanted changes --- .../contrib/chat/browser/chatEditing/chatEditingSession.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts index 2aca28634ef..d5a2a10f61a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts @@ -420,7 +420,10 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio const linearHistoryPtr = this._linearHistoryIndex.get(); const newLinearHistory: IChatEditingSessionSnapshot[] = []; for (const entry of this._linearHistory.get()) { - if (linearHistoryPtr - entry.startIndex < entry.stops.length) { + if (entry.startIndex >= linearHistoryPtr) { + // all further entries are being dropped + break; + } else if (linearHistoryPtr - entry.startIndex < entry.stops.length) { newLinearHistory.push({ requestId: entry.requestId, stops: entry.stops.slice(0, linearHistoryPtr - entry.startIndex), startIndex: entry.startIndex, postEdit: undefined }); } else { newLinearHistory.push(entry); From 3aaf8f936565f5f1c80b6fa69484a811186d9913 Mon Sep 17 00:00:00 2001 From: Josh Spicer <23246594+joshspicer@users.noreply.github.com> Date: Thu, 12 Jun 2025 13:40:31 -0700 Subject: [PATCH 224/236] Adopt mcp token flag (#251297) * adopt mcp token flag (https://github.com/microsoft/vscode-internalbacklog/issues/5514) * dont use constant to ChatMCP * use common/objects equals() --- .../contrib/chat/browser/chat.contribution.ts | 3 - .../accounts/common/defaultAccount.ts | 10 ++- .../policies/common/accountPolicyService.ts | 71 +++++++++++++------ 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 0a9390b5740..ef758ec4c06 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -243,12 +243,9 @@ configurationRegistry.registerConfiguration({ type: 'boolean', description: nls.localize('chat.mcp.enabled', "Enables integration with Model Context Protocol servers to provide additional tools and functionality."), default: true, - tags: ['preview'], policy: { name: 'ChatMCP', minimumVersion: '1.99', - previewFeature: true, - defaultValue: false } }, [mcpServerSamplingSection]: { diff --git a/src/vs/workbench/services/accounts/common/defaultAccount.ts b/src/vs/workbench/services/accounts/common/defaultAccount.ts index 7cfd7775ade..e58fae3118b 100644 --- a/src/vs/workbench/services/accounts/common/defaultAccount.ts +++ b/src/vs/workbench/services/accounts/common/defaultAccount.ts @@ -36,6 +36,7 @@ export interface IDefaultAccount { readonly can_signup_for_limited?: boolean; readonly chat_enabled?: boolean; readonly chat_preview_features_enabled?: boolean; + readonly mcp?: boolean; readonly analytics_tracking_id?: string; readonly limited_user_quotas?: { readonly chat: number; @@ -189,7 +190,7 @@ export class DefaultAccountManagementContribution extends Disposable implements } } - private extractFromToken(token: string, key: string): string | undefined { + private extractFromToken(token: string): Map { const result = new Map(); const firstPart = token?.split(':')[0]; const fields = firstPart?.split(';'); @@ -197,7 +198,7 @@ export class DefaultAccountManagementContribution extends Disposable implements const [key, value] = field.split('='); result.set(key, value); } - return result.get(key); + return result; } private async getDefaultAccountFromAuthenticatedSessions(authProviderId: string, enterpriseAuthProviderId: string, enterpriseAuthProviderConfig: string, scopes: string[], tokenEntitlementUrl: string, chatEntitlementUrl: string): Promise { @@ -243,9 +244,12 @@ export class DefaultAccountManagementContribution extends Disposable implements const chatData = await asJson(chatContext); if (chatData) { + const tokenMap = this.extractFromToken(chatData.token); return { // Editor preview features are disabled if the flag is present and set to 0 - chat_preview_features_enabled: this.extractFromToken(chatData.token, 'editor_preview_features') !== '0', + chat_preview_features_enabled: tokenMap.get('editor_preview_features') !== '0', + // MCP is disabled if the flag is present and set to 0 + mcp: tokenMap.get('mcp') !== '0', }; } this.logService.error('Failed to fetch token entitlements', 'No data returned'); diff --git a/src/vs/workbench/services/policies/common/accountPolicyService.ts b/src/vs/workbench/services/policies/common/accountPolicyService.ts index 9040c4f79f5..ffac5297272 100644 --- a/src/vs/workbench/services/policies/common/accountPolicyService.ts +++ b/src/vs/workbench/services/policies/common/accountPolicyService.ts @@ -4,12 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import { IStringDictionary } from '../../../../base/common/collections.js'; +import { equals } from '../../../../base/common/objects.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { AbstractPolicyService, IPolicyService, PolicyDefinition } from '../../../../platform/policy/common/policy.js'; import { IDefaultAccountService } from '../../accounts/common/defaultAccount.js'; +interface IAccountPolicy { + readonly chatPreviewFeaturesEnabled: boolean; + readonly mcpEnabled: boolean; +} + export class AccountPolicyService extends AbstractPolicyService implements IPolicyService { - private chatPreviewFeaturesEnabled: boolean = true; + private accountPolicy: IAccountPolicy = { + chatPreviewFeaturesEnabled: true, + mcpEnabled: true + }; constructor( @ILogService private readonly logService: ILogService, @IDefaultAccountService private readonly defaultAccountService: IDefaultAccountService @@ -18,43 +27,61 @@ export class AccountPolicyService extends AbstractPolicyService implements IPoli this.defaultAccountService.getDefaultAccount() .then(account => { - this._update(account?.chat_preview_features_enabled ?? true); - this._register(this.defaultAccountService.onDidChangeDefaultAccount(account => this._update(account?.chat_preview_features_enabled ?? true))); + this._update({ + chatPreviewFeaturesEnabled: account?.chat_preview_features_enabled ?? true, + mcpEnabled: account?.mcp ?? true + }); + this._register(this.defaultAccountService.onDidChangeDefaultAccount( + account => this._update({ + chatPreviewFeaturesEnabled: account?.chat_preview_features_enabled ?? true, + mcpEnabled: account?.mcp ?? true + }) + )); }); } - private _update(chatPreviewFeaturesEnabled: boolean | undefined) { - const newValue = (chatPreviewFeaturesEnabled === undefined) || chatPreviewFeaturesEnabled; - if (this.chatPreviewFeaturesEnabled !== newValue) { - this.chatPreviewFeaturesEnabled = newValue; + private _update(updatedPolicy: IAccountPolicy): void { + if (!equals(this.accountPolicy, updatedPolicy)) { + this.accountPolicy = updatedPolicy; this._updatePolicyDefinitions(this.policyDefinitions); } } protected async _updatePolicyDefinitions(policyDefinitions: IStringDictionary): Promise { this.logService.trace(`AccountPolicyService#_updatePolicyDefinitions: Got ${Object.keys(policyDefinitions).length} policy definitions`); + const updated: string[] = []; + + const updateIfNeeded = (key: string, policy: PolicyDefinition, isFeatureEnabled: boolean): void => { + if (isFeatureEnabled) { + // Clear the policy if it is set + if (this.policies.has(key)) { + this.policies.delete(key); + updated.push(key); + } + } else { + // Enforce the defaultValue if not already set + const updatedValue = policy.defaultValue === undefined ? false : policy.defaultValue; + if (this.policies.get(key) !== updatedValue) { + this.policies.set(key, updatedValue); + updated.push(key); + } + } + }; - const update: string[] = []; for (const key in policyDefinitions) { const policy = policyDefinitions[key]; + // Preview Features if (policy.previewFeature) { - if (this.chatPreviewFeaturesEnabled) { - this.policies.delete(key); - update.push(key); - continue; - } - const defaultValue = policy.defaultValue; - const updatedValue = defaultValue === undefined ? false : defaultValue; - if (this.policies.get(key) === updatedValue) { - continue; - } - this.policies.set(key, updatedValue); - update.push(key); + updateIfNeeded(key, policy, this.accountPolicy?.chatPreviewFeaturesEnabled); + } + // MCP + else if (key === 'ChatMCP') { + updateIfNeeded(key, policy, this.accountPolicy?.mcpEnabled); } } - if (update.length) { - this._onDidChange.fire(update); + if (updated.length) { + this._onDidChange.fire(updated); } } } From 6582eb540f9d5a5e0e98877ddd9483ee76ca1e27 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Jun 2025 15:47:30 -0700 Subject: [PATCH 225/236] Fix down arrow navigation in last notebook cell to move cursor to end of line (#251156) * Initial plan for issue * Fix down arrow navigation in last notebook cell to move cursor to end of line Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Add test to validate cursor position logic for last cell arrow navigation Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Fix notebook down arrow navigation logic to move cursor to end of line Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Implement proper down arrow navigation logic based on feedback - Check NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY context key - Only move to end of line when cursor boundary is 'start' or 'none' - Use ICellViewModel's setSelections method for cursor positioning - Apply logic to any cell on last line, not just last cell - Preserve existing behavior for last cell navigation Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * holy overthinking copilot --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> Co-authored-by: Michael Lively --- .../notebook/browser/contrib/navigation/arrow.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts b/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts index 7e40ee920d0..9a94c4a3f2b 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts @@ -21,7 +21,7 @@ import { InlineChatController } from '../../../../inlineChat/browser/inlineChatC import { CTX_NOTEBOOK_CHAT_OUTER_FOCUS_POSITION } from '../../controller/chat/notebookChatContext.js'; import { INotebookActionContext, INotebookCellActionContext, NotebookAction, NotebookCellAction, NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT, findTargetCellEditor } from '../../controller/coreActions.js'; import { CellEditState } from '../../notebookBrowser.js'; -import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from '../../../common/notebookCommon.js'; +import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY } from '../../../common/notebookCommon.js'; import { NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_TYPE, NOTEBOOK_CURSOR_NAVIGATION_MODE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_OUTPUT_INPUT_FOCUSED, NOTEBOOK_OUTPUT_FOCUSED, NOTEBOOK_CELL_EDITOR_FOCUSED, IS_COMPOSITE_NOTEBOOK } from '../../../common/notebookContextKeys.js'; const NOTEBOOK_FOCUS_TOP = 'notebook.focusTop'; @@ -77,6 +77,10 @@ registerAction2(class FocusNextCellAction extends NotebookCellAction { EditorContextKeys.editorTextFocus, NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('top'), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('none'), + ContextKeyExpr.or( + NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY.isEqualTo('end'), + NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY.isEqualTo('both') + ) ), EditorContextKeys.isEmbeddedDiffEditor.negate() ), @@ -158,6 +162,10 @@ registerAction2(class FocusPreviousCellAction extends NotebookCellAction { EditorContextKeys.editorTextFocus, NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('bottom'), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('none'), + ContextKeyExpr.or( + NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY.isEqualTo('start'), + NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY.isEqualTo('both') + ) ), EditorContextKeys.isEmbeddedDiffEditor.negate() ), From 6d2793975c01b8aed026001d0810aae8b8e8a1f1 Mon Sep 17 00:00:00 2001 From: Justin Chen <54879025+justschen@users.noreply.github.com> Date: Thu, 12 Jun 2025 16:31:27 -0700 Subject: [PATCH 226/236] undo button to undo requests, adds request in input (#251306) change to undo, setting for exp --- .../contrib/chat/browser/chat.contribution.ts | 6 ++++++ .../chat/browser/chatEditing/chatEditingActions.ts | 11 ++++++++--- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index ef758ec4c06..fd14681e382 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -239,6 +239,12 @@ configurationRegistry.registerConfiguration({ type: 'boolean', tags: ['experimental'] }, + 'chat.undoRequests.restoreInput': { + default: true, + markdownDescription: nls.localize('chat.undoRequests.restoreInput', "Controls whether the input of the chat should be restored when an undo request is made. The input will be filled with the text of the request that was restored."), + type: 'boolean', + tags: ['experimental'] + }, [mcpEnabledSection]: { type: 'boolean', description: nls.localize('chat.mcp.enabled', "Enables integration with Model Context Protocol servers to provide additional tools and functionality."), diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts index c1aebb45553..c7dcae66c15 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts @@ -312,7 +312,7 @@ registerAction2(class RemoveAction extends Action2 { title: localize2('chat.undoEdits.label', "Undo Requests"), f1: false, category: CHAT_CATEGORY, - icon: Codicon.x, + icon: Codicon.discard, keybinding: { primary: KeyCode.Delete, mac: { @@ -334,9 +334,9 @@ registerAction2(class RemoveAction extends Action2 { async run(accessor: ServicesAccessor, ...args: any[]) { let item: ChatTreeItem | undefined = args[0]; + const chatWidgetService = accessor.get(IChatWidgetService); + const widget = chatWidgetService.lastFocusedWidget; if (!isResponseVM(item) && !isRequestVM(item)) { - const chatWidgetService = accessor.get(IChatWidgetService); - const widget = chatWidgetService.lastFocusedWidget; item = widget?.getFocus(); } @@ -409,6 +409,11 @@ registerAction2(class RemoveAction extends Action2 { const snapshotRequestId = chatRequests[itemIndex].id; await session.restoreSnapshot(snapshotRequestId, undefined); } + + if (isRequestVM(item) && configurationService.getValue('chat.undoRequests.restoreInput')) { + widget?.focusInput(); + widget?.input.setValue(item.messageText, false); + } } }); diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index e4e6fb6f67f..7e023d96e1e 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1928,7 +1928,7 @@ have to be updated for changes to the rules above, or to support more deeply nes height: 22px; } - .request-hover .actions-container .action-label.codicon-x { + .request-hover .actions-container .action-label.codicon-discard { margin-top: 4px; padding: 3px 3px; } From 7e4e0f4e55d0d0a2a931aa4e0b7acc518e5da0dd Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Jun 2025 01:14:07 +0000 Subject: [PATCH 227/236] mcp: implement stdio shutdown spec compliance with graceful shutdown manager (#250207) * Initial plan for issue * Implement MCP stdio shutdown spec compliance with graceful shutdown manager Co-authored-by: connor4312 <2230985+connor4312@users.noreply.github.com> * Add error handling and cleanup optimizations to MCP shutdown manager Co-authored-by: connor4312 <2230985+connor4312@users.noreply.github.com> * update * cleanup --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: connor4312 <2230985+connor4312@users.noreply.github.com> Co-authored-by: Connor Peet --- src/vs/base/node/processes.ts | 51 +++++++++- src/vs/base/node/terminateProcess.sh | 17 ++-- src/vs/workbench/api/node/extHostMcpNode.ts | 44 ++++----- .../contrib/debug/node/debugAdapter.ts | 11 +-- .../contrib/mcp/node/mcpStdioStateHandler.ts | 94 ++++++++++++++++++ .../test/node/mcpStdioStateHandler.test.ts | 96 +++++++++++++++++++ 6 files changed, 268 insertions(+), 45 deletions(-) create mode 100644 src/vs/workbench/contrib/mcp/node/mcpStdioStateHandler.ts create mode 100644 src/vs/workbench/contrib/mcp/test/node/mcpStdioStateHandler.test.ts diff --git a/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts index 3a9fd987e6d..c2028fc5409 100644 --- a/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -8,10 +8,12 @@ import { Stats, promises } from 'fs'; import { getCaseInsensitive } from '../common/objects.js'; import * as path from '../common/path.js'; import * as Platform from '../common/platform.js'; -import * as process from '../common/process.js'; +import * as processCommon from '../common/process.js'; import { CommandOptions, ForkOptions, Source, SuccessData, TerminateResponse, TerminateResponseCode } from '../common/processes.js'; import * as Types from '../common/types.js'; import * as pfs from './pfs.js'; +import { FileAccess } from '../common/network.js'; +import Stream from 'stream'; export { Source, TerminateResponseCode, type CommandOptions, type ForkOptions, type SuccessData, type TerminateResponse }; export type ValueCallback = (value: T | Promise) => void; @@ -19,7 +21,7 @@ export type ErrorCallback = (error?: any) => void; export type ProgressCallback = (progress: T) => void; -export function getWindowsShell(env = process.env as Platform.IProcessEnvironment): string { +export function getWindowsShell(env = processCommon.env as Platform.IProcessEnvironment): string { return env['comspec'] || 'cmd.exe'; } @@ -81,17 +83,17 @@ async function fileExistsDefault(path: string): Promise { return false; } -export function getWindowPathExtensions(env = process.env) { +export function getWindowPathExtensions(env = processCommon.env) { return (getCaseInsensitive(env, 'PATHEXT') as string || '.COM;.EXE;.BAT;.CMD').split(';'); } -export async function findExecutable(command: string, cwd?: string, paths?: string[], env: Platform.IProcessEnvironment = process.env as Platform.IProcessEnvironment, fileExists: (path: string) => Promise = fileExistsDefault): Promise { +export async function findExecutable(command: string, cwd?: string, paths?: string[], env: Platform.IProcessEnvironment = processCommon.env as Platform.IProcessEnvironment, fileExists: (path: string) => Promise = fileExistsDefault): Promise { // If we have an absolute path then we take it. if (path.isAbsolute(command)) { return await fileExists(command) ? command : undefined; } if (cwd === undefined) { - cwd = process.cwd(); + cwd = processCommon.cwd(); } const dir = path.dirname(command); if (dir !== '.') { @@ -140,3 +142,42 @@ export async function findExecutable(command: string, cwd?: string, paths?: stri const fullPath = path.join(cwd, command); return await fileExists(fullPath) ? fullPath : undefined; } + +/** + * Kills a process and all its children. + * @param pid the process id to kill + * @param forceful whether to forcefully kill the process (default: false). Note + * that on Windows, terminal processes can _only_ be killed forcefully and this + * will throw when not forceful. + */ +export async function killTree(pid: number, forceful = false) { + let child: cp.ChildProcessByStdio; + if (Platform.isWindows) { + const windir = process.env['WINDIR'] || 'C:\\Windows'; + const taskKill = path.join(windir, 'System32', 'taskkill.exe'); + + const args = ['/T']; + if (forceful) { + args.push('/F'); + } + args.push('/PID', String(pid)); + child = cp.spawn(taskKill, args, { stdio: ['ignore', 'pipe', 'pipe'] }); + } else { + const killScript = FileAccess.asFileUri('vs/base/node/terminateProcess.sh').fsPath; + child = cp.spawn('/bin/sh', [killScript, String(pid), forceful ? '9' : '15'], { stdio: ['ignore', 'pipe', 'pipe'] }); + } + + return new Promise((resolve, reject) => { + const stdout: Buffer[] = []; + child.stdout.on('data', (data) => stdout.push(data)); + child.stderr.on('data', (data) => stdout.push(data)); + child.on('error', reject); + child.on('exit', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`taskkill exited with code ${code}: ${Buffer.concat(stdout).toString()}`)); + } + }); + }); +} diff --git a/src/vs/base/node/terminateProcess.sh b/src/vs/base/node/terminateProcess.sh index acdcbf8ed42..a8e8738fdb4 100755 --- a/src/vs/base/node/terminateProcess.sh +++ b/src/vs/base/node/terminateProcess.sh @@ -1,12 +1,13 @@ -#!/bin/bash +#!/bin/sh + +ROOT_PID=$1 +SIGNAL=$2 terminateTree() { - for cpid in $(/usr/bin/pgrep -P $1); do - terminateTree $cpid - done - kill -9 $1 > /dev/null 2>&1 + for cpid in $(pgrep -P $1); do + terminateTree $cpid + done + kill -$SIGNAL $1 > /dev/null 2>&1 } -for pid in $*; do - terminateTree $pid -done \ No newline at end of file +terminateTree $ROOT_PID diff --git a/src/vs/workbench/api/node/extHostMcpNode.ts b/src/vs/workbench/api/node/extHostMcpNode.ts index 0e65834ab19..ee90057f2e3 100644 --- a/src/vs/workbench/api/node/extHostMcpNode.ts +++ b/src/vs/workbench/api/node/extHostMcpNode.ts @@ -8,14 +8,16 @@ import { readFile } from 'fs/promises'; import { homedir } from 'os'; import { parseEnvFile } from '../../../base/common/envfile.js'; import { untildify } from '../../../base/common/labels.js'; +import { DisposableMap } from '../../../base/common/lifecycle.js'; +import * as path from '../../../base/common/path.js'; import { StreamSplitter } from '../../../base/node/nodeStreams.js'; import { findExecutable } from '../../../base/node/processes.js'; import { ILogService, LogLevel } from '../../../platform/log/common/log.js'; import { McpConnectionState, McpServerLaunch, McpServerTransportStdio, McpServerTransportType } from '../../contrib/mcp/common/mcpTypes.js'; +import { McpStdioStateHandler } from '../../contrib/mcp/node/mcpStdioStateHandler.js'; +import { IExtHostInitDataService } from '../common/extHostInitDataService.js'; import { ExtHostMcpService } from '../common/extHostMcp.js'; import { IExtHostRpcService } from '../common/extHostRpcService.js'; -import * as path from '../../../base/common/path.js'; -import { IExtHostInitDataService } from '../common/extHostInitDataService.js'; export class NodeExtHostMpcService extends ExtHostMcpService { constructor( @@ -26,10 +28,7 @@ export class NodeExtHostMpcService extends ExtHostMcpService { super(extHostRpc, logService, initDataService); } - private nodeServers = new Map(); + private nodeServers = this._register(new DisposableMap()); protected override _startMcp(id: number, launch: McpServerLaunch): void { if (launch.type === McpServerTransportType.Stdio) { @@ -42,8 +41,7 @@ export class NodeExtHostMpcService extends ExtHostMcpService { override $stopMcp(id: number): void { const nodeServer = this.nodeServers.get(id); if (nodeServer) { - nodeServer.abortCtrl.abort(); - this.nodeServers.delete(id); + nodeServer.stop(); // will get removed from map when process is fully stopped } else { super.$stopMcp(id); } @@ -52,7 +50,7 @@ export class NodeExtHostMpcService extends ExtHostMcpService { override $sendMessage(id: number, message: string): void { const nodeServer = this.nodeServers.get(id); if (nodeServer) { - nodeServer.child.stdin.write(message + '\n'); + nodeServer.write(message); } else { super.$sendMessage(id, message); } @@ -82,7 +80,6 @@ export class NodeExtHostMpcService extends ExtHostMcpService { env[key] = value === null ? undefined : String(value); } - const abortCtrl = new AbortController(); let child: ChildProcessWithoutNullStreams; try { const home = homedir(); @@ -102,16 +99,17 @@ export class NodeExtHostMpcService extends ExtHostMcpService { child = spawn(executable, args, { stdio: 'pipe', cwd, - signal: abortCtrl.signal, env, shell, }); } catch (e) { onError(e); - abortCtrl.abort(); return; } + // Create the connection manager for graceful shutdown + const connectionManager = new McpStdioStateHandler(child); + this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Starting }); child.stdout.pipe(new StreamSplitter('\n')).on('data', line => this._proxy.$onDidReceiveMessage(id, line.toString())); @@ -126,22 +124,22 @@ export class NodeExtHostMpcService extends ExtHostMcpService { child.on('spawn', () => this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Running })); child.on('error', e => { - if (abortCtrl.signal.aborted) { + onError(e); + }); + child.on('exit', code => { + this.nodeServers.deleteAndDispose(id); + + if (code === 0 || connectionManager.stopped) { this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Stopped }); } else { - onError(e); - } - }); - child.on('exit', code => - code === 0 || abortCtrl.signal.aborted - ? this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Stopped }) - : this._proxy.$onDidChangeState(id, { + this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Error, message: `Process exited with code ${code}`, - }) - ); + }); + } + }); - this.nodeServers.set(id, { abortCtrl, child }); + this.nodeServers.set(id, connectionManager); } } diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index 4892338a1c1..1698883b62c 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -15,6 +15,7 @@ import * as nls from '../../../../nls.js'; import { IExtensionDescription } from '../../../../platform/extensions/common/extensions.js'; import { IDebugAdapterExecutable, IDebugAdapterNamedPipeServer, IDebugAdapterServer, IDebuggerContribution, IPlatformSpecificAdapterContribution } from '../common/debug.js'; import { AbstractDebugAdapter } from '../common/abstractDebugAdapter.js'; +import { killTree } from '../../../../base/node/processes.js'; /** * An implementation that communicates via two streams with the debug adapter. @@ -288,15 +289,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { // processes. Therefore we use TASKKILL.EXE await this.cancelPendingRequests(); if (platform.isWindows) { - return new Promise((c, e) => { - const killer = cp.exec(`taskkill /F /T /PID ${this.serverProcess!.pid}`, function (err, stdout, stderr) { - if (err) { - return e(err); - } - }); - killer.on('exit', c); - killer.on('error', e); - }); + return killTree(this.serverProcess!.pid!, true); } else { this.serverProcess.kill('SIGTERM'); return Promise.resolve(undefined); diff --git a/src/vs/workbench/contrib/mcp/node/mcpStdioStateHandler.ts b/src/vs/workbench/contrib/mcp/node/mcpStdioStateHandler.ts new file mode 100644 index 00000000000..fba931a0280 --- /dev/null +++ b/src/vs/workbench/contrib/mcp/node/mcpStdioStateHandler.ts @@ -0,0 +1,94 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ChildProcessWithoutNullStreams } from 'child_process'; +import { TimeoutTimer } from '../../../../base/common/async.js'; +import { IDisposable } from '../../../../base/common/lifecycle.js'; +import { killTree } from '../../../../base/node/processes.js'; +import { isWindows } from '../../../../base/common/platform.js'; + +const enum McpProcessState { + Running, + StdinEnded, + KilledPolite, + KilledForceful, +} + +/** + * Manages graceful shutdown of MCP stdio connections following the MCP specification. + * + * Per spec, shutdown should: + * 1. Close the input stream to the child process + * 2. Wait for the server to exit, or send SIGTERM if it doesn't exit within 10 seconds + * 3. Send SIGKILL if the server doesn't exit within 10 seconds after SIGTERM + * 4. Allow forceful killing if called twice + */ +export class McpStdioStateHandler implements IDisposable { + private static readonly GRACE_TIME_MS = 10_000; + + private _procState = McpProcessState.Running; + private _nextTimeout?: IDisposable; + + public get stopped() { + return this._procState !== McpProcessState.Running; + } + + constructor( + private readonly _child: ChildProcessWithoutNullStreams, + private readonly _graceTimeMs: number = McpStdioStateHandler.GRACE_TIME_MS + ) { } + + /** + * Initiates graceful shutdown. If called while shutdown is already in progress, + * forces immediate termination. + */ + public stop(): void { + if (this._procState === McpProcessState.Running) { + try { + this._child.stdin.end(); + } catch (error) { + // If stdin.end() fails, continue with termination sequence + // This can happen if the stream is already in an error state + } + this._nextTimeout = new TimeoutTimer(() => this.killPolite(), this._graceTimeMs); + } else { + this._nextTimeout?.dispose(); + this.killForceful(); + } + } + + private async killPolite() { + this._procState = McpProcessState.KilledPolite; + this._nextTimeout = new TimeoutTimer(() => this.killForceful(), this._graceTimeMs); + + if (this._child.pid) { + if (!isWindows) { + await killTree(this._child.pid, false); + } + } else { + this._child.kill('SIGTERM'); + } + } + + private async killForceful() { + this._procState = McpProcessState.KilledForceful; + + if (this._child.pid) { + await killTree(this._child.pid, true); + } else { + this._child.kill(); + } + } + + public write(message: string): void { + if (!this.stopped) { + this._child.stdin.write(message + '\n'); + } + } + + public dispose() { + this._nextTimeout?.dispose(); + } +} diff --git a/src/vs/workbench/contrib/mcp/test/node/mcpStdioStateHandler.test.ts b/src/vs/workbench/contrib/mcp/test/node/mcpStdioStateHandler.test.ts new file mode 100644 index 00000000000..9bee4963b01 --- /dev/null +++ b/src/vs/workbench/contrib/mcp/test/node/mcpStdioStateHandler.test.ts @@ -0,0 +1,96 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { spawn } from 'child_process'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; +import * as assert from 'assert'; +import { McpStdioStateHandler } from '../../node/mcpStdioStateHandler.js'; +import { isWindows } from '../../../../../base/common/platform.js'; + +const GRACE_TIME = 100; + +suite('McpStdioStateHandler', () => { + const store = ensureNoDisposablesAreLeakedInTestSuite(); + + function run(code: string) { + const child = spawn('node', ['-e', code], { + stdio: 'pipe', + env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' }, + }); + + return { + child, + handler: store.add(new McpStdioStateHandler(child, GRACE_TIME)), + processId: new Promise((resolve) => { + child.on('spawn', () => resolve(child.pid!)); + }), + output: new Promise((resolve) => { + let output = ''; + child.stderr.setEncoding('utf-8').on('data', (data) => { + output += data.toString(); + }); + child.stdout.setEncoding('utf-8').on('data', (data) => { + output += data.toString(); + }); + child.on('close', () => resolve(output)); + }), + }; + } + + test('stdin ends process', async () => { + const { child, handler, output } = run(` + const data = require('fs').readFileSync(0, 'utf-8'); + process.stdout.write('Data received: ' + data); + process.on('SIGTERM', () => process.stdout.write('SIGTERM received')); + `); + + child.stdin.write('Hello MCP!'); + handler.stop(); + const result = await output; + assert.strictEqual(result.trim(), 'Data received: Hello MCP!'); + }); + + if (!isWindows) { + test('sigterm after grace', async () => { + const { handler, output } = run(` + setInterval(() => {}, 1000); + process.stdin.on('end', () => process.stdout.write('stdin ended\\n')); + process.stdin.resume(); + process.on('SIGTERM', () => { + process.stdout.write('SIGTERM received', () => process.exit(0)); + }); + `); + + const before = Date.now(); + handler.stop(); + const result = await output; + const delay = Date.now() - before; + assert.strictEqual(result.trim(), 'stdin ended\nSIGTERM received'); + assert.ok(delay >= GRACE_TIME, `Expected at least ${GRACE_TIME}ms delay, got ${delay}ms`); + }); + } + + test('sigkill after grace', async () => { + const { handler, output } = run(` + setInterval(() => {}, 1000); + process.stdin.on('end', () => process.stdout.write('stdin ended\\n')); + process.stdin.resume(); + process.on('SIGTERM', () => { + process.stdout.write('SIGTERM received'); + }); + `); + + const before = Date.now(); + handler.stop(); + const result = await output; + const delay = Date.now() - before; + if (!isWindows) { + assert.strictEqual(result.trim(), 'stdin ended\nSIGTERM received'); + } else { + assert.strictEqual(result.trim(), 'stdin ended'); + } + assert.ok(delay >= GRACE_TIME * 2, `Expected at least ${GRACE_TIME * 2}ms delay, got ${delay}ms`); + }); +}); From 7766411d9f288d70458cce77ea0995e6d6fd1a50 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 12 Jun 2025 22:56:36 -0700 Subject: [PATCH 228/236] Add ... (#251350) Fix microsoft/vscode-copilot#18203 --- .../contrib/chat/browser/promptSyntax/chatModeActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts index 45668199fe3..a63ca141f3b 100644 --- a/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts +++ b/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.ts @@ -26,8 +26,8 @@ class ManageModeAction extends Action2 { constructor() { super({ id: COMFIGURE_MODES_ACTION_ID, - title: localize2('configure-modes', "Configure Chat Modes"), - shortTitle: localize('manage-mode', "Configure Modes"), + title: localize2('configure-modes', "Configure Chat Modes..."), + shortTitle: localize('manage-mode', "Configure Modes..."), icon: Codicon.bookmark, f1: true, precondition: ContextKeyExpr.and(PromptsConfig.enabledCtx, ChatContextKeys.enabled), From 31620a3decb7f5ec0d6a3c55fab89ab17906a77e Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt <2644648+TylerLeonhardt@users.noreply.github.com> Date: Thu, 12 Jun 2025 23:14:41 -0700 Subject: [PATCH 229/236] Have Loopback Server flow redirect back to VS Code and make it the primary flow (#251333) * Have Loopback Server flow redirect back to VS Code and make it the primary flow Fixes https://github.com/microsoft/vscode/issues/250086 * Fix test * Fix test * Fix other test --- .../github-authentication/media/index.html | 10 +- extensions/github-authentication/src/flows.ts | 681 +++++++++--------- .../src/node/authServer.ts | 4 +- .../src/test/flows.test.ts | 4 +- .../src/test/node/authServer.test.ts | 4 +- 5 files changed, 358 insertions(+), 345 deletions(-) diff --git a/extensions/github-authentication/media/index.html b/extensions/github-authentication/media/index.html index efd092d6dfb..16593d751e0 100644 --- a/extensions/github-authentication/media/index.html +++ b/extensions/github-authentication/media/index.html @@ -23,13 +23,17 @@ diff --git a/extensions/github-authentication/src/flows.ts b/extensions/github-authentication/src/flows.ts index 8920ea5d357..47107db7069 100644 --- a/extensions/github-authentication/src/flows.ts +++ b/extensions/github-authentication/src/flows.ts @@ -121,356 +121,365 @@ async function exchangeCodeForToken( } } -const allFlows: IFlow[] = [ - new class UrlHandlerFlow implements IFlow { - label = l10n.t('url handler'); - options: IFlowOptions = { - supportsGitHubDotCom: true, - // Supporting GHES would be challenging because different versions - // used a different client ID. We could try to detect the version - // and use the right one, but that's a lot of work when we have - // other flows that work well. - supportsGitHubEnterpriseServer: false, - supportsHostedGitHubEnterprise: true, - supportsRemoteExtensionHost: true, - supportsWebWorkerExtensionHost: true, - // exchanging a code for a token requires a client secret - supportsNoClientSecret: false, - supportsSupportedClients: true, - supportsUnsupportedClients: false - }; +class UrlHandlerFlow implements IFlow { + label = l10n.t('url handler'); + options: IFlowOptions = { + supportsGitHubDotCom: true, + // Supporting GHES would be challenging because different versions + // used a different client ID. We could try to detect the version + // and use the right one, but that's a lot of work when we have + // other flows that work well. + supportsGitHubEnterpriseServer: false, + supportsHostedGitHubEnterprise: true, + supportsRemoteExtensionHost: true, + supportsWebWorkerExtensionHost: true, + // exchanging a code for a token requires a client secret + supportsNoClientSecret: false, + supportsSupportedClients: true, + supportsUnsupportedClients: false + }; - async trigger({ - scopes, - baseUri, - redirectUri, - logger, - nonce, - callbackUri, - uriHandler, - enterpriseUri, - existingLogin - }: IFlowTriggerOptions): Promise { - logger.info(`Trying without local server... (${scopes})`); - return await window.withProgress({ - location: ProgressLocation.Notification, - title: l10n.t({ - message: 'Signing in to {0}...', - args: [baseUri.authority], - comment: ['The {0} will be a url, e.g. github.com'] - }), - cancellable: true - }, async (_, token) => { - const promise = uriHandler.waitForCode(logger, scopes, nonce, token); + async trigger({ + scopes, + baseUri, + redirectUri, + logger, + nonce, + callbackUri, + uriHandler, + enterpriseUri, + existingLogin + }: IFlowTriggerOptions): Promise { + logger.info(`Trying without local server... (${scopes})`); + return await window.withProgress({ + location: ProgressLocation.Notification, + title: l10n.t({ + message: 'Signing in to {0}...', + args: [baseUri.authority], + comment: ['The {0} will be a url, e.g. github.com'] + }), + cancellable: true + }, async (_, token) => { + const promise = uriHandler.waitForCode(logger, scopes, nonce, token); - const searchParams = new URLSearchParams([ - ['client_id', Config.gitHubClientId], - ['redirect_uri', redirectUri.toString(true)], - ['scope', scopes], - ['state', encodeURIComponent(callbackUri.toString(true))] - ]); - if (existingLogin) { - searchParams.append('login', existingLogin); - } else { - searchParams.append('prompt', 'select_account'); - } - - // The extra toString, parse is apparently needed for env.openExternal - // to open the correct URL. - const uri = Uri.parse(baseUri.with({ - path: '/login/oauth/authorize', - query: searchParams.toString() - }).toString(true)); - await env.openExternal(uri); - - const code = await promise; - - const proxyEndpoints: { [providerId: string]: string } | undefined = await commands.executeCommand('workbench.getCodeExchangeProxyEndpoints'); - const endpointUrl = proxyEndpoints?.github - ? Uri.parse(`${proxyEndpoints.github}login/oauth/access_token`) - : baseUri.with({ path: '/login/oauth/access_token' }); - - const accessToken = await exchangeCodeForToken(logger, endpointUrl, redirectUri, code, enterpriseUri); - return accessToken; - }); - } - }, - new class LocalServerFlow implements IFlow { - label = l10n.t('local server'); - options: IFlowOptions = { - supportsGitHubDotCom: true, - // Supporting GHES would be challenging because different versions - // used a different client ID. We could try to detect the version - // and use the right one, but that's a lot of work when we have - // other flows that work well. - supportsGitHubEnterpriseServer: false, - supportsHostedGitHubEnterprise: true, - // Opening a port on the remote side can't be open in the browser on - // the client side so this flow won't work in remote extension hosts - supportsRemoteExtensionHost: false, - // Web worker can't open a port to listen for the redirect - supportsWebWorkerExtensionHost: false, - // exchanging a code for a token requires a client secret - supportsNoClientSecret: false, - supportsSupportedClients: true, - supportsUnsupportedClients: true - }; - async trigger({ - scopes, - baseUri, - redirectUri, - logger, - enterpriseUri, - existingLogin - }: IFlowTriggerOptions): Promise { - logger.info(`Trying with local server... (${scopes})`); - return await window.withProgress({ - location: ProgressLocation.Notification, - title: l10n.t({ - message: 'Signing in to {0}...', - args: [baseUri.authority], - comment: ['The {0} will be a url, e.g. github.com'] - }), - cancellable: true - }, async (_, token) => { - const searchParams = new URLSearchParams([ - ['client_id', Config.gitHubClientId], - ['redirect_uri', redirectUri.toString(true)], - ['scope', scopes], - ]); - if (existingLogin) { - searchParams.append('login', existingLogin); - } else { - searchParams.append('prompt', 'select_account'); - } - - const loginUrl = baseUri.with({ - path: '/login/oauth/authorize', - query: searchParams.toString() - }); - const server = new LoopbackAuthServer(path.join(__dirname, '../media'), loginUrl.toString(true)); - const port = await server.start(); - - let codeToExchange; - try { - env.openExternal(Uri.parse(`http://127.0.0.1:${port}/signin?nonce=${encodeURIComponent(server.nonce)}`)); - const { code } = await Promise.race([ - server.waitForOAuthResponse(), - new Promise((_, reject) => setTimeout(() => reject(TIMED_OUT_ERROR), 300_000)), // 5min timeout - promiseFromEvent(token.onCancellationRequested, (_, __, reject) => { reject(USER_CANCELLATION_ERROR); }).promise - ]); - codeToExchange = code; - } finally { - setTimeout(() => { - void server.stop(); - }, 5000); - } - - const accessToken = await exchangeCodeForToken( - logger, - baseUri.with({ path: '/login/oauth/access_token' }), - redirectUri, - codeToExchange, - enterpriseUri); - return accessToken; - }); - } - }, - new class DeviceCodeFlow implements IFlow { - label = l10n.t('device code'); - options: IFlowOptions = { - supportsGitHubDotCom: true, - supportsGitHubEnterpriseServer: true, - supportsHostedGitHubEnterprise: true, - supportsRemoteExtensionHost: true, - // CORS prevents this from working in web workers - supportsWebWorkerExtensionHost: false, - supportsNoClientSecret: true, - supportsSupportedClients: true, - supportsUnsupportedClients: true - }; - async trigger({ scopes, baseUri, logger }: IFlowTriggerOptions) { - logger.info(`Trying device code flow... (${scopes})`); - - // Get initial device code - const uri = baseUri.with({ - path: '/login/device/code', - query: `client_id=${Config.gitHubClientId}&scope=${scopes}` - }); - const result = await fetching(uri.toString(true), { - method: 'POST', - headers: { - Accept: 'application/json' - } - }); - if (!result.ok) { - throw new Error(`Failed to get one-time code: ${await result.text()}`); + const searchParams = new URLSearchParams([ + ['client_id', Config.gitHubClientId], + ['redirect_uri', redirectUri.toString(true)], + ['scope', scopes], + ['state', encodeURIComponent(callbackUri.toString(true))] + ]); + if (existingLogin) { + searchParams.append('login', existingLogin); + } else { + searchParams.append('prompt', 'select_account'); } - const json = await result.json() as IGitHubDeviceCodeResponse; + // The extra toString, parse is apparently needed for env.openExternal + // to open the correct URL. + const uri = Uri.parse(baseUri.with({ + path: '/login/oauth/authorize', + query: searchParams.toString() + }).toString(true)); + await env.openExternal(uri); - const button = l10n.t('Copy & Continue to GitHub'); - const modalResult = await window.showInformationMessage( - l10n.t({ message: 'Your Code: {0}', args: [json.user_code], comment: ['The {0} will be a code, e.g. 123-456'] }), - { - modal: true, - detail: l10n.t('To finish authenticating, navigate to GitHub and paste in the above one-time code.') - }, button); + const code = await promise; - if (modalResult !== button) { - throw new Error(USER_CANCELLATION_ERROR); + const proxyEndpoints: { [providerId: string]: string } | undefined = await commands.executeCommand('workbench.getCodeExchangeProxyEndpoints'); + const endpointUrl = proxyEndpoints?.github + ? Uri.parse(`${proxyEndpoints.github}login/oauth/access_token`) + : baseUri.with({ path: '/login/oauth/access_token' }); + + const accessToken = await exchangeCodeForToken(logger, endpointUrl, redirectUri, code, enterpriseUri); + return accessToken; + }); + } +} + +class LocalServerFlow implements IFlow { + label = l10n.t('local server'); + options: IFlowOptions = { + supportsGitHubDotCom: true, + // Supporting GHES would be challenging because different versions + // used a different client ID. We could try to detect the version + // and use the right one, but that's a lot of work when we have + // other flows that work well. + supportsGitHubEnterpriseServer: false, + supportsHostedGitHubEnterprise: true, + // Opening a port on the remote side can't be open in the browser on + // the client side so this flow won't work in remote extension hosts + supportsRemoteExtensionHost: false, + // Web worker can't open a port to listen for the redirect + supportsWebWorkerExtensionHost: false, + // exchanging a code for a token requires a client secret + supportsNoClientSecret: false, + supportsSupportedClients: true, + supportsUnsupportedClients: true + }; + async trigger({ + scopes, + baseUri, + redirectUri, + logger, + callbackUri, + enterpriseUri, + existingLogin + }: IFlowTriggerOptions): Promise { + logger.info(`Trying with local server... (${scopes})`); + return await window.withProgress({ + location: ProgressLocation.Notification, + title: l10n.t({ + message: 'Signing in to {0}...', + args: [baseUri.authority], + comment: ['The {0} will be a url, e.g. github.com'] + }), + cancellable: true + }, async (_, token) => { + const searchParams = new URLSearchParams([ + ['client_id', Config.gitHubClientId], + ['redirect_uri', redirectUri.toString(true)], + ['scope', scopes], + ]); + if (existingLogin) { + searchParams.append('login', existingLogin); + } else { + searchParams.append('prompt', 'select_account'); } - await env.clipboard.writeText(json.user_code); - - const uriToOpen = await env.asExternalUri(Uri.parse(json.verification_uri)); - await env.openExternal(uriToOpen); - - return await this.waitForDeviceCodeAccessToken(baseUri, json); - } - - private async waitForDeviceCodeAccessToken( - baseUri: Uri, - json: IGitHubDeviceCodeResponse, - ): Promise { - return await window.withProgress({ - location: ProgressLocation.Notification, - cancellable: true, - title: l10n.t({ - message: 'Open [{0}]({0}) in a new tab and paste your one-time code: {1}', - args: [json.verification_uri, json.user_code], - comment: [ - 'The [{0}]({0}) will be a url and the {1} will be a code, e.g. 123-456', - '{Locked="[{0}]({0})"}' - ] - }) - }, async (_, token) => { - const refreshTokenUri = baseUri.with({ - path: '/login/oauth/access_token', - query: `client_id=${Config.gitHubClientId}&device_code=${json.device_code}&grant_type=urn:ietf:params:oauth:grant-type:device_code` - }); - - // Try for 2 minutes - const attempts = 120 / json.interval; - for (let i = 0; i < attempts; i++) { - await new Promise(resolve => setTimeout(resolve, json.interval * 1000)); - if (token.isCancellationRequested) { - throw new Error(USER_CANCELLATION_ERROR); - } - let accessTokenResult; - try { - accessTokenResult = await fetching(refreshTokenUri.toString(true), { - method: 'POST', - headers: { - Accept: 'application/json' - } - }); - } catch { - continue; - } - - if (!accessTokenResult.ok) { - continue; - } - - const accessTokenJson = await accessTokenResult.json(); - - if (accessTokenJson.error === 'authorization_pending') { - continue; - } - - if (accessTokenJson.error) { - throw new Error(accessTokenJson.error_description); - } - - return accessTokenJson.access_token; - } - - throw new Error(TIMED_OUT_ERROR); + const loginUrl = baseUri.with({ + path: '/login/oauth/authorize', + query: searchParams.toString() }); - } - }, - new class PatFlow implements IFlow { - label = l10n.t('personal access token'); - options: IFlowOptions = { - supportsGitHubDotCom: true, - supportsGitHubEnterpriseServer: true, - supportsHostedGitHubEnterprise: true, - supportsRemoteExtensionHost: true, - supportsWebWorkerExtensionHost: true, - supportsNoClientSecret: true, - // PATs can't be used with Settings Sync so we don't enable this flow - // for supported clients - supportsSupportedClients: false, - supportsUnsupportedClients: true - }; + const server = new LoopbackAuthServer(path.join(__dirname, '../media'), loginUrl.toString(true), callbackUri.toString(true)); + const port = await server.start(); - async trigger({ scopes, baseUri, logger, enterpriseUri }: IFlowTriggerOptions) { - logger.info(`Trying to retrieve PAT... (${scopes})`); - - const button = l10n.t('Continue to GitHub'); - const modalResult = await window.showInformationMessage( - l10n.t('Continue to GitHub to create a Personal Access Token (PAT)'), - { - modal: true, - detail: l10n.t('To finish authenticating, navigate to GitHub to create a PAT then paste the PAT into the input box.') - }, button); - - if (modalResult !== button) { - throw new Error(USER_CANCELLATION_ERROR); - } - - const description = `${env.appName} (${scopes})`; - const uriToOpen = await env.asExternalUri(baseUri.with({ path: '/settings/tokens/new', query: `description=${description}&scopes=${scopes.split(' ').join(',')}` })); - await env.openExternal(uriToOpen); - const token = await window.showInputBox({ placeHolder: `ghp_1a2b3c4...`, prompt: `GitHub Personal Access Token - ${scopes}`, ignoreFocusOut: true }); - if (!token) { throw new Error(USER_CANCELLATION_ERROR); } - - const appUri = !enterpriseUri || isHostedGitHubEnterprise(enterpriseUri) - ? Uri.parse(`${baseUri.scheme}://api.${baseUri.authority}`) - : Uri.parse(`${baseUri.scheme}://${baseUri.authority}/api/v3`); - - const tokenScopes = await this.getScopes(token, appUri, logger); // Example: ['repo', 'user'] - const scopesList = scopes.split(' '); // Example: 'read:user repo user:email' - if (!scopesList.every(scope => { - const included = tokenScopes.includes(scope); - if (included || !scope.includes(':')) { - return included; - } - - return scope.split(':').some(splitScopes => { - return tokenScopes.includes(splitScopes); - }); - })) { - throw new Error(`The provided token does not match the requested scopes: ${scopes}`); - } - - return token; - } - - private async getScopes(token: string, serverUri: Uri, logger: Log): Promise { + let codeToExchange; try { - logger.info('Getting token scopes...'); - const result = await fetching(serverUri.toString(), { - headers: { - Authorization: `token ${token}`, - 'User-Agent': `${env.appName} (${env.appHost})` - } - }); - - if (result.ok) { - const scopes = result.headers.get('X-OAuth-Scopes'); - return scopes ? scopes.split(',').map(scope => scope.trim()) : []; - } else { - logger.error(`Getting scopes failed: ${result.statusText}`); - throw new Error(result.statusText); - } - } catch (ex) { - logger.error(ex.message); - throw new Error(NETWORK_ERROR); + env.openExternal(Uri.parse(`http://127.0.0.1:${port}/signin?nonce=${encodeURIComponent(server.nonce)}`)); + const { code } = await Promise.race([ + server.waitForOAuthResponse(), + new Promise((_, reject) => setTimeout(() => reject(TIMED_OUT_ERROR), 300_000)), // 5min timeout + promiseFromEvent(token.onCancellationRequested, (_, __, reject) => { reject(USER_CANCELLATION_ERROR); }).promise + ]); + codeToExchange = code; + } finally { + setTimeout(() => { + void server.stop(); + }, 5000); } + + const accessToken = await exchangeCodeForToken( + logger, + baseUri.with({ path: '/login/oauth/access_token' }), + redirectUri, + codeToExchange, + enterpriseUri); + return accessToken; + }); + } +} + +class DeviceCodeFlow implements IFlow { + label = l10n.t('device code'); + options: IFlowOptions = { + supportsGitHubDotCom: true, + supportsGitHubEnterpriseServer: true, + supportsHostedGitHubEnterprise: true, + supportsRemoteExtensionHost: true, + // CORS prevents this from working in web workers + supportsWebWorkerExtensionHost: false, + supportsNoClientSecret: true, + supportsSupportedClients: true, + supportsUnsupportedClients: true + }; + async trigger({ scopes, baseUri, logger }: IFlowTriggerOptions) { + logger.info(`Trying device code flow... (${scopes})`); + + // Get initial device code + const uri = baseUri.with({ + path: '/login/device/code', + query: `client_id=${Config.gitHubClientId}&scope=${scopes}` + }); + const result = await fetching(uri.toString(true), { + method: 'POST', + headers: { + Accept: 'application/json' + } + }); + if (!result.ok) { + throw new Error(`Failed to get one-time code: ${await result.text()}`); + } + + const json = await result.json() as IGitHubDeviceCodeResponse; + + const button = l10n.t('Copy & Continue to GitHub'); + const modalResult = await window.showInformationMessage( + l10n.t({ message: 'Your Code: {0}', args: [json.user_code], comment: ['The {0} will be a code, e.g. 123-456'] }), + { + modal: true, + detail: l10n.t('To finish authenticating, navigate to GitHub and paste in the above one-time code.') + }, button); + + if (modalResult !== button) { + throw new Error(USER_CANCELLATION_ERROR); + } + + await env.clipboard.writeText(json.user_code); + + const uriToOpen = await env.asExternalUri(Uri.parse(json.verification_uri)); + await env.openExternal(uriToOpen); + + return await this.waitForDeviceCodeAccessToken(baseUri, json); + } + + private async waitForDeviceCodeAccessToken( + baseUri: Uri, + json: IGitHubDeviceCodeResponse, + ): Promise { + return await window.withProgress({ + location: ProgressLocation.Notification, + cancellable: true, + title: l10n.t({ + message: 'Open [{0}]({0}) in a new tab and paste your one-time code: {1}', + args: [json.verification_uri, json.user_code], + comment: [ + 'The [{0}]({0}) will be a url and the {1} will be a code, e.g. 123-456', + '{Locked="[{0}]({0})"}' + ] + }) + }, async (_, token) => { + const refreshTokenUri = baseUri.with({ + path: '/login/oauth/access_token', + query: `client_id=${Config.gitHubClientId}&device_code=${json.device_code}&grant_type=urn:ietf:params:oauth:grant-type:device_code` + }); + + // Try for 2 minutes + const attempts = 120 / json.interval; + for (let i = 0; i < attempts; i++) { + await new Promise(resolve => setTimeout(resolve, json.interval * 1000)); + if (token.isCancellationRequested) { + throw new Error(USER_CANCELLATION_ERROR); + } + let accessTokenResult; + try { + accessTokenResult = await fetching(refreshTokenUri.toString(true), { + method: 'POST', + headers: { + Accept: 'application/json' + } + }); + } catch { + continue; + } + + if (!accessTokenResult.ok) { + continue; + } + + const accessTokenJson = await accessTokenResult.json(); + + if (accessTokenJson.error === 'authorization_pending') { + continue; + } + + if (accessTokenJson.error) { + throw new Error(accessTokenJson.error_description); + } + + return accessTokenJson.access_token; + } + + throw new Error(TIMED_OUT_ERROR); + }); + } +} + +class PatFlow implements IFlow { + label = l10n.t('personal access token'); + options: IFlowOptions = { + supportsGitHubDotCom: true, + supportsGitHubEnterpriseServer: true, + supportsHostedGitHubEnterprise: true, + supportsRemoteExtensionHost: true, + supportsWebWorkerExtensionHost: true, + supportsNoClientSecret: true, + // PATs can't be used with Settings Sync so we don't enable this flow + // for supported clients + supportsSupportedClients: false, + supportsUnsupportedClients: true + }; + + async trigger({ scopes, baseUri, logger, enterpriseUri }: IFlowTriggerOptions) { + logger.info(`Trying to retrieve PAT... (${scopes})`); + + const button = l10n.t('Continue to GitHub'); + const modalResult = await window.showInformationMessage( + l10n.t('Continue to GitHub to create a Personal Access Token (PAT)'), + { + modal: true, + detail: l10n.t('To finish authenticating, navigate to GitHub to create a PAT then paste the PAT into the input box.') + }, button); + + if (modalResult !== button) { + throw new Error(USER_CANCELLATION_ERROR); + } + + const description = `${env.appName} (${scopes})`; + const uriToOpen = await env.asExternalUri(baseUri.with({ path: '/settings/tokens/new', query: `description=${description}&scopes=${scopes.split(' ').join(',')}` })); + await env.openExternal(uriToOpen); + const token = await window.showInputBox({ placeHolder: `ghp_1a2b3c4...`, prompt: `GitHub Personal Access Token - ${scopes}`, ignoreFocusOut: true }); + if (!token) { throw new Error(USER_CANCELLATION_ERROR); } + + const appUri = !enterpriseUri || isHostedGitHubEnterprise(enterpriseUri) + ? Uri.parse(`${baseUri.scheme}://api.${baseUri.authority}`) + : Uri.parse(`${baseUri.scheme}://${baseUri.authority}/api/v3`); + + const tokenScopes = await this.getScopes(token, appUri, logger); // Example: ['repo', 'user'] + const scopesList = scopes.split(' '); // Example: 'read:user repo user:email' + if (!scopesList.every(scope => { + const included = tokenScopes.includes(scope); + if (included || !scope.includes(':')) { + return included; + } + + return scope.split(':').some(splitScopes => { + return tokenScopes.includes(splitScopes); + }); + })) { + throw new Error(`The provided token does not match the requested scopes: ${scopes}`); + } + + return token; + } + + private async getScopes(token: string, serverUri: Uri, logger: Log): Promise { + try { + logger.info('Getting token scopes...'); + const result = await fetching(serverUri.toString(), { + headers: { + Authorization: `token ${token}`, + 'User-Agent': `${env.appName} (${env.appHost})` + } + }); + + if (result.ok) { + const scopes = result.headers.get('X-OAuth-Scopes'); + return scopes ? scopes.split(',').map(scope => scope.trim()) : []; + } else { + logger.error(`Getting scopes failed: ${result.statusText}`); + throw new Error(result.statusText); + } + } catch (ex) { + logger.error(ex.message); + throw new Error(NETWORK_ERROR); } } +} + +const allFlows: IFlow[] = [ + new LocalServerFlow(), + new UrlHandlerFlow(), + new DeviceCodeFlow(), + new PatFlow() ]; export function getFlows(query: IFlowQuery) { diff --git a/extensions/github-authentication/src/node/authServer.ts b/extensions/github-authentication/src/node/authServer.ts index de08c6fca0f..989cf0d4223 100644 --- a/extensions/github-authentication/src/node/authServer.ts +++ b/extensions/github-authentication/src/node/authServer.ts @@ -82,7 +82,7 @@ export class LoopbackAuthServer implements ILoopbackServer { return this._startingRedirect.searchParams.get('state') ?? undefined; } - constructor(serveRoot: string, startingRedirect: string) { + constructor(serveRoot: string, startingRedirect: string, callbackUri: string) { if (!serveRoot) { throw new Error('serveRoot must be defined'); } @@ -126,7 +126,7 @@ export class LoopbackAuthServer implements ILoopbackServer { throw new Error('Nonce does not match.'); } deferred.resolve({ code, state }); - res.writeHead(302, { location: '/' }); + res.writeHead(302, { location: `/?redirect_uri=${encodeURIComponent(callbackUri)}` }); res.end(); break; } diff --git a/extensions/github-authentication/src/test/flows.test.ts b/extensions/github-authentication/src/test/flows.test.ts index 7f4963f4bd5..77c023e4819 100644 --- a/extensions/github-authentication/src/test/flows.test.ts +++ b/extensions/github-authentication/src/test/flows.test.ts @@ -34,8 +34,8 @@ suite('getFlows', () => { target: GitHubTarget.DotCom }, expectedFlows: [ - Flows.UrlHandlerFlow, Flows.LocalServerFlow, + Flows.UrlHandlerFlow, Flows.DeviceCodeFlow ] }, @@ -47,8 +47,8 @@ suite('getFlows', () => { target: GitHubTarget.HostedEnterprise }, expectedFlows: [ - Flows.UrlHandlerFlow, Flows.LocalServerFlow, + Flows.UrlHandlerFlow, Flows.DeviceCodeFlow, Flows.PatFlow ] diff --git a/extensions/github-authentication/src/test/node/authServer.test.ts b/extensions/github-authentication/src/test/node/authServer.test.ts index 6de8da61fda..1079300a502 100644 --- a/extensions/github-authentication/src/test/node/authServer.test.ts +++ b/extensions/github-authentication/src/test/node/authServer.test.ts @@ -11,7 +11,7 @@ suite('LoopbackAuthServer', () => { let port: number; setup(async () => { - server = new LoopbackAuthServer(__dirname, 'http://localhost:8080'); + server = new LoopbackAuthServer(__dirname, 'http://localhost:8080', 'https://code.visualstudio.com'); port = await server.start(); }); @@ -53,7 +53,7 @@ suite('LoopbackAuthServer', () => { { redirect: 'manual' } ); assert.strictEqual(response.status, 302); - assert.strictEqual(response.headers.get('location'), '/'); + assert.strictEqual(response.headers.get('location'), '/?redirect_uri=https%3A%2F%2Fcode.visualstudio.com'); await Promise.race([ server.waitForOAuthResponse().then(result => { assert.strictEqual(result.code, 'valid-code'); From 5547eb94df1cbe57fceb31142d023c48f6ece9d7 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 13 Jun 2025 00:29:59 -0700 Subject: [PATCH 230/236] chat: fix not notifying window on confirmation (#251292) Applies updated naming Ref https://github.com/microsoft/vscode/issues/251290 --- .../chat/browser/chatContentParts/chatConfirmationWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatConfirmationWidget.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatConfirmationWidget.ts index e5dd645e80b..061a92a0154 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatConfirmationWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatConfirmationWidget.ts @@ -176,7 +176,7 @@ abstract class BaseChatConfirmationWidget extends Disposable { protected renderMessage(element: HTMLElement, listContainer: HTMLElement): void { this.messageElement.append(element); - if (this._configurationService.getValue('chat.focusWindowOnConfirmation')) { + if (this._configurationService.getValue('chat.notifyWindowOnConfirmation')) { const targetWindow = dom.getWindow(listContainer); if (!targetWindow.document.hasFocus()) { this._hostService.focus(targetWindow, { mode: FocusMode.Notify }); From f0aef94f97813cd438226d1cfeedd37636bf4305 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Jun 2025 11:32:39 +0200 Subject: [PATCH 231/236] chat - update badge in dock to notify when window has no focus (#251358) --- .../windows/electron-main/windowImpl.ts | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index 78587bf0b8c..31d0dc59843 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -150,6 +150,8 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { this.dispose(); })); this._register(Event.fromNodeEventEmitter(win, 'focus')(() => { + this.clearFocusNotificationBadge(); + this._lastFocusTime = Date.now(); })); this._register(Event.fromNodeEventEmitter(this._win, 'enter-full-screen')(() => this._onDidEnterFullScreen.fire())); @@ -323,11 +325,21 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { case FocusMode.Notify: if (isMacintosh) { + this.setFocusNotificationBadge(undefined /* generic dot */); + + // On macOS we have direct API to bounce the dock icon electron.app.dock?.bounce('informational'); } else if (isWindows) { - // On Windows, this just flashes the taskbar icon, which is desired + this.setFocusNotificationBadge(undefined /* generic dot */); + + // On Windows, calling focus() will bounce the taskbar icon // https://github.com/electron/electron/issues/2867 this.win?.focus(); + } else if (isLinux) { + this.setFocusNotificationBadge(1 /* only number supported */); + + // On Linux, there seems to be no way to bounce the taskbar icon + // as calling focus() will actually steal focus away. } break; @@ -340,6 +352,20 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { } } + private hasFocusNotificationBadge = false; + + private setFocusNotificationBadge(count?: number): void { + electron.app.setBadgeCount(count); + this.hasFocusNotificationBadge = true; + } + + private clearFocusNotificationBadge(): void { + if (this.hasFocusNotificationBadge) { + electron.app.setBadgeCount(0); + this.hasFocusNotificationBadge = false; + } + } + private doFocusWindow() { const win = this.win; if (!win) { From ea92c32109b9fa7ae62582efdfd6089507073229 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 13 Jun 2025 13:41:51 +0200 Subject: [PATCH 232/236] Git - fix race condition with computing teh branch base (#251374) --- extensions/git/src/git.ts | 2 -- extensions/git/src/historyProvider.ts | 2 ++ extensions/git/src/repository.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 7f3da5090d5..e5ab4067248 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -16,7 +16,6 @@ import { CancellationError, CancellationToken, ConfigurationChangeEvent, LogOutp import { Commit as ApiCommit, Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, RefQuery as ApiRefQuery, InitOptions } from './api/git'; import * as byline from 'byline'; import { StringDecoder } from 'string_decoder'; -import { sequentialize } from './decorators'; // https://github.com/microsoft/vscode/issues/65693 const MAX_CLI_LENGTH = 30000; @@ -1242,7 +1241,6 @@ export class Repository { return this.git.spawn(args, options); } - @sequentialize async config(command: string, scope: string, key: string, value: any = null, options: SpawnOptions = {}): Promise { const args = ['config', `--${command}`]; diff --git a/extensions/git/src/historyProvider.ts b/extensions/git/src/historyProvider.ts index 1efd80585eb..9830928fcd3 100644 --- a/extensions/git/src/historyProvider.ts +++ b/extensions/git/src/historyProvider.ts @@ -13,6 +13,7 @@ import { emojify, ensureEmojis } from './emoji'; import { Commit } from './git'; import { OperationKind, OperationResult } from './operation'; import { ISourceControlHistoryItemDetailsProviderRegistry, provideSourceControlHistoryItemAvatar, provideSourceControlHistoryItemMessageLinks } from './historyItemDetailsProvider'; +import { throttle } from './decorators'; function compareSourceControlHistoryItemRef(ref1: SourceControlHistoryItemRef, ref2: SourceControlHistoryItemRef): number { const getOrder = (ref: SourceControlHistoryItemRef): number => { @@ -87,6 +88,7 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec this.commitShortHashLength = config.get('commitShortHashLength', 7); } + @throttle private async onDidRunWriteOperation(result: OperationResult): Promise { if (!this.repository.HEAD) { this.logger.trace('[GitHistoryProvider][onDidRunWriteOperation] repository.HEAD is undefined'); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 670e667c9f9..111561b665b 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -13,7 +13,7 @@ import { ApiRepository } from './api/api1'; import { Branch, BranchQuery, Change, CommitOptions, FetchOptions, ForcePushMode, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status } from './api/git'; import { AutoFetcher } from './autofetch'; import { GitBranchProtectionProvider, IBranchProtectionProviderRegistry } from './branchProtection'; -import { debounce, memoize, throttle } from './decorators'; +import { debounce, memoize, sequentialize, throttle } from './decorators'; import { Repository as BaseRepository, BlameInformation, Commit, GitError, LogFileOptions, LsTreeElement, PullOptions, RefQuery, Stash, Submodule } from './git'; import { GitHistoryProvider } from './historyProvider'; import { Operation, OperationKind, OperationManager, OperationResult } from './operation'; @@ -1554,6 +1554,7 @@ export class Repository implements Disposable { }); } + @sequentialize async getBranchBase(ref: string): Promise { const branch = await this.getBranch(ref); From 5d1bd8f13d9cd0d9c84ae96fd7a86f3fd51d6979 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Jun 2025 15:38:51 +0200 Subject: [PATCH 233/236] Revert "Fix extraction of tab title name" (#251379) * Revert "Fix extraction of tab title name (#250621)" This reverts commit ab6d98e59979694408744de691bd64b540ad8f0b. * skip test --- build/azure-pipelines/product-build.yml | 2 +- .../inlineChat/test/browser/inlineChatController.test.ts | 3 ++- test/automation/src/terminal.ts | 5 ++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 12e7b05d4ba..a6116d8c05c 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -337,7 +337,7 @@ extends: - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true),eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true),eq(parameters.VSCODE_BUILD_LINUX_ARM64, true),eq(parameters.VSCODE_BUILD_ALPINE, true),eq(parameters.VSCODE_BUILD_ALPINE_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}: - CompileCLI pool: - name: 1es-windows-2022-x64 + name: 1es-windows-2019-x64 os: windows jobs: - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts index b7cb3635c48..185e27616e3 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts @@ -77,6 +77,7 @@ import { IInlineChatSessionService } from '../../browser/inlineChatSessionServic import { InlineChatSessionServiceImpl } from '../../browser/inlineChatSessionServiceImpl.js'; import { CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatConfigKeys, InlineChatResponseType } from '../../common/inlineChat.js'; import { TestWorkerService } from './testWorkerService.js'; +import { isSafari, isWeb } from '../../../../../base/common/platform.js'; suite('InlineChatController', function () { @@ -667,7 +668,7 @@ suite('InlineChatController', function () { await r; }); - test('Clicking "re-run without /doc" while a request is in progress closes the widget #5997', async function () { + ((isWeb && isSafari) ? test.skip /* flaky */ : test)('Clicking "re-run without /doc" while a request is in progress closes the widget #5997', async function () { model.setValue(''); diff --git a/test/automation/src/terminal.ts b/test/automation/src/terminal.ts index af2a152fb81..214ca824f7c 100644 --- a/test/automation/src/terminal.ts +++ b/test/automation/src/terminal.ts @@ -17,7 +17,6 @@ export enum Selector { Xterm = `#terminal .terminal-wrapper`, XtermEditor = `.editor-instance .terminal-wrapper`, TabsEntry = '.terminal-tabs-entry', - Name = '.label-name', Description = '.label-description', XtermFocused = '.terminal.xterm.focus', PlusButton = '.codicon-plus', @@ -213,7 +212,7 @@ export class Terminal { const tabCount = (await this.code.waitForElements(Selector.Tabs, true)).length; const groups: TerminalGroup[] = []; for (let i = 0; i < tabCount; i++) { - const title = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry} ${Selector.Name}`, e => e?.textContent?.length ? e?.textContent?.length > 1 : false); + const title = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry}`, e => e?.textContent?.length ? e?.textContent?.length > 1 : false); const description: IElement | undefined = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry} ${Selector.Description}`, () => true); const label: TerminalLabel = { @@ -238,7 +237,7 @@ export class Terminal { private async assertTabExpected(selector?: string, listIndex?: number, nameRegex?: RegExp, icon?: string, color?: string, description?: string): Promise { if (listIndex) { if (nameRegex) { - await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry} ${Selector.Name}`, entry => !!entry && !!entry?.textContent.match(nameRegex)); + await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry}`, entry => !!entry && !!entry?.textContent.match(nameRegex)); if (description) { await this.code.waitForElement(`${Selector.Tabs}[data-index="${listIndex}"] ${Selector.TabsEntry} ${Selector.Description}`, e => !!e && e.textContent === description); } From 2c4bd5e3a732f317381d5f18ffcf8303d03bee1d Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Fri, 13 Jun 2025 14:28:53 +0000 Subject: [PATCH 234/236] feat: add middle mouse button scrolling (#245882) * feat: add middle scroll --------- Co-authored-by: Henning Dieterichs --- src/vs/editor/browser/observableCodeEditor.ts | 7 + src/vs/editor/browser/view/viewController.ts | 5 +- src/vs/editor/common/config/editorOptions.ts | 11 +- src/vs/editor/common/core/2d/point.ts | 23 +++ .../common/standalone/standaloneEnums.ts | 3 +- .../browser/model/animation.ts | 6 +- .../browser/middleScroll.contribution.ts | 9 ++ .../middleScroll/browser/middleScroll.css | 27 ++++ .../browser/middleScrollController.ts | 141 ++++++++++++++++++ src/vs/editor/editor.all.ts | 2 + src/vs/monaco.d.ts | 8 +- 11 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 src/vs/editor/contrib/middleScroll/browser/middleScroll.contribution.ts create mode 100644 src/vs/editor/contrib/middleScroll/browser/middleScroll.css create mode 100644 src/vs/editor/contrib/middleScroll/browser/middleScrollController.ts diff --git a/src/vs/editor/browser/observableCodeEditor.ts b/src/vs/editor/browser/observableCodeEditor.ts index a30f01dacc8..cf69c10810f 100644 --- a/src/vs/editor/browser/observableCodeEditor.ts +++ b/src/vs/editor/browser/observableCodeEditor.ts @@ -204,6 +204,11 @@ export class ObservableCodeEditor extends Disposable { this._endUpdate(); } })); + + this.domNode = derived(reader => { + this.model.read(reader); + return this.editor.getDomNode(); + }); } public forceUpdate(): void; @@ -273,6 +278,8 @@ export class ObservableCodeEditor extends Disposable { public readonly contentWidth; public readonly contentHeight; + public readonly domNode; + public getOption(id: T): IObservable> { return observableFromEvent(this, cb => this.editor.onDidChangeConfiguration(e => { if (e.hasChanged(id)) { cb(undefined); } diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index 5e53d12d2e4..18eb3d7df39 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -133,7 +133,10 @@ export class ViewController { const options = this.configuration.options; const selectionClipboardIsOn = (platform.isLinux && options.get(EditorOption.selectionClipboard)); const columnSelection = options.get(EditorOption.columnSelection); - if (data.middleButton && !selectionClipboardIsOn) { + const scrollOnMiddleClick = options.get(EditorOption.scrollOnMiddleClick); + if (data.middleButton && !selectionClipboardIsOn && scrollOnMiddleClick) { + // nothing to do here, handled in the contribution + } else if (data.middleButton && !selectionClipboardIsOn && columnSelection) { this._columnSelect(data.position, data.mouseColumn, data.inSelectionMode); } else if (data.startedOnLineNumbers) { // If the dragging started on the gutter, then have operations work on the entire line diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 035e449c231..db1ac7e59b1 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -294,6 +294,10 @@ export interface IEditorOptions { * Defaults to true. */ scrollBeyondLastLine?: boolean; + /** + * Scroll editor on middle click + */ + scrollOnMiddleClick?: boolean; /** * Enable that scrolling can go beyond the last column by a number of columns. * Defaults to 5. @@ -5657,7 +5661,8 @@ export const enum EditorOption { defaultColorDecorators, colorDecoratorsActivatedOn, inlineCompletionsAccessibilityVerbose, - effectiveEditContext + effectiveEditContext, + scrollOnMiddleClick, } export const EditorOptions = { @@ -6261,6 +6266,10 @@ export const EditorOptions = { EditorOption.scrollBeyondLastLine, 'scrollBeyondLastLine', true, { description: nls.localize('scrollBeyondLastLine', "Controls whether the editor will scroll beyond the last line.") } )), + scrollOnMiddleClick: register(new EditorBooleanOption( + EditorOption.scrollOnMiddleClick, 'scrollOnMiddleClick', false, + { description: nls.localize('scrollOnMiddleClick', "Controls whether the editor will scroll when the middle button is pressed.") } + )), scrollPredominantAxis: register(new EditorBooleanOption( EditorOption.scrollPredominantAxis, 'scrollPredominantAxis', true, { description: nls.localize('scrollPredominantAxis', "Scroll only along the predominant axis when scrolling both vertically and horizontally at the same time. Prevents horizontal drift when scrolling vertically on a trackpad.") } diff --git a/src/vs/editor/common/core/2d/point.ts b/src/vs/editor/common/core/2d/point.ts index 586367df62c..8b43c0d0595 100644 --- a/src/vs/editor/common/core/2d/point.ts +++ b/src/vs/editor/common/core/2d/point.ts @@ -28,4 +28,27 @@ export class Point { public toString() { return `(${this.x},${this.y})`; } + + public subtract(other: Point): Point { + return new Point(this.x - other.x, this.y - other.y); + } + + public scale(factor: number): Point { + return new Point(this.x * factor, this.y * factor); + } + + public mapComponents(map: (value: number) => number): Point { + return new Point(map(this.x), map(this.y)); + } + + public withThreshold(threshold: number): Point { + return this.mapComponents(axisVal => { + if (axisVal > threshold) { + return axisVal - threshold; + } else if (axisVal < -threshold) { + return axisVal + threshold; + } + return 0; + }); + } } diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index ba19d1861ee..6c05046a9b2 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -333,7 +333,8 @@ export enum EditorOption { defaultColorDecorators = 156, colorDecoratorsActivatedOn = 157, inlineCompletionsAccessibilityVerbose = 158, - effectiveEditContext = 159 + effectiveEditContext = 159, + scrollOnMiddleClick = 160 } /** diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/animation.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/animation.ts index 7b5ed388002..0f50d23385c 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/animation.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/animation.ts @@ -79,14 +79,14 @@ export class ObservableAnimatedValue { getValue(reader: IReader | undefined): number { const value = this._value.read(reader); if (!value.isFinished()) { - Scheduler.instance.invalidateOnNextAnimationFrame(reader); + AnimationFrameScheduler.instance.invalidateOnNextAnimationFrame(reader); } return value.getValue(); } } -class Scheduler { - public static instance = new Scheduler(); +export class AnimationFrameScheduler { + public static instance = new AnimationFrameScheduler(); private readonly _counter = observableSignal(this); diff --git a/src/vs/editor/contrib/middleScroll/browser/middleScroll.contribution.ts b/src/vs/editor/contrib/middleScroll/browser/middleScroll.contribution.ts new file mode 100644 index 00000000000..f82b1e3096f --- /dev/null +++ b/src/vs/editor/contrib/middleScroll/browser/middleScroll.contribution.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { EditorContributionInstantiation, registerEditorContribution } from '../../../browser/editorExtensions.js'; +import { MiddleScrollController } from './middleScrollController.js'; + +registerEditorContribution(MiddleScrollController.ID, MiddleScrollController, EditorContributionInstantiation.BeforeFirstInteraction); diff --git a/src/vs/editor/contrib/middleScroll/browser/middleScroll.css b/src/vs/editor/contrib/middleScroll/browser/middleScroll.css new file mode 100644 index 00000000000..2e68b82d4de --- /dev/null +++ b/src/vs/editor/contrib/middleScroll/browser/middleScroll.css @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-editor { + .scroll-editor-on-middle-click-dot { + cursor: all-scroll; + position: absolute; + z-index: 1; + background-color: var(--vscode-editor-foreground, white); + border: 1px solid var(--vscode-editor-background, black); + opacity: 0.5; + width: 5px; + height: 5px; + border-radius: 50%; + transform: translate(-50%, -50%); + + &.hidden { + display: none; + } + } + + &.scroll-editor-on-middle-click-editor * { + cursor: all-scroll; + } +} diff --git a/src/vs/editor/contrib/middleScroll/browser/middleScrollController.ts b/src/vs/editor/contrib/middleScroll/browser/middleScrollController.ts new file mode 100644 index 00000000000..28e7c22d621 --- /dev/null +++ b/src/vs/editor/contrib/middleScroll/browser/middleScrollController.ts @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { getWindow, addDisposableListener, n } from '../../../../base/browser/dom.js'; +import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; +import { ICodeEditor } from '../../../browser/editorBrowser.js'; +import { IEditorContribution, INewScrollPosition } from '../../../common/editorCommon.js'; +import { EditorOption } from '../../../common/config/editorOptions.js'; +import { autorun, derived, disposableObservableValue, IObservable, observableValue } from '../../../../base/common/observable.js'; +import { observableCodeEditor } from '../../../browser/observableCodeEditor.js'; +import { Point } from '../../../common/core/2d/point.js'; +import { AnimationFrameScheduler } from '../../inlineCompletions/browser/model/animation.js'; +import { appendRemoveOnDispose } from '../../../browser/widget/diffEditor/utils.js'; +import './middleScroll.css'; + +export class MiddleScrollController extends Disposable implements IEditorContribution { + public static readonly ID = 'editor.contrib.middleScroll'; + + static get(editor: ICodeEditor): MiddleScrollController | null { + return editor.getContribution(MiddleScrollController.ID); + } + + constructor( + private readonly _editor: ICodeEditor + ) { + super(); + + const obsEditor = observableCodeEditor(this._editor); + const scrollOnMiddleClick = obsEditor.getOption(EditorOption.scrollOnMiddleClick); + + this._register(autorun(reader => { + if (!scrollOnMiddleClick.read(reader)) { + return; + } + const editorDomNode = obsEditor.domNode.read(reader); + if (!editorDomNode) { + return; + } + + const scrollingSession = reader.store.add( + disposableObservableValue( + 'scrollingSession', + undefined as undefined | { mouseDeltaAfterThreshold: IObservable; initialMousePosInEditor: Point } & IDisposable + ) + ); + + reader.store.add(this._editor.onMouseDown(e => { + if (!e.event.middleButton) { + return; + } + e.event.stopPropagation(); + e.event.preventDefault(); + + const store = new DisposableStore(); + const initialPos = new Point(e.event.posx, e.event.posy); + const mousePos = observeWindowMousePos(getWindow(editorDomNode), initialPos, store); + const mouseDeltaAfterThreshold = mousePos.map(v => v.subtract(initialPos).withThreshold(5)); + + const editorDomNodeRect = editorDomNode.getBoundingClientRect(); + const initialMousePosInEditor = new Point(initialPos.x - editorDomNodeRect.left, initialPos.y - editorDomNodeRect.top); + + scrollingSession.set({ + mouseDeltaAfterThreshold, + initialMousePosInEditor, + dispose: () => store.dispose(), + }, undefined); + })); + + reader.store.add(this._editor.onMouseUp(e => { + scrollingSession.set(undefined, undefined); + })); + + reader.store.add(autorun(reader => { + const session = scrollingSession.read(reader); + if (!session) { + return; + } + + let lastTime = Date.now(); + reader.store.add(autorun(reader => { + AnimationFrameScheduler.instance.invalidateOnNextAnimationFrame(reader); + + const curTime = Date.now(); + const frameDurationMs = curTime - lastTime; + lastTime = curTime; + + const mouseDelta = session.mouseDeltaAfterThreshold.get(); + + // scroll by mouse delta every 32ms + const factor = frameDurationMs / 32; + const scrollDelta = mouseDelta.scale(factor); + + const scrollPos = new Point(this._editor.getScrollLeft(), this._editor.getScrollTop()); + this._editor.setScrollPosition(toScrollPosition(scrollPos.add(scrollDelta))); + })); + + const directionAttr = derived(reader => { + const delta = session.mouseDeltaAfterThreshold.read(reader); + let direction: string = ''; + direction += (delta.y < 0 ? 'n' : (delta.y > 0 ? 's' : '')); + direction += (delta.x < 0 ? 'w' : (delta.x > 0 ? 'e' : '')); + return direction; + }); + reader.store.add(autorun(reader => { + editorDomNode.setAttribute('data-scroll-direction', directionAttr.read(reader)); + })); + })); + + const dotDomElem = reader.store.add(n.div({ + class: ['scroll-editor-on-middle-click-dot', scrollingSession.map(session => session ? '' : 'hidden')], + style: { + left: scrollingSession.map((session) => session ? session.initialMousePosInEditor.x : 0), + top: scrollingSession.map((session) => session ? session.initialMousePosInEditor.y : 0), + } + }).toDisposableLiveElement()); + reader.store.add(appendRemoveOnDispose(editorDomNode, dotDomElem.element)); + + reader.store.add(autorun(reader => { + const session = scrollingSession.read(reader); + editorDomNode.classList.toggle('scroll-editor-on-middle-click-editor', !!session); + })); + })); + } +} + +function observeWindowMousePos(window: Window, initialPos: Point, store: DisposableStore): IObservable { + const val = observableValue('pos', initialPos); + store.add(addDisposableListener(window, 'mousemove', (e: MouseEvent) => { + val.set(new Point(e.pageX, e.pageY), undefined); + })); + return val; +} + +function toScrollPosition(p: Point): INewScrollPosition { + return { + scrollLeft: p.x, + scrollTop: p.y, + }; +} diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index 9edba1675a3..1f42a726b7a 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -41,6 +41,7 @@ import './contrib/linesOperations/browser/linesOperations.js'; import './contrib/linkedEditing/browser/linkedEditing.js'; import './contrib/links/browser/links.js'; import './contrib/longLinesHelper/browser/longLinesHelper.js'; +import './contrib/middleScroll/browser/middleScroll.contribution.js'; import './contrib/multicursor/browser/multicursor.js'; import './contrib/parameterHints/browser/parameterHints.js'; import './contrib/placeholderText/browser/placeholderText.contribution.js'; @@ -68,3 +69,4 @@ import './contrib/diffEditorBreadcrumbs/browser/contribution.js'; import './common/standaloneStrings.js'; import '../base/browser/ui/codicons/codiconStyles.js'; // The codicons are defined here and must be loaded + diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index b61ba153ebf..8960c3fc9b4 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3355,6 +3355,10 @@ declare namespace monaco.editor { * Defaults to true. */ scrollBeyondLastLine?: boolean; + /** + * Scroll editor on middle click + */ + scrollOnMiddleClick?: boolean; /** * Enable that scrolling can go beyond the last column by a number of columns. * Defaults to 5. @@ -5078,7 +5082,8 @@ declare namespace monaco.editor { defaultColorDecorators = 156, colorDecoratorsActivatedOn = 157, inlineCompletionsAccessibilityVerbose = 158, - effectiveEditContext = 159 + effectiveEditContext = 159, + scrollOnMiddleClick = 160 } export const EditorOptions: { @@ -5198,6 +5203,7 @@ declare namespace monaco.editor { scrollbar: IEditorOption; scrollBeyondLastColumn: IEditorOption; scrollBeyondLastLine: IEditorOption; + scrollOnMiddleClick: IEditorOption; scrollPredominantAxis: IEditorOption; selectionClipboard: IEditorOption; selectionHighlight: IEditorOption; From 292353090d28e55ddc271d35015bb654d9a10751 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Jun 2025 16:37:16 +0200 Subject: [PATCH 235/236] debt - inline `extpath.ts` into `pfs.ts` (#251388) --- src/vs/base/node/extpath.ts | 108 -------------- src/vs/base/node/pfs.ts | 138 +++++++++++++++--- src/vs/base/test/node/extpath.test.ts | 62 -------- src/vs/base/test/node/pfs/pfs.test.ts | 64 ++++---- .../node/watcher/nodejs/nodejsWatcherLib.ts | 3 +- .../node/watcher/parcel/parcelWatcher.ts | 4 +- .../electron-main/nativeHostMainService.ts | 3 +- .../api/node/extHostExtensionService.ts | 2 +- .../api/node/extensionHostProcess.ts | 3 +- 9 files changed, 157 insertions(+), 230 deletions(-) delete mode 100644 src/vs/base/node/extpath.ts delete mode 100644 src/vs/base/test/node/extpath.test.ts diff --git a/src/vs/base/node/extpath.ts b/src/vs/base/node/extpath.ts deleted file mode 100644 index 60fbdd6e4c7..00000000000 --- a/src/vs/base/node/extpath.ts +++ /dev/null @@ -1,108 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as fs from 'fs'; -import { CancellationToken } from '../common/cancellation.js'; -import { basename, dirname, join, normalize, sep } from '../common/path.js'; -import { isLinux } from '../common/platform.js'; -import { rtrim } from '../common/strings.js'; -import { Promises } from './pfs.js'; - -/** - * Copied from: https://github.com/microsoft/vscode-node-debug/blob/master/src/node/pathUtilities.ts#L83 - * - * Given an absolute, normalized, and existing file path 'realcase' returns the exact path that the file has on disk. - * On a case insensitive file system, the returned path might differ from the original path by character casing. - * On a case sensitive file system, the returned path will always be identical to the original path. - * In case of errors, null is returned. But you cannot use this function to verify that a path exists. - * realcase does not handle '..' or '.' path segments and it does not take the locale into account. - */ -export async function realcase(path: string, token?: CancellationToken): Promise { - if (isLinux) { - // This method is unsupported on OS that have case sensitive - // file system where the same path can exist in different forms - // (see also https://github.com/microsoft/vscode/issues/139709) - return path; - } - - const dir = dirname(path); - if (path === dir) { // end recursion - return path; - } - - const name = (basename(path) /* can be '' for windows drive letters */ || path).toLowerCase(); - try { - if (token?.isCancellationRequested) { - return null; - } - - const entries = await Promises.readdir(dir); - const found = entries.filter(e => e.toLowerCase() === name); // use a case insensitive search - if (found.length === 1) { - // on a case sensitive filesystem we cannot determine here, whether the file exists or not, hence we need the 'file exists' precondition - const prefix = await realcase(dir, token); // recurse - if (prefix) { - return join(prefix, found[0]); - } - } else if (found.length > 1) { - // must be a case sensitive $filesystem - const ix = found.indexOf(name); - if (ix >= 0) { // case sensitive - const prefix = await realcase(dir, token); // recurse - if (prefix) { - return join(prefix, found[ix]); - } - } - } - } catch (error) { - // silently ignore error - } - - return null; -} - -export async function realpath(path: string): Promise { - try { - // DO NOT USE `fs.promises.realpath` here as it internally - // calls `fs.native.realpath` which will result in subst - // drives to be resolved to their target on Windows - // https://github.com/microsoft/vscode/issues/118562 - return await Promises.realpath(path); - } catch (error) { - - // We hit an error calling fs.realpath(). Since fs.realpath() is doing some path normalization - // we now do a similar normalization and then try again if we can access the path with read - // permissions at least. If that succeeds, we return that path. - // fs.realpath() is resolving symlinks and that can fail in certain cases. The workaround is - // to not resolve links but to simply see if the path is read accessible or not. - const normalizedPath = normalizePath(path); - - await fs.promises.access(normalizedPath, fs.constants.R_OK); - - return normalizedPath; - } -} - -export function realpathSync(path: string): string { - try { - return fs.realpathSync(path); - } catch (error) { - - // We hit an error calling fs.realpathSync(). Since fs.realpathSync() is doing some path normalization - // we now do a similar normalization and then try again if we can access the path with read - // permissions at least. If that succeeds, we return that path. - // fs.realpath() is resolving symlinks and that can fail in certain cases. The workaround is - // to not resolve links but to simply see if the path is read accessible or not. - const normalizedPath = normalizePath(path); - - fs.accessSync(normalizedPath, fs.constants.R_OK); // throws in case of an error - - return normalizedPath; - } -} - -function normalizePath(path: string): string { - return rtrim(normalize(path), sep); -} diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index 052ec7fa1c7..cf76e466400 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -9,10 +9,12 @@ import { promisify } from 'util'; import { ResourceQueue, timeout } from '../common/async.js'; import { isEqualOrParent, isRootOrDriveLetter, randomPath } from '../common/extpath.js'; import { normalizeNFC } from '../common/normalization.js'; -import { join } from '../common/path.js'; +import { basename, dirname, join, normalize, sep } from '../common/path.js'; import { isLinux, isMacintosh, isWindows } from '../common/platform.js'; import { extUriBiasedIgnorePathCase } from '../common/resources.js'; import { URI } from '../common/uri.js'; +import { CancellationToken } from '../common/cancellation.js'; +import { rtrim } from '../common/strings.js'; //#region rimraf @@ -82,14 +84,6 @@ async function rimrafUnlink(path: string): Promise { return fs.promises.rm(path, { recursive: true, force: true, maxRetries: 3 }); } -export function rimrafSync(path: string): void { - if (isRootOrDriveLetter(path)) { - throw new Error('rimraf - will refuse to recursively delete root'); - } - - fs.rmSync(path, { recursive: true, force: true, maxRetries: 3 }); -} - //#endregion //#region readdir with NFC support (macos) @@ -154,15 +148,6 @@ async function safeReaddirWithFileTypes(path: string): Promise { return result; } -/** - * Drop-in replacement of `fs.readdirSync` with support - * for converting from macOS NFD unicon form to NFC - * (https://github.com/nodejs/node/issues/2165) - */ -export function readdirSync(path: string): string[] { - return handleDirectoryChildren(fs.readdirSync(path)); -} - function handleDirectoryChildren(children: string[]): string[]; function handleDirectoryChildren(children: IDirent[]): IDirent[]; function handleDirectoryChildren(children: (string | IDirent)[]): (string | IDirent)[]; @@ -437,6 +422,8 @@ function doWriteFileAndFlush(path: string, data: string | Buffer | Uint8Array, o * Same as `fs.writeFileSync` but with an additional call to * `fs.fdatasyncSync` after writing to ensure changes are * flushed to disk. + * + * @deprecated always prefer async variants over sync! */ export function writeFileSync(path: string, data: string | Buffer, options?: IWriteFileOptions): void { const ensuredOptions = ensureWriteOptions(options); @@ -657,6 +644,113 @@ async function doCopySymlink(source: string, target: string, payload: ICopyPaylo //#endregion +//#region Path resolvers + +/** + * Given an absolute, normalized, and existing file path 'realcase' returns the + * exact path that the file has on disk. + * On a case insensitive file system, the returned path might differ from the original + * path by character casing. + * On a case sensitive file system, the returned path will always be identical to the + * original path. + * In case of errors, null is returned. But you cannot use this function to verify that + * a path exists. + * + * realcase does not handle '..' or '.' path segments and it does not take the locale into account. + */ +export async function realcase(path: string, token?: CancellationToken): Promise { + if (isLinux) { + // This method is unsupported on OS that have case sensitive + // file system where the same path can exist in different forms + // (see also https://github.com/microsoft/vscode/issues/139709) + return path; + } + + const dir = dirname(path); + if (path === dir) { // end recursion + return path; + } + + const name = (basename(path) /* can be '' for windows drive letters */ || path).toLowerCase(); + try { + if (token?.isCancellationRequested) { + return null; + } + + const entries = await Promises.readdir(dir); + const found = entries.filter(e => e.toLowerCase() === name); // use a case insensitive search + if (found.length === 1) { + // on a case sensitive filesystem we cannot determine here, whether the file exists or not, hence we need the 'file exists' precondition + const prefix = await realcase(dir, token); // recurse + if (prefix) { + return join(prefix, found[0]); + } + } else if (found.length > 1) { + // must be a case sensitive $filesystem + const ix = found.indexOf(name); + if (ix >= 0) { // case sensitive + const prefix = await realcase(dir, token); // recurse + if (prefix) { + return join(prefix, found[ix]); + } + } + } + } catch (error) { + // silently ignore error + } + + return null; +} + +async function realpath(path: string): Promise { + try { + // DO NOT USE `fs.promises.realpath` here as it internally + // calls `fs.native.realpath` which will result in subst + // drives to be resolved to their target on Windows + // https://github.com/microsoft/vscode/issues/118562 + return await promisify(fs.realpath)(path); + } catch (error) { + + // We hit an error calling fs.realpath(). Since fs.realpath() is doing some path normalization + // we now do a similar normalization and then try again if we can access the path with read + // permissions at least. If that succeeds, we return that path. + // fs.realpath() is resolving symlinks and that can fail in certain cases. The workaround is + // to not resolve links but to simply see if the path is read accessible or not. + const normalizedPath = normalizePath(path); + + await fs.promises.access(normalizedPath, fs.constants.R_OK); + + return normalizedPath; + } +} + +/** + * @deprecated always prefer async variants over sync! + */ +export function realpathSync(path: string): string { + try { + return fs.realpathSync(path); + } catch (error) { + + // We hit an error calling fs.realpathSync(). Since fs.realpathSync() is doing some path normalization + // we now do a similar normalization and then try again if we can access the path with read + // permissions at least. If that succeeds, we return that path. + // fs.realpath() is resolving symlinks and that can fail in certain cases. The workaround is + // to not resolve links but to simply see if the path is read accessible or not. + const normalizedPath = normalizePath(path); + + fs.accessSync(normalizedPath, fs.constants.R_OK); // throws in case of an error + + return normalizedPath; + } +} + +function normalizePath(path: string): string { + return rtrim(normalize(path), sep); +} + +//#endregion + //#region Promise based fs methods /** @@ -711,14 +805,12 @@ export const Promises = new class { }; } - get fdatasync() { return promisify(fs.fdatasync); } // not exposed as API in 20.x yet + get fdatasync() { return promisify(fs.fdatasync); } // not exposed as API in 22.x yet get open() { return promisify(fs.open); } // changed to return `FileHandle` in promise API get close() { return promisify(fs.close); } // not exposed as API due to the `FileHandle` return type of `open` - get realpath() { return promisify(fs.realpath); } // `fs.promises.realpath` will use `fs.realpath.native` which we do not want - - get ftruncate() { return promisify(fs.ftruncate); } // not exposed as API in 20.x yet + get ftruncate() { return promisify(fs.ftruncate); } // not exposed as API in 22.x yet //#endregion @@ -744,6 +836,8 @@ export const Promises = new class { get rename() { return rename; } get copy() { return copy; } + get realpath() { return realpath; } // `fs.promises.realpath` will use `fs.realpath.native` which we do not want + //#endregion }; diff --git a/src/vs/base/test/node/extpath.test.ts b/src/vs/base/test/node/extpath.test.ts deleted file mode 100644 index c86f3cea0d1..00000000000 --- a/src/vs/base/test/node/extpath.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as fs from 'fs'; -import assert from 'assert'; -import { tmpdir } from 'os'; -import { realcase, realpath, realpathSync } from '../../node/extpath.js'; -import { Promises } from '../../node/pfs.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../common/utils.js'; -import { flakySuite, getRandomTestPath } from './testUtils.js'; - -flakySuite('Extpath', () => { - let testDir: string; - - setup(() => { - testDir = getRandomTestPath(tmpdir(), 'vsctests', 'extpath'); - - return fs.promises.mkdir(testDir, { recursive: true }); - }); - - teardown(() => { - return Promises.rm(testDir); - }); - - test('realcase', async () => { - - // assume case insensitive file system - if (process.platform === 'win32' || process.platform === 'darwin') { - const upper = testDir.toUpperCase(); - const real = await realcase(upper); - - if (real) { // can be null in case of permission errors - assert.notStrictEqual(real, upper); - assert.strictEqual(real.toUpperCase(), upper); - assert.strictEqual(real, testDir); - } - } - - // linux, unix, etc. -> assume case sensitive file system - else { - let real = await realcase(testDir); - assert.strictEqual(real, testDir); - - real = await realcase(testDir.toUpperCase()); - assert.strictEqual(real, testDir.toUpperCase()); - } - }); - - test('realpath', async () => { - const realpathVal = await realpath(testDir); - assert.ok(realpathVal); - }); - - test('realpathSync', () => { - const realpath = realpathSync(testDir); - assert.ok(realpath); - }); - - ensureNoDisposablesAreLeakedInTestSuite(); -}); diff --git a/src/vs/base/test/node/pfs/pfs.test.ts b/src/vs/base/test/node/pfs/pfs.test.ts index 1cc0b17f24d..3574bef988d 100644 --- a/src/vs/base/test/node/pfs/pfs.test.ts +++ b/src/vs/base/test/node/pfs/pfs.test.ts @@ -12,7 +12,7 @@ import { randomPath } from '../../../common/extpath.js'; import { FileAccess } from '../../../common/network.js'; import { basename, dirname, join, sep } from '../../../common/path.js'; import { isWindows } from '../../../common/platform.js'; -import { configureFlushOnWrite, Promises, RimRafMode, rimrafSync, SymlinkSupport, writeFileSync } from '../../../node/pfs.js'; +import { configureFlushOnWrite, Promises, realcase, realpathSync, RimRafMode, SymlinkSupport, writeFileSync } from '../../../node/pfs.js'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../common/utils.js'; import { flakySuite, getRandomTestPath } from '../testUtils.js'; @@ -146,34 +146,6 @@ flakySuite('PFS', function () { assert.ok(!fs.existsSync(testDir)); }); - test('rimrafSync - swallows file not found error', function () { - const nonExistingDir = join(testDir, 'not-existing'); - rimrafSync(nonExistingDir); - - assert.ok(!fs.existsSync(nonExistingDir)); - }); - - test('rimrafSync - simple', async () => { - fs.writeFileSync(join(testDir, 'somefile.txt'), 'Contents'); - fs.writeFileSync(join(testDir, 'someOtherFile.txt'), 'Contents'); - - rimrafSync(testDir); - - assert.ok(!fs.existsSync(testDir)); - }); - - test('rimrafSync - recursive folder structure', async () => { - fs.writeFileSync(join(testDir, 'somefile.txt'), 'Contents'); - fs.writeFileSync(join(testDir, 'someOtherFile.txt'), 'Contents'); - - fs.mkdirSync(join(testDir, 'somefolder')); - fs.writeFileSync(join(testDir, 'somefolder', 'somefile.txt'), 'Contents'); - - rimrafSync(testDir); - - assert.ok(!fs.existsSync(testDir)); - }); - test('copy, rename and delete', async () => { const sourceDir = FileAccess.asFileUri('vs/base/test/node/pfs/fixtures').fsPath; const parentDir = join(tmpdir(), 'vsctests', 'pfs'); @@ -490,5 +462,39 @@ flakySuite('PFS', function () { assert.strictEqual(fs.readFileSync(testFile).toString(), largeString); }); + test('realcase', async () => { + + // assume case insensitive file system + if (process.platform === 'win32' || process.platform === 'darwin') { + const upper = testDir.toUpperCase(); + const real = await realcase(upper); + + if (real) { // can be null in case of permission errors + assert.notStrictEqual(real, upper); + assert.strictEqual(real.toUpperCase(), upper); + assert.strictEqual(real, testDir); + } + } + + // linux, unix, etc. -> assume case sensitive file system + else { + let real = await realcase(testDir); + assert.strictEqual(real, testDir); + + real = await realcase(testDir.toUpperCase()); + assert.strictEqual(real, testDir.toUpperCase()); + } + }); + + test('realpath', async () => { + const realpathVal = await Promises.realpath(testDir); + assert.ok(realpathVal); + }); + + test('realpathSync', () => { + const realpath = realpathSync(testDir); + assert.ok(realpath); + }); + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts b/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts index 26a54be46ff..5484ddc3a4d 100644 --- a/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts +++ b/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts @@ -13,7 +13,6 @@ import { basename, dirname, join } from '../../../../../base/common/path.js'; import { isLinux, isMacintosh } from '../../../../../base/common/platform.js'; import { joinPath } from '../../../../../base/common/resources.js'; import { URI } from '../../../../../base/common/uri.js'; -import { realpath } from '../../../../../base/node/extpath.js'; import { Promises } from '../../../../../base/node/pfs.js'; import { FileChangeFilter, FileChangeType, IFileChange } from '../../../common/files.js'; import { ILogMessage, coalesceEvents, INonRecursiveWatchRequest, parseWatcherPatterns, IRecursiveWatcherWithSubscribe, isFiltered, isWatchRequestWithCorrelation } from '../../../common/watcher.js'; @@ -67,7 +66,7 @@ export class NodeJSFileWatcherLibrary extends Disposable { let result = this.request.path; try { - result = await realpath(this.request.path); + result = await Promises.realpath(this.request.path); if (this.request.path !== result) { this.trace(`correcting a path to watch that seems to be a symbolic link (original: ${this.request.path}, real: ${result})`); diff --git a/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts b/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts index f57af9c5b7a..dce2f4db700 100644 --- a/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts +++ b/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts @@ -18,7 +18,7 @@ import { TernarySearchTree } from '../../../../../base/common/ternarySearchTree. import { normalizeNFC } from '../../../../../base/common/normalization.js'; import { normalize, join } from '../../../../../base/common/path.js'; import { isLinux, isMacintosh, isWindows } from '../../../../../base/common/platform.js'; -import { realcase, realpath } from '../../../../../base/node/extpath.js'; +import { Promises, realcase } from '../../../../../base/node/pfs.js'; import { FileChangeType, IFileChange } from '../../../common/files.js'; import { coalesceEvents, IRecursiveWatchRequest, parseWatcherPatterns, IRecursiveWatcherWithSubscribe, isFiltered, IWatcherErrorEvent } from '../../../common/watcher.js'; import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; @@ -492,7 +492,7 @@ export class ParcelWatcher extends BaseWatcher implements IRecursiveWatcherWithS try { // First check for symbolic link - realPath = await realpath(request.path); + realPath = await Promises.realpath(request.path); // Second check for casing difference // Note: this will be a no-op on Linux platforms diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 37ecd52d628..f3d2fbc9a57 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -16,7 +16,6 @@ import { dirname, join, posix, resolve, win32 } from '../../../base/common/path. import { isLinux, isMacintosh, isWindows } from '../../../base/common/platform.js'; import { AddFirstParameterToFunctions } from '../../../base/common/types.js'; import { URI } from '../../../base/common/uri.js'; -import { realpath } from '../../../base/node/extpath.js'; import { virtualMachineHint } from '../../../base/node/id.js'; import { Promises, SymlinkSupport } from '../../../base/node/pfs.js'; import { findFreePort, isPortFree } from '../../../base/node/ports.js'; @@ -384,7 +383,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain try { const { symbolicLink } = await SymlinkSupport.stat(source); if (symbolicLink && !symbolicLink.dangling) { - const linkTargetRealPath = await realpath(source); + const linkTargetRealPath = await Promises.realpath(source); if (target === linkTargetRealPath) { return; } diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index edc1452c76d..92cf4652104 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -16,7 +16,7 @@ import { Schemas } from '../../../base/common/network.js'; import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js'; import { ExtensionRuntime } from '../common/extHostTypes.js'; import { CLIServer } from './extHostCLIServer.js'; -import { realpathSync } from '../../../base/node/extpath.js'; +import { realpathSync } from '../../../base/node/pfs.js'; import { ExtHostConsoleForwarder } from './extHostConsoleForwarder.js'; import { ExtHostDiskFileSystemProvider } from './extHostDiskFileSystemProvider.js'; import nodeModule from 'node:module'; diff --git a/src/vs/workbench/api/node/extensionHostProcess.ts b/src/vs/workbench/api/node/extensionHostProcess.ts index 079bc9989a4..533e0228cbc 100644 --- a/src/vs/workbench/api/node/extensionHostProcess.ts +++ b/src/vs/workbench/api/node/extensionHostProcess.ts @@ -12,7 +12,6 @@ import { PendingMigrationError, isCancellationError, isSigPipeError, onUnexpecte import { Event } from '../../../base/common/event.js'; import * as performance from '../../../base/common/performance.js'; import { IURITransformer } from '../../../base/common/uriIpc.js'; -import { realpath } from '../../../base/node/extpath.js'; import { Promises } from '../../../base/node/pfs.js'; import { IMessagePassingProtocol } from '../../../base/parts/ipc/common/ipc.js'; import { BufferedEmitter, PersistentProtocol, ProtocolConstants } from '../../../base/parts/ipc/common/ipc.net.js'; @@ -420,7 +419,7 @@ async function startExtensionHostProcess(): Promise { public readonly pid = process.pid; exit(code: number) { nativeExit(code); } fsExists(path: string) { return Promises.exists(path); } - fsRealpath(path: string) { return realpath(path); } + fsRealpath(path: string) { return Promises.realpath(path); } }; // Attempt to load uri transformer From fafd5bfd8087fe01977276c1adeb86ec382d3a69 Mon Sep 17 00:00:00 2001 From: Aaron Munger <2019016+amunger@users.noreply.github.com> Date: Fri, 13 Jun 2025 07:39:47 -0700 Subject: [PATCH 236/236] update widget aria label on title switch (#251017) * widget aria label is also observable * update the aria label * fix initialization * remove unused getter --- src/vs/base/browser/ui/list/listPaging.ts | 2 +- src/vs/base/browser/ui/list/listWidget.ts | 9 +++++++-- .../notebookVariables/notebookVariablesTree.ts | 12 ++++++++++-- .../notebookVariables/notebookVariablesView.ts | 6 +++++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 736a1d727a9..cb486cfaaba 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -77,7 +77,7 @@ class PagedAccessibilityProvider implements IListAccessibilityProvider ) { } - getWidgetAriaLabel(): string { + getWidgetAriaLabel() { return this.accessibilityProvider.getWidgetAriaLabel(); } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index e464d9fca7e..96865619e88 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -856,7 +856,7 @@ export interface IStyleController { export interface IListAccessibilityProvider extends IListViewAccessibilityProvider { getAriaLabel(element: T): string | IObservable | null; - getWidgetAriaLabel(): string; + getWidgetAriaLabel(): string | IObservable; getWidgetRole?(): AriaRole; getAriaLevel?(element: T): number | undefined; onDidChangeActiveDescendant?: Event; @@ -1530,7 +1530,12 @@ export class List implements ISpliceable, IDisposable { this.onDidChangeSelection(this._onSelectionChange, this, this.disposables); if (this.accessibilityProvider) { - this.ariaLabel = this.accessibilityProvider.getWidgetAriaLabel(); + const ariaLabel = this.accessibilityProvider.getWidgetAriaLabel(); + const observable = (ariaLabel && typeof ariaLabel !== 'string') ? ariaLabel : constObservable(ariaLabel); + + this.disposables.add(autorun(reader => { + this.ariaLabel = reader.readObservable(observable); + })); } if (this._options.multipleSelectionSupport !== false) { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesTree.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesTree.ts index a8dc1d801d8..715e2220a23 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesTree.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesTree.ts @@ -9,11 +9,13 @@ import { IListAccessibilityProvider } from '../../../../../../base/browser/ui/li import { ITreeNode, ITreeRenderer } from '../../../../../../base/browser/ui/tree/tree.js'; import { FuzzyScore } from '../../../../../../base/common/filters.js'; import { DisposableStore } from '../../../../../../base/common/lifecycle.js'; +import { observableValue } from '../../../../../../base/common/observable.js'; import { localize } from '../../../../../../nls.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { WorkbenchObjectTree } from '../../../../../../platform/list/browser/listService.js'; import { DebugExpressionRenderer } from '../../../../debug/browser/debugExpressionRenderer.js'; import { INotebookVariableElement } from './notebookVariablesDataSource.js'; +import { NotebookVariablesView } from './notebookVariablesView.js'; const $ = dom.$; const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024; @@ -86,8 +88,14 @@ export class NotebookVariableRenderer implements ITreeRenderer { - getWidgetAriaLabel(): string { - return localize('debugConsole', "Notebook Variables"); + private _widgetAriaLabel = observableValue('widgetAriaLabel', NotebookVariablesView.NOTEBOOK_TITLE.value); + + getWidgetAriaLabel() { + return this._widgetAriaLabel; + } + + updateWidgetAriaLabel(label: string): void { + this._widgetAriaLabel.set(label, undefined); } getAriaLabel(element: INotebookVariableElement): string { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesView.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesView.ts index dc86e5ba940..80f65399122 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesView.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariablesView.ts @@ -45,6 +45,7 @@ export class NotebookVariablesView extends ViewPane { private tree: WorkbenchAsyncDataTree | undefined; private activeNotebook: NotebookTextModel | undefined; private readonly dataSource: NotebookVariableDataSource; + private readonly accessibilityProvider: NotebookVariableAccessibilityProvider; private updateScheduler: RunOnceScheduler; @@ -73,6 +74,7 @@ export class NotebookVariablesView extends ViewPane { this._register(this.notebookExecutionStateService.onDidChangeExecution(this.handleExecutionStateChange.bind(this))); this._register(this.editorService.onDidCloseEditor((e) => this.handleCloseEditor(e))); + this.accessibilityProvider = new NotebookVariableAccessibilityProvider(); this.handleActiveEditorChange(false); this.dataSource = new NotebookVariableDataSource(this.notebookKernelService); @@ -91,7 +93,7 @@ export class NotebookVariablesView extends ViewPane { [this.instantiationService.createInstance(NotebookVariableRenderer)], this.dataSource, { - accessibilityProvider: new NotebookVariableAccessibilityProvider(), + accessibilityProvider: this.accessibilityProvider, identityProvider: { getId: (e: INotebookVariableElement) => e.id }, }); @@ -150,8 +152,10 @@ export class NotebookVariablesView extends ViewPane { if (isCompositeNotebookEditorInput(editor.input)) { this.updateTitle(NotebookVariablesView.REPL_TITLE.value); + this.accessibilityProvider.updateWidgetAriaLabel(NotebookVariablesView.REPL_TITLE.value); } else { this.updateTitle(NotebookVariablesView.NOTEBOOK_TITLE.value); + this.accessibilityProvider.updateWidgetAriaLabel(NotebookVariablesView.NOTEBOOK_TITLE.value); } if (doUpdate) {