import { assertAllDefined, assertIsDefined } from 'vs/base/common/types'; import { NotificationsCenterVisibleContext } from 'vs/workbench/common/contextkeys'; import { INotificationService } from 'vs/platform/notification/common/notification'; <ins> import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; </ins> export class NotificationsCenter extends Themable implements INotificationsCenterController {


@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IKeybindingService private readonly keybindingService: IKeybindingService, @INotificationService private readonly notificationService: INotificationService, <ins> @IAccessibleNotificationService private readonly accessibleNotificationService: IAccessibleNotificationService </ins> ) { super(themeService);


if (!notification.hasProgress) { notification.close(); } <ins> this.accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); </ins> } } }


import { ActionRunner, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { hash } from 'vs/base/common/hash'; import { firstOrDefault } from 'vs/base/common/arrays'; <ins> import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; </ins> // Center export const SHOW_NOTIFICATIONS_CENTER = 'notifications.showList';


primary: KeyMod.CtrlCmd | KeyCode.Backspace }, handler: (accessor, args?) => { <ins> const accessibleNotificationService = accessor.get(IAccessibleNotificationService); </ins> const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification && !notification.hasProgress) { notification.close(); <ins> accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); </ins> } } });


this.stateModel.setRuntimeValue(LayoutStateKeys.EDITOR_HIDDEN, false); } <del> // Activity bar cannot be hidden if (this.stateModel.getRuntimeValue(LayoutStateKeys.ACTIVITYBAR_HIDDEN) && !this.canActivityBarBeHidden()) { this.stateModel.setRuntimeValue(LayoutStateKeys.ACTIVITYBAR_HIDDEN, false); } </del> this.stateModel.onDidChangeState(change => { if (change.key === LayoutStateKeys.ACTIVITYBAR_HIDDEN) { this.setActivityBarHidden(change.value as boolean);


} } <ins> // Activity bar cannot be hidden // This check must be called after state is set // because canActivityBarBeHidden calls isVisible if (this.stateModel.getRuntimeValue(LayoutStateKeys.ACTIVITYBAR_HIDDEN) && !this.canActivityBarBeHidden()) { this.stateModel.setRuntimeValue(LayoutStateKeys.ACTIVITYBAR_HIDDEN, false); } </ins> // Window border this.updateWindowBorder(true); }


export function parseAuthorityWithPort(authority: string): { host: string; port: number } { const { host, port } = parseAuthority(authority); if (typeof port === 'undefined') { <del> throw new Error(`Remote authority doesn't contain a port!`); </del> <ins> throw new Error(`Invalid remote authority: ${authority}. It must either be a remote of form <remoteName>+<arg> or a remote host of form <host>:<port>.`); </ins> } return { host, port }; }


"textCodeBlock.background": "#2B2B2B", "textLink.activeForeground": "#4daafc", "textLink.foreground": "#4daafc", <del> "textPreformat.foreground": "#D0D0D0", </del> <ins> "textPreformat.foreground": "#D7BA7D", </ins> "textPreformat.background": "#3C3C3C", "textSeparator.foreground": "#21262D", "titleBar.activeBackground": "#181818",


"textCodeBlock.background": "#F8F8F8", "textLink.activeForeground": "#005FB8", "textLink.foreground": "#005FB8", <del> "textPreformat.foreground": "#3B3B3B", </del> <ins> "textPreformat.foreground": "#A31515", </ins> "textPreformat.background":	"#0000001F", "textSeparator.foreground": "#21262D", "titleBar.activeBackground": "#F8F8F8",


export const textSeparatorForeground = registerColor('textSeparator.foreground', { light: '#0000002e', dark: '#ffffff2e', hcDark: Color.black, hcLight: '#292929' }, nls.localize('textSeparatorForeground', "Color for text separators.")); export const textLinkForeground = registerColor('textLink.foreground', { light: '#006AB1', dark: '#3794FF', hcDark: '#3794FF', hcLight: '#0F4A85' }, nls.localize('textLinkForeground', "Foreground color for links in text.")); export const textLinkActiveForeground = registerColor('textLink.activeForeground', { light: '#006AB1', dark: '#3794FF', hcDark: '#3794FF', hcLight: '#0F4A85' }, nls.localize('textLinkActiveForeground', "Foreground color for links in text when clicked on and on mouse hover.")); <del> export const textPreformatForeground = registerColor('textPreformat.foreground', { light: '#A31515', dark: '#D7BA7D', hcDark: '#000000', hcLight: '#FFFFFF' }, nls.localize('textPreformatForeground', "Foreground color for preformatted text segments.")); </del> <ins> export const textPreformatForeground = registerColor('textPreformat.foreground', { light: '#A31515', dark: '#D7BA7D', hcDark: '#D7BA7D', hcLight: '#292929' }, nls.localize('textPreformatForeground', "Foreground color for preformatted text segments.")); </ins> export const textPreformatBackground = registerColor('textPreformat.background', { light: '#0000001A', dark: '#FFFFFF1A', hcDark: '#FFFFFF', hcLight: '#09345f' }, nls.localize('textPreformatBackground', "Background color for preformatted text segments.")); export const textBlockQuoteBackground = registerColor('textBlockQuote.background', { light: '#f2f2f2', dark: '#222222', hcDark: null, hcLight: '#F2F2F2' }, nls.localize('textBlockQuoteBackground', "Background color for block quotes in text.")); export const textBlockQuoteBorder = registerColor('textBlockQuote.border', { light: '#007acc80', dark: '#007acc80', hcDark: Color.white, hcLight: '#292929' }, nls.localize('textBlockQuoteBorder', "Border color for block quotes in text."));


font-family: var(--monaco-monospace-font); font-size: 12px; color: var(--vscode-textPreformat-foreground); <del> background-color: var(--vscode-textPreformat-background); </del> padding: 1px 3px; border-radius: 4px; }


font-family: var(--monaco-monospace-font); font-size: 11px; color: var(--vscode-textPreformat-foreground); <del> background-color: var(--vscode-textPreformat-background); </del> padding: 1px 3px; border-radius: 4px; }


font-family: var(--monaco-monospace-font); font-size: 12px; color: var(--vscode-textPreformat-foreground); <del> background-color: var(--vscode-textPreformat-background); </del> padding: 2px 5px; border-radius: 4px; }


IFS=':' read -ra ADDR <<< "$VSCODE_ENV_REPLACE" for ITEM in "${ADDR[@]}"; do VARNAME="$(echo $ITEM | cut -d "=" -f 1)" <del> VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2)" </del> <ins> VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2-)" </ins> export $VARNAME="$VALUE" done builtin unset VSCODE_ENV_REPLACE


IFS=':' read -ra ADDR <<< "$VSCODE_ENV_PREPEND" for ITEM in "${ADDR[@]}"; do VARNAME="$(echo $ITEM | cut -d "=" -f 1)" <del> VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2)" </del> <ins> VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2-)" </ins> export $VARNAME="$VALUE${!VARNAME}" done builtin unset VSCODE_ENV_PREPEND


IFS=':' read -ra ADDR <<< "$VSCODE_ENV_APPEND" for ITEM in "${ADDR[@]}"; do VARNAME="$(echo $ITEM | cut -d "=" -f 1)" <del> VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2)" </del> <ins> VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2-)" </ins> export $VARNAME="${!VARNAME}$VALUE" done builtin unset VSCODE_ENV_APPEND


if ($env:VSCODE_ENV_REPLACE) { $Split = $env:VSCODE_ENV_REPLACE.Split(":") foreach ($Item in $Split) { <del> $Inner = $Item.Split('=') </del> <ins> $Inner = $Item.Split('=', 2) </ins> [Environment]::SetEnvironmentVariable($Inner[0], $Inner[1].Replace('x3a', ':')) } $env:VSCODE_ENV_REPLACE = $null


if ($env:VSCODE_ENV_PREPEND) { $Split = $env:VSCODE_ENV_PREPEND.Split(":") foreach ($Item in $Split) { <del> $Inner = $Item.Split('=') </del> <ins> $Inner = $Item.Split('=', 2) </ins> [Environment]::SetEnvironmentVariable($Inner[0], $Inner[1].Replace('x3a', ':') + [Environment]::GetEnvironmentVariable($Inner[0])) } $env:VSCODE_ENV_PREPEND = $null


if ($env:VSCODE_ENV_APPEND) { $Split = $env:VSCODE_ENV_APPEND.Split(":") foreach ($Item in $Split) { <del> $Inner = $Item.Split('=') </del> <ins> $Inner = $Item.Split('=', 2) </ins> [Environment]::SetEnvironmentVariable($Inner[0], [Environment]::GetEnvironmentVariable($Inner[0]) + $Inner[1].Replace('x3a', ':')) } $env:VSCODE_ENV_APPEND = $null


private _removeAllDecorations(): void { const currentEditors = this.codeEditorService.listCodeEditors(); <ins> const deleteURI = []; </ins> // iterate over editors and store models in currentModels for (const editor of currentEditors) { if (!editor.hasModel()) {


} editor.removeDecorations(currentDecorationIDs); <del> WordHighlighter.storedDecorations.delete(editor.getModel().uri); </del> <ins> deleteURI.push(editor.getModel().uri); </ins> const editorHighlighterContrib = WordHighlighterContribution.get(editor); if (!editorHighlighterContrib?.wordHighlighter) {


editorHighlighterContrib.wordHighlighter._hasWordHighlights.set(false); } } <ins> for (const uri of deleteURI) { WordHighlighter.storedDecorations.delete(uri); } </ins> } private _stopSingular(): void { // Remove any existing decorations + a possible query, and re - run to update decorations this._removeSingleDecorations(); <del> if (this.editor.hasWidgetFocus()) { </del> <ins> if (this.editor.hasTextFocus()) { </ins> if (this.editor.getModel()?.uri.scheme !== Schemas.vscodeNotebookCell && WordHighlighter.query?.modelInfo?.model.uri.scheme !== Schemas.vscodeNotebookCell) { // clear query if focused non-nb editor WordHighlighter.query = null; this._run();


} } <del> private _stopAll(): void { </del> <ins> private _stopAll() { </ins> // Remove any existing decorations <del> // TODO: @Yoyokrazy - this triggers as notebooks scroll, causing highlights to disappear momentarily. </del> <ins> // TODO: @Yoyokrazy -- this triggers as notebooks scroll, causing highlights to disappear momentarily. // maybe a nb type check? </ins> this._removeAllDecorations(); // Cancel any renderDecorationsTimer


// a) there is no stored query model, but there is a word. This signals the editor that drove the highlight is disposed (cell out of viewport, etc) // b) the queried model is not the current model. This signals that the editor that drove the highlight is still in the viewport, but we are highlighting a different cell // otherwise, we send null in place of the word, and the model and selection are used to compute the word <ins> // TODO: @Yoyokrazy -- investigate this logic for sendWord </ins> const sendWord = (!WordHighlighter.query.modelInfo && WordHighlighter.query.word) || (WordHighlighter.query.modelInfo?.model.uri !== this.model.uri) ? true : false;


const newDocumentHighlights = this.workerRequestValue.get(uri); if (newDocumentHighlights) { for (const highlight of newDocumentHighlights) { <ins> if (!highlight.range) { continue; } </ins> newDecorations.push({ range: highlight.range, options: getHighlightDecorationOptions(highlight.kind)


import * as arrays from 'vs/base/common/arrays'; import { RunOnceScheduler } from 'vs/base/common/async'; import * as errors from 'vs/base/common/errors'; <del> import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; </del> <ins> import { DisposableStore, dispose, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; </ins> import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/debugToolBar'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';


import { CONTEXT_DEBUG_STATE, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG, CONTEXT_IN_DEBUG_MODE, CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, IDebugConfiguration, IDebugService, State, VIEWLET_ID } from 'vs/workbench/contrib/debug/common/debug'; import { EditorTabsMode, IWorkbenchLayoutService, LayoutSettings, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { Codicon } from 'vs/base/common/codicons'; <del> import { mainWindow } from 'vs/base/browser/window'; </del> <ins> import { CodeWindow, mainWindow } from 'vs/base/browser/window'; import { clamp } from 'vs/base/common/numbers'; </ins> const DEBUG_TOOLBAR_POSITION_KEY = 'debug.actionswidgetposition'; const DEBUG_TOOLBAR_Y_KEY = 'debug.actionswidgety';


private isBuilt = false; private readonly stopActionViewItemDisposables = this._register(new DisposableStore()); <ins> /** coordinate of the debug toolbar per aux window */ private readonly auxWindowCoordinates = new WeakMap<CodeWindow, { x: number; y: number | undefined }>(); </ins> constructor( @INotificationService private readonly notificationService: INotificationService,


// log in telemetry this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: e.action.id, from: 'debugActionsWidget' }); })); <del> this._register(dom.addDisposableListener(mainWindow, dom.EventType.RESIZE, () => this.setCoordinates())); </del> this._register(dom.addDisposableGenericMouseUpListener(this.dragArea, (event: MouseEvent) => { const mouseClickEvent = new StandardMouseEvent(dom.getWindow(this.dragArea), event); <ins> const activeWindow = dom.getWindow(this.layoutService.activeContainer); </ins> if (mouseClickEvent.detail === 2) { // double click on debug bar centers it again #8250 const widgetWidth = this.$el.clientWidth; <del> this.setCoordinates(0.5 * mainWindow.innerWidth - 0.5 * widgetWidth, 0); </del> <ins> this.setCoordinates(0.5 * activeWindow.innerWidth - 0.5 * widgetWidth, 0); </ins> this.storePosition(); } })); this._register(dom.addDisposableGenericMouseDownListener(this.dragArea, (event: MouseEvent) => { this.dragArea.classList.add('dragged'); <ins> const activeWindow = dom.getWindow(this.layoutService.activeContainer); </ins> <del> const mouseMoveListener = dom.addDisposableGenericMouseMoveListener(mainWindow, (e: MouseEvent) => { const mouseMoveEvent = new StandardMouseEvent(mainWindow, e); </del> <ins> const mouseMoveListener = dom.addDisposableGenericMouseMoveListener(activeWindow, (e: MouseEvent) => { const mouseMoveEvent = new StandardMouseEvent(activeWindow, e); </ins> // Prevent default to stop editor selecting text #8524 mouseMoveEvent.preventDefault(); // Reduce x by width of drag handle to reduce jarring #16604 this.setCoordinates(mouseMoveEvent.posx - 14, mouseMoveEvent.posy - 14); }); <del> const mouseUpListener = dom.addDisposableGenericMouseUpListener(mainWindow, (e: MouseEvent) => { </del> <ins> const mouseUpListener = dom.addDisposableGenericMouseUpListener(activeWindow, (e: MouseEvent) => { </ins> this.storePosition(); this.dragArea.classList.remove('dragged');


this._register(this.layoutService.onDidChangePartVisibility(() => this.setYCoordinate())); this._register(browser.PixelRatio.onDidChange(() => this.setYCoordinate())); <ins> const resizeListener = this._register(new MutableDisposable()); this._register(this.layoutService.onDidChangeActiveContainer(() => { this._yRange = undefined; // note: we intentionally don't read the activeContainer before the // `then` clause to avoid any races due to quickly switching windows. this.layoutService.whenActiveContainerStylesLoaded.then(() => { if (this.isBuilt) { this.layoutService.activeContainer.appendChild(this.$el); this.setCoordinates(); } resizeListener.value = this._register(dom.addDisposableListener( dom.getWindow(this.layoutService.activeContainer), dom.EventType.RESIZE, () => this.setYCoordinate())); }); })); </ins> } private storePosition(): void { <del> const left = dom.getComputedStyle(this.$el).left; if (left) { const position = parseFloat(left) / mainWindow.innerWidth; this.storageService.store(DEBUG_TOOLBAR_POSITION_KEY, position, StorageScope.PROFILE, StorageTarget.MACHINE); } if (this.yCoordinate) { </del> <ins> const activeWindow = dom.getWindow(this.layoutService.activeContainer); const isMainWindow = this.layoutService.activeContainer === this.layoutService.mainContainer; const left = this.$el.getBoundingClientRect().left / activeWindow.innerWidth; if (isMainWindow) { this.storageService.store(DEBUG_TOOLBAR_POSITION_KEY, left, StorageScope.PROFILE, StorageTarget.MACHINE); </ins> this.storageService.store(DEBUG_TOOLBAR_Y_KEY, this.yCoordinate, StorageScope.PROFILE, StorageTarget.MACHINE); } else { <del> this.storageService.remove(DEBUG_TOOLBAR_Y_KEY, StorageScope.PROFILE); </del> <ins> this.auxWindowCoordinates.set(activeWindow, { x: left, y: this.yCoordinate }); </ins> } }


if (!this.isVisible) { return; } const widgetWidth = this.$el.clientWidth; <ins> const currentWindow = dom.getWindow(this.layoutService.activeContainer); const isMainWindow = currentWindow === mainWindow; </ins> if (x === undefined) { <del> const positionPercentage = this.storageService.get(DEBUG_TOOLBAR_POSITION_KEY, StorageScope.PROFILE); x = positionPercentage !== undefined ? parseFloat(positionPercentage) * mainWindow.innerWidth : (0.5 * mainWindow.innerWidth - 0.5 * widgetWidth); </del> <ins> const positionPercentage = isMainWindow ? Number(this.storageService.get(DEBUG_TOOLBAR_POSITION_KEY, StorageScope.PROFILE)) : this.auxWindowCoordinates.get(currentWindow)?.x; x = positionPercentage !== undefined ? positionPercentage * currentWindow.innerWidth : (0.5 * currentWindow.innerWidth - 0.5 * widgetWidth); </ins> } <del> x = Math.max(0, Math.min(x, mainWindow.innerWidth - widgetWidth)); // do not allow the widget to overflow on the right </del> <ins> x = clamp(x, 0, currentWindow.innerWidth - widgetWidth); // do not allow the widget to overflow on the right </ins> this.$el.style.left = `${x}px`; if (y === undefined) { <del> y = this.storageService.getNumber(DEBUG_TOOLBAR_Y_KEY, StorageScope.PROFILE, 0); </del> <ins> y = isMainWindow ? this.storageService.getNumber(DEBUG_TOOLBAR_Y_KEY, StorageScope.PROFILE) : this.auxWindowCoordinates.get(currentWindow)?.y; </ins> } <del> this.setYCoordinate(y); </del> <ins> this.setYCoordinate(y || 0); </ins> } private setYCoordinate(y = this.yCoordinate): void {


private _yRange: [number, number] | undefined; private get yRange(): [number, number] { if (!this._yRange) { <del> const isTitleBarVisible = this.layoutService.isVisible(Parts.TITLEBAR_PART, mainWindow); </del> <ins> const isTitleBarVisible = this.layoutService.isVisible(Parts.TITLEBAR_PART, dom.getWindow(this.layoutService.activeContainer)); </ins> const yMin = isTitleBarVisible ? 0 : this.layoutService.mainContainerOffset.top; let yMax = 0;


} if (!this.isBuilt) { this.isBuilt = true; <del> this.layoutService.mainContainer.appendChild(this.$el); </del> <ins> this.layoutService.activeContainer.appendChild(this.$el); </ins> } this.isVisible = true;


await TerminalAccessibleViewContribution.get(instance)?.navigateToCommand(NavigationType.Previous); } }); <ins> registerTerminalAction({ id: TerminalCommandId.ScrollToBottom, title: { value: localize('workbench.action.terminal.scrollToBottom', "Scroll to Bottom"), original: 'Scroll to Bottom' }, precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), ContextKeyExpr.and(accessibleViewIsShown, ContextKeyExpr.equals(accessibleViewCurrentProviderId.key, AccessibleViewProviderId.Terminal))), keybinding: { primary: KeyMod.CtrlCmd | KeyCode.End, linux: { primary: KeyMod.Shift | KeyCode.End }, when: accessibleViewCurrentProviderId.isEqualTo(AccessibleViewProviderId.Terminal), weight: KeybindingWeight.WorkbenchContrib }, run: (c, accessor) => { const accessibleViewService = accessor.get(IAccessibleViewService); const lastPosition = accessibleViewService.getLastPosition(); if (!lastPosition) { return; } accessibleViewService.setPosition(lastPosition, true); } }); registerTerminalAction({ id: TerminalCommandId.ScrollToTop, title: { value: localize('workbench.action.terminal.scrollToTop', "Scroll to Top"), original: 'Scroll to Top' }, precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), ContextKeyExpr.and(accessibleViewIsShown, ContextKeyExpr.equals(accessibleViewCurrentProviderId.key, AccessibleViewProviderId.Terminal))), keybinding: { primary: KeyMod.CtrlCmd | KeyCode.Home, linux: { primary: KeyMod.Shift | KeyCode.Home }, when: accessibleViewCurrentProviderId.isEqualTo(AccessibleViewProviderId.Terminal), weight: KeybindingWeight.WorkbenchContrib }, run: (c, accessor) => { const accessibleViewService = accessor.get(IAccessibleViewService); accessibleViewService.setPosition({ lineNumber: 1, column: 1 } as Position, true); } }); </ins>


return; } this._inlineChatKeybinding = keybinding; <del> const hoverMessage = new MarkdownString(keybinding ? localize('runWithKeybinding', 'Start Inline Chat [{0}]', keybinding) : LOCALIZED_START_INLINE_CHAT_STRING); </del> <ins> const hoverMessage = new MarkdownString(keybinding ? localize('runWithKeybinding', 'Start Inline Chat ({0})', keybinding) : LOCALIZED_START_INLINE_CHAT_STRING); </ins> this._gutterDecorationTransparent.glyphMarginHoverMessage = hoverMessage; this._gutterDecorationOpaque.glyphMarginHoverMessage = hoverMessage; }


/** * Sets or triggers a quick pick to change the color of the associated terminal tab icon. */ <del> changeColor(color?: string): Promise<string | undefined>; </del> <ins> changeColor(color?: string, skipQuickPick?: boolean): Promise<string | undefined>; </ins> /** * Triggers a quick pick that displays recent commands or cwds. Selecting one will


precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.tabsSingularSelection), run: async (c, accessor) => { let color: string | undefined; <ins> let i = 0; </ins> for (const terminal of getSelectedInstances(accessor) ?? []) { <del> color = await terminal.changeColor(color); </del> <ins> const skipQuickPick = i !== 0; // Always show the quickpick on the first iteration color = await terminal.changeColor(color, skipQuickPick); i++; </ins> } } });


when: TerminalContextKeys.tabsFocus }, run: async (c, accessor) => { <del> for (const terminal of getSelectedInstances(accessor) ?? []) { c.service.safeDisposeTerminal(terminal); </del> <ins> const disposePromises: Promise<void>[] = []; for (const terminal of getSelectedInstances(accessor, true) ?? []) { disposePromises.push(c.service.safeDisposeTerminal(terminal)); </ins> } <ins> await Promise.all(disposePromises); </ins> c.groupService.focusTabs(); } });


const terminalGroupService = accessor.get(ITerminalGroupService); const result: ITerminalInstance[] = []; <del> // Get inline tab instance if (terminalGroupService.lastAccessedMenu === 'inline-tab') { </del> <ins> const list = listService.lastFocusedList; // Get selected tab list instance(s) const selections = list?.getSelection(); // Get inline tab instance if there are not tab list selections #196578 if (terminalGroupService.lastAccessedMenu === 'inline-tab' && !selections?.length) { </ins> const instance = terminalGroupService.activeInstance; return instance ? [terminalGroupService.activeInstance] : undefined; } <del> // Get tab list instance if (!listService.lastFocusedList?.getSelection()) { </del> <ins> if (!list || !selections) { </ins> return undefined; } <del> const selections = listService.lastFocusedList.getSelection(); const focused = listService.lastFocusedList.getFocus(); </del> <ins> const focused = list.getFocus(); </ins> if (focused.length === 1 && !selections.includes(focused[0])) { // focused length is always a max of 1


return; } <del> async changeColor(color?: string): Promise<string | undefined> { </del> <ins> async changeColor(color?: string, skipQuickPick?: boolean): Promise<string | undefined> { </ins> if (color) { this.shellLaunchConfig.color = color; this._onIconChanged.fire({ instance: this, userInitiated: true }); return color; <ins> } else if (skipQuickPick) { // Reset this tab's color this.shellLaunchConfig.color = ''; this._onIconChanged.fire({ instance: this, userInitiated: true }); return; </ins> } const icon = this._getIcon(); if (!icon) {


title: { value: LOCALIZED_START_INLINE_CHAT_STRING, original: 'Start Inline Chat' }, category: AbstractInlineChatAction.category, f1: true, <del> precondition: CTX_INLINE_CHAT_HAS_PROVIDER, </del> <ins> precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_HAS_PROVIDER, EditorContextKeys.writable), </ins> keybinding: { when: EditorContextKeys.focus, weight: KeybindingWeight.WorkbenchContrib,


import * as perf from 'vs/base/common/performance'; import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { memoize } from 'vs/base/common/decorators'; <del> import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext, ExplorerResourceAvailableEditorIdsContext, VIEW_ID, VIEWLET_ID, ExplorerResourceNotReadonlyContext, ViewHasSomeCollapsibleRootItemContext, FoldersViewVisibleContext } from 'vs/workbench/contrib/files/common/files'; </del> <ins> import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext, ExplorerResourceAvailableEditorIdsContext, VIEW_ID, ExplorerResourceNotReadonlyContext, ViewHasSomeCollapsibleRootItemContext, FoldersViewVisibleContext } from 'vs/workbench/contrib/files/common/files'; </ins> import { FileCopiedContext, NEW_FILE_COMMAND_ID, NEW_FOLDER_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileActions'; import * as DOM from 'vs/base/browser/dom'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';


import { IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; <del> import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; </del> <ins> import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views'; </ins> import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor';


import { Codicon } from 'vs/base/common/codicons'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IEditorResolverService } from 'vs/workbench/services/editor/common/editorResolverService'; <del> import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; </del> import { EditorOpenSource } from 'vs/platform/editor/common/editor'; import { ResourceMap } from 'vs/base/common/map'; import { isInputElement } from 'vs/base/browser/ui/list/listWidget';


} async run(accessor: ServicesAccessor): Promise<void> { <del> const paneCompositeService = accessor.get(IPaneCompositePartService); </del> <ins> const viewsService = accessor.get(IViewsService); </ins> const explorerService = accessor.get(IExplorerService); <del> await paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar); </del> <ins> await viewsService.openView(VIEW_ID); </ins> await explorerService.refresh(); } });


"@vscode/l10n-dev": "0.0.30", "@vscode/telemetry-extractor": "^1.10.2", "@vscode/test-cli": "^0.0.3", <del> "@vscode/test-electron": "^2.3.5", </del> <ins> "@vscode/test-electron": "^2.3.8", </ins> "@vscode/test-web": "^0.0.42", "@vscode/v8-heap-parser": "^0.1.0", "@vscode/vscode-perf": "^0.0.14",


supports-color "^9.4.0" yargs "^17.7.2" <del> "@vscode/test-electron@^2.3.5": version "2.3.5" resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.3.5.tgz#c472c5bdce1329aeb4762b8aa7a2cbe7aa783aac" integrity sha512-lAW7nQ0HuPqJnGJrtCzEKZCICtRizeP6qNanyCrjmdCOAAWjX3ixiG8RVPwqsYPQBWLPgYuE12qQlwXsOR/2fQ== </del> <ins> "@vscode/test-electron@^2.3.8": version "2.3.8" resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.3.8.tgz#06a7c50b38cfac0ede833905e088d55c61cd12d3" integrity sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg== </ins> dependencies: http-proxy-agent "^4.0.1" https-proxy-agent "^5.0.0"


} else if (name === 'nu') { // nushell requires ^ before quoted path to treat it as a command command = `^'${process.execPath}' ${extraArgs} -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`; shellArgs = ['-i', '-l', '-c']; <ins> } else if (name === 'xonsh') { // #200374: native implementation is shorter command = `import os, json; print("${mark}", json.dumps(dict(os.environ)), "${mark}")`; shellArgs = ['-i', '-l', '-c']; </ins> } else { command = `'${process.execPath}' ${extraArgs} -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`;


} let { top, left } = placement; <del> if (!alignAtTop) { </del> <ins> if (!alignAtTop && height > anchorBox.height) { </ins> top = bottom - height; } const editorDomNode = this._editor.getDomNode();


export interface IButtonOptions extends Partial<IButtonStyles> { readonly title?: boolean | string; <ins> readonly ariaLabel?: boolean | string; </ins> readonly supportIcons?: boolean; readonly supportShortLabel?: boolean; readonly secondary?: boolean;


this._element.classList.add('monaco-text-button-with-short-label'); } <ins> if (typeof options.ariaLabel === 'string') { this._element.setAttribute('aria-label', options.ariaLabel); } </ins> container.appendChild(this._element); this._register(Gesture.addTarget(this._element));


this._element.title = renderStringAsPlaintext(value); } <ins> if (typeof this.options.ariaLabel === 'string') { this._element.setAttribute('aria-label', this.options.ariaLabel); } else if (this.options.ariaLabel) { this._element.setAttribute('aria-label', this._element.title); } </ins> this._label = value; }


actionRunner: this._actionRunner, actions: rest, contextMenuProvider: this._contextMenuService, <ins> ariaLabel: action.label </ins> }); } else { action = actionOrSubmenu; btn = this.addButton({ secondary: conifgProvider(action)?.isSecondary ?? secondary, <ins> ariaLabel: action.label </ins> }); }


readonly position: number; } <ins> function stickyScrollNodeStateEquals<T, TFilterData>(node1: StickyScrollNode<T, TFilterData>, node2: StickyScrollNode<T, TFilterData>) { return node1.position === node2.position && stickyScrollNodeEquals(node1, node2); } </ins> function stickyScrollNodeEquals<T, TFilterData>(node1: StickyScrollNode<T, TFilterData>, node2: StickyScrollNode<T, TFilterData>) { <del> return node1.position === node2.position && node1.node.element === node2.node.element && </del> <ins> return node1.node.element === node2.node.element && </ins> node1.startIndex === node2.startIndex && node1.height === node2.height && node1.endIndex === node2.endIndex; } <del> class StickyScrollState<T, TFilterData, TRef> extends Disposable { </del> <ins> class StickyScrollState<T, TFilterData, TRef> { </ins> constructor( readonly stickyNodes: StickyScrollNode<T, TFilterData>[] = [] <del> ) { super(); } </del> <ins> ) { } </ins> get count(): number { return this.stickyNodes.length; } equal(state: StickyScrollState<T, TFilterData, TRef>): boolean { <del> return equals(this.stickyNodes, state.stickyNodes, stickyScrollNodeEquals); </del> <ins> return equals(this.stickyNodes, state.stickyNodes, stickyScrollNodeStateEquals); </ins> } lastNodePartiallyVisible(): boolean {


return secondLastStickyNode.position + secondLastStickyNode.height !== lastStickyNode.position; } <del> addDisposable(disposable: IDisposable): void { this._register(disposable); </del> <ins> animationStateChanged(previousState: StickyScrollState<T, TFilterData, TRef>): boolean { if (!equals(this.stickyNodes, previousState.stickyNodes, stickyScrollNodeEquals)) { return false; } if (this.count === 0) { return false; } const lastStickyNode = this.stickyNodes[this.count - 1]; const previousLastStickyNode = previousState.stickyNodes[previousState.count - 1]; return lastStickyNode.position !== previousLastStickyNode.position; </ins> } }


private readonly _rootDomNode: HTMLElement; private _previousState: StickyScrollState<T, TFilterData, TRef> | undefined; <ins> private _previousElements: HTMLElement[] = []; private _previousStateDisposables: DisposableStore = new DisposableStore(); </ins> private stickyScrollFocus: StickyScrollFocus<T, TFilterData, TRef>; readonly onDidChangeHasFocus: Event<boolean>;


private readonly accessibilityProvider: IListAccessibilityProvider<T> | undefined, ) { <del> this._rootDomNode = document.createElement('div'); this._rootDomNode.classList.add('monaco-tree-sticky-container'); </del> <ins> this._rootDomNode = $('.monaco-tree-sticky-container'); </ins> container.appendChild(this._rootDomNode); <ins> const shadow = $('.monaco-tree-sticky-container-shadow'); this._rootDomNode.appendChild(shadow); </ins> this.stickyScrollFocus = new StickyScrollFocus(this._rootDomNode, view); this.onDidChangeHasFocus = this.stickyScrollFocus.onDidChangeHasFocus; this.onContextMenu = this.stickyScrollFocus.onContextMenu;


this.setVisible(isVisible); } <del> // Remove previous state this._previousState?.dispose(); this._previousState = state; </del> if (!isVisible) { <ins> this._previousState = undefined; this._previousElements = []; this._previousStateDisposables.clear(); </ins> return; } <del> const elements = Array(state.count); for (let stickyIndex = state.count - 1; stickyIndex >= 0; stickyIndex--) { const stickyNode = state.stickyNodes[stickyIndex]; const { element, disposable } = this.createElement(stickyNode, stickyIndex, state.count); elements[stickyIndex] = element; </del> <ins> const lastStickyNode = state.stickyNodes[state.count - 1]; </ins> <del> this._rootDomNode.appendChild(element); state.addDisposable(disposable); </del> <ins> // If the new state is only a change in the last node's position, update the position of the last element if (this._previousState && state.animationStateChanged(this._previousState)) { this._previousElements[this._previousState.count - 1].style.top = `${lastStickyNode.position}px`; </ins> } <ins> // create new dom elements else { this._previousStateDisposables.clear(); </ins> <del> this.stickyScrollFocus.updateElements(elements, state); </del> <ins> const elements = Array(state.count); for (let stickyIndex = state.count - 1; stickyIndex >= 0; stickyIndex--) { const stickyNode = state.stickyNodes[stickyIndex]; </ins> <del> // Add shadow element to the end of the widget const shadow = $('.monaco-tree-sticky-container-shadow'); this._rootDomNode.appendChild(shadow); state.addDisposable(toDisposable(() => shadow.remove())); </del> <ins> const { element, disposable } = this.createElement(stickyNode, stickyIndex, state.count); elements[stickyIndex] = element; this._rootDomNode.appendChild(element); this._previousStateDisposables.add(disposable); } this.stickyScrollFocus.updateElements(elements, state); this._previousState = state; this._previousElements = elements; } </ins> // Set the height of the widget to the bottom of the last sticky node <del> const lastStickyNode = state.stickyNodes[state.count - 1]; </del> this._rootDomNode.style.height = `${lastStickyNode.position + lastStickyNode.height}px`; }


dispose(): void { this.stickyScrollFocus.dispose(); <del> this._previousState?.dispose(); </del> <ins> this._previousStateDisposables.dispose(); </ins> this._rootDomNode.remove(); } }


command: 'git.commit', title: l10n.t('{0} Continue', '$(check)'), tooltip: this.state.isCommitInProgress ? l10n.t('Continuing Rebase...') : l10n.t('Continue Rebase'), <del> arguments: [this.repository.sourceControl, ''] </del> <ins> arguments: [this.repository.sourceControl, null] </ins> }; }


command: 'git.commit', title: l10n.t('{0} Commit', '$(check)'), tooltip: this.state.isCommitInProgress ? l10n.t('Committing Changes...') : l10n.t('Commit Changes'), <del> arguments: [this.repository.sourceControl, ''] </del> <ins> arguments: [this.repository.sourceControl, null] </ins> }; }


const childNodes: INotebookVariableElement[] = []; if (parent.indexedChildrenCount > variablePageSize) { <del> // TODO: improve handling of large number of children const indexedChildCountLimit = 100000; const limit = Math.min(parent.indexedChildrenCount, indexedChildCountLimit); for (let start = 0; start < limit; start += variablePageSize) { let end = start + variablePageSize; if (end > limit) { end = limit; </del> <ins> const nestedPageSize = Math.floor(Math.max(parent.indexedChildrenCount / variablePageSize, 100)); const indexedChildCountLimit = 1_000_000; let start = parent.indexStart ?? 0; const last = start + Math.min(parent.indexedChildrenCount, indexedChildCountLimit); for (; start < last; start += nestedPageSize) { let end = start + nestedPageSize; if (end > last) { end = last; </ins> } childNodes.push({


childNodes.push({ kind: 'variable', notebook: parent.notebook, <del> id: parent.id + `${limit + 1}`, </del> <ins> id: parent.id + `${last + 1}`, </ins> extHostId: parent.extHostId, name: localize('notebook.indexedChildrenLimitReached', "Display limit reached"), value: '',


assert.equal(variables[0].extHostId, parent.extHostId, 'ExtHostId should match the parent since we will use it to get the real children'); }); <ins> test('Get children for very large list', async () => { const parent = { kind: 'variable', notebook: notebookModel, id: '1', extHostId: 1, name: 'list', value: '[...]', hasNamedChildren: false, indexedChildrenCount: 1_000_000 } as INotebookVariableElement; results = []; const groups = await dataSource.getChildren(parent); const children = await dataSource.getChildren(groups[99]); assert(children.length === 100, 'We should have a full page of child groups'); assert(!provideVariablesCalled, 'provideVariables should not be called'); assert.equal(children[0].extHostId, parent.extHostId, 'ExtHostId should match the parent since we will use it to get the real children'); }); </ins> test('Cancel while enumerating through children', async () => { const parent = { kind: 'variable', notebook: notebookModel, id: '1', extHostId: 1, name: 'list', value: '[...]', hasNamedChildren: false, indexedChildrenCount: 10 } as INotebookVariableElement; results = [


public onDidChangeTaskSystemInfo: Event<void> = this._onDidChangeTaskSystemInfo.event; private _onDidReconnectToTasks: Emitter<void> = new Emitter(); public onDidReconnectToTasks: Event<void> = this._onDidReconnectToTasks.event; <ins> private _onDidChangeTaskConfig: Emitter<void> = new Emitter(); public onDidChangeTaskConfig: Event<void> = this._onDidChangeTaskConfig.event; </ins> public get isReconnected(): boolean { return this._tasksReconnected; } constructor(


this._updateSetup(folderSetup); return this._updateWorkspaceTasks(TaskRunSource.FolderOpen); })); <del> this._register(this._configurationService.onDidChangeConfiguration((e) => { </del> <ins> this._register(this._configurationService.onDidChangeConfiguration(async (e) => { </ins> if (!e.affectsConfiguration('tasks') || (!this._taskSystem && !this._workspaceTasksPromise)) { return; }


} this._setTaskLRUCacheLimit(); <del> return this._updateWorkspaceTasks(TaskRunSource.ConfigurationChange); </del> <ins> await this._updateWorkspaceTasks(TaskRunSource.ConfigurationChange); this._onDidChangeTaskConfig.fire(); </ins> })); this._taskRunningState = TASK_RUNNING_STATE.bindTo(_contextKeyService); this._onDidStateChange = this._register(new Emitter());


this._logService.trace('RunAutomaticTasks: Awaiting task system info.'); await Event.toPromise(Event.once(this._taskService.onDidChangeTaskSystemInfo)); } <del> const workspaceTasks = await this._taskService.getWorkspaceTasks(TaskRunSource.FolderOpen); </del> <ins> let workspaceTasks = await this._taskService.getWorkspaceTasks(TaskRunSource.FolderOpen); </ins> this._logService.trace(`RunAutomaticTasks: Found ${workspaceTasks.size} automatic tasks`); <del> await this._runWithPermission(this._taskService, this._configurationService, workspaceTasks); </del> <ins> let autoTasks = this._findAutoTasks(this._taskService, workspaceTasks); this._logService.trace(`RunAutomaticTasks: taskNames=${JSON.stringify(autoTasks.taskNames)}`); // As seen in some cases with the Remote SSH extension, the tasks configuration is loaded after we have come // to this point. Let's give it some extra time. if (autoTasks.taskNames.length === 0) { const updatedWithinTimeout = await Promise.race([ new Promise<boolean>((resolve) => { Event.toPromise(Event.once(this._taskService.onDidChangeTaskConfig)).then(() => resolve(true)); }), new Promise<boolean>((resolve) => { const timer = setTimeout(() => { clearTimeout(timer); resolve(false); }, 10000); })]); if (!updatedWithinTimeout) { this._logService.trace(`RunAutomaticTasks: waited some extra time, but no update of tasks configuration`); return; } workspaceTasks = await this._taskService.getWorkspaceTasks(TaskRunSource.FolderOpen); autoTasks = this._findAutoTasks(this._taskService, workspaceTasks); this._logService.trace(`RunAutomaticTasks: updated taskNames=${JSON.stringify(autoTasks.taskNames)}`); } this._runWithPermission(this._taskService, this._configurationService, autoTasks.tasks, autoTasks.taskNames); </ins> } private _runTasks(taskService: ITaskService, tasks: Array<Task | Promise<Task | undefined>>) {


return { tasks, taskNames, locations }; } <del> private async _runWithPermission(taskService: ITaskService, configurationService: IConfigurationService, workspaceTaskResult: Map<string, IWorkspaceFolderTaskResult>) { const { tasks, taskNames } = this._findAutoTasks(taskService, workspaceTaskResult); </del> <ins> private async _runWithPermission(taskService: ITaskService, configurationService: IConfigurationService, tasks: (Task | Promise<Task | undefined>)[], taskNames: string[]) { </ins> if (taskNames.length === 0) { return; }


registerTaskSystem(scheme: string, taskSystemInfo: ITaskSystemInfo): void; onDidChangeTaskSystemInfo: Event<void>; <ins> onDidChangeTaskConfig: Event<void>; </ins> readonly hasTaskSystemInfo: boolean; registerSupportedExecutions(custom?: boolean, shell?: boolean, process?: boolean): void;


} finalMatchedTargets.add(uri); }); <ins> }).catch(err => { // temporary fix for https://github.com/microsoft/vscode/issues/205044: don't show notebook results for remotehub repos. if (err.code === 'ENOENT') { console.warn(`Could not find notebook search results, ignoring notebook results.`); return { limitHit: false, messages: [], }; } else { throw err; } </ins> }); })) ));


return this.input.selectionEnd === this.input.value.length && this.input.selectionStart === this.input.selectionEnd; } <del> public getSelection(): IRange | null { const selectionStart = this.input.selectionStart; if (selectionStart === null) { return null; } const selectionEnd = this.input.selectionEnd ?? selectionStart; return { start: selectionStart, end: selectionEnd, }; } </del> public enable(): void { this.input.removeAttribute('disabled'); }


} } <del> // Store the existing selection if there was one. const visibleSelection = visibleQuickAccess?.picker?.valueSelection; </del> // Create a picker for the provider to use with the initial value // and adjust the filtering to exclude the prefix from filtering const disposables = new DisposableStore();


// on the onDidHide event. picker.show(); <del> // If the previous picker had a selection, we should set that in the new picker. if (visibleSelection) { picker.valueSelection = visibleSelection; } </del> // Pick mode: return with promise if (pick) { return pickPromise?.p;


return this.ui.keyMods; } <del> get valueSelection() { const selection = this.ui.inputBox.getSelection(); if (!selection) { return undefined; } return [selection.start, selection.end]; } set valueSelection(valueSelection: Readonly<[number, number]> | undefined) { </del> <ins> set valueSelection(valueSelection: Readonly<[number, number]>) { </ins> this._valueSelection = valueSelection; this.valueSelectionUpdated = true; this.update();


this.update(); } <del> get valueSelection() { const selection = this.ui.inputBox.getSelection(); if (!selection) { return undefined; } return [selection.start, selection.end]; } set valueSelection(valueSelection: Readonly<[number, number]> | undefined) { </del> <ins> set valueSelection(valueSelection: Readonly<[number, number]>) { </ins> this._valueSelection = valueSelection; this.valueSelectionUpdated = true; this.update();


this.findInput.inputBox.select(range); } <del> getSelection(): IRange | null { return this.findInput.inputBox.getSelection(); } </del> isSelectionAtEnd(): boolean { return this.findInput.inputBox.isSelectionAtEnd(); }


'terminal.ansiGreen': { index: 2, defaults: { <del> light: '#00BC00', </del> <ins> light: '#107C10', </ins> dark: '#0DBC79', hcDark: '#00cd00', <del> hcLight: '#00bc00' </del> <ins> hcLight: '#136C13' </ins> } }, 'terminal.ansiYellow': {


assert.deepStrictEqual(colors, [ '#000000', '#cd3131', <del> '#00bc00', </del> <ins> '#107c10', </ins> '#949800', '#0451a5', '#bc05bc',


import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { NOTEBOOK_VARIABLE_VIEW_ENABLED } from 'vs/workbench/contrib/notebook/browser/contrib/notebookVariables/notebookVariableContextKeys'; export class NotebookVariables extends Disposable implements IWorkbenchContribution { private listeners: IDisposable[] = []; private configListener: IDisposable;


this.viewEnabled = NOTEBOOK_VARIABLE_VIEW_ENABLED.bindTo(contextKeyService); <del> this.listeners.push(this.editorService.onDidEditorsChange(() => this.handleInitEvent())); this.listeners.push(this.notebookExecutionStateService.onDidChangeExecution(() => this.handleInitEvent())); </del> <ins> this.listeners.push(this.editorService.onDidActiveEditorChange(() => this.handleInitEvent())); this.listeners.push(this.notebookExecutionStateService.onDidChangeExecution((e) => this.handleInitEvent())); </ins> this.configListener = configurationService.onDidChangeConfiguration((e) => this.handleConfigChange(e)); }


if (this.configurationService.getValue(NotebookSetting.notebookVariablesView) && this.editorService.activeEditorPane?.getId() === 'workbench.editor.notebook') { <del> if (this.hasVariableProvider()) { </del> <ins> if (this.hasVariableProvider() && !this.initialized && this.initializeView()) { </ins> this.viewEnabled.set(true); <del> } if (!this.initialized && this.initializeView()) { </del> this.initialized = true; this.listeners.forEach(listener => listener.dispose()); }


private setActiveNotebook() { const current = this.activeNotebook; const activeEditorPane = this.editorService.activeEditorPane; <del> if (activeEditorPane && activeEditorPane.getId() === 'workbench.editor.notebook') { </del> <ins> if (activeEditorPane?.getId() === 'workbench.editor.notebook') { </ins> const notebookDocument = getNotebookEditorFromEditorPane(activeEditorPane)?.getViewModel()?.notebookDocument; this.activeNotebook = notebookDocument; }


import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; <del> import { IQuickPickItem, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; </del> <ins> import { IQuickPickItem, IQuickInputService, IQuickPickSeparator, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; </ins> import { AUX_WINDOW_GROUP, AUX_WINDOW_GROUP_TYPE, IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { assertIsDefined } from 'vs/base/common/types'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';


const editorService = accessor.get(IEditorService); const fileConfigurationService = accessor.get(IFilesConfigurationService); <del> const entries: IOutputChannelQuickPickItem[] = outputService.getChannelDescriptors().filter(c => c.file && c.log) .map(channel => (<IOutputChannelQuickPickItem>{ id: channel.id, label: channel.label, channel })); const argName = args && typeof args === 'string' ? args : undefined; </del> let entry: IOutputChannelQuickPickItem | undefined; <del> if (argName) { entry = entries.find(e => e.id === argName); </del> <ins> const argName = args && typeof args === 'string' ? args : undefined; const extensionChannels: IOutputChannelQuickPickItem[] = []; const coreChannels: IOutputChannelQuickPickItem[] = []; for (const c of outputService.getChannelDescriptors()) { if (c.file && c.log) { const e = { id: c.id, label: c.label, channel: c }; if (c.extensionId) { extensionChannels.push(e); } else { coreChannels.push(e); } if (e.id === argName) { entry = e; } } </ins> } if (!entry) { <del> entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log File") }); </del> <ins> const entries: QuickPickInput[] = [...extensionChannels.sort((a, b) => a.label.localeCompare(b.label))]; if (entries.length && coreChannels.length) { entries.push({ type: 'separator' }); entries.push(...coreChannels.sort((a, b) => a.label.localeCompare(b.label))); } entry = <IOutputChannelQuickPickItem | undefined>await quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log File") }); </ins> } if (entry) { const resource = assertIsDefined(entry.channel.file);


hideOnHover: true, hideOnKeyDown: true, }, <ins> appearance: { compact: true, }, </ins> ...overrideOptions }, focus); }


const response = await fetch(url, init); if (!response.ok) { <ins> console.error('Invalid GitHub URL provided.'); </ins> return false; } const result = await response.json();


let issueUrl = hasUri ? this.getExtensionBugsUrl() : this.getIssueUrl(); if (!issueUrl) { <ins> console.error('No issue url found'); </ins> return false; }


try { url = await this.writeToClipboard(baseUrl, issueBody); } catch (_) { <ins> console.error('Writing to clipboard failed'); </ins> return false; } }


owner: match[1], repositoryName: match[2] }; <ins> } else { console.error('No GitHub match'); </ins> } return undefined;


githubAccessToken }, dataOverrides); <ins> if (issueReporterData.extensionId) { const extensionExists = extensionData.some(extension => extension.id === issueReporterData.extensionId); if (!extensionExists) { console.error(`Extension with ID ${issueReporterData.extensionId} does not exist.`); } } </ins> if (issueReporterData.extensionId && this.extensionIdentifierSet.has(issueReporterData.extensionId)) { ipcRenderer.send(`vscode:triggerReporterMenuResponse:${issueReporterData.extensionId}`, issueReporterData); this.extensionIdentifierSet.delete(new ExtensionIdentifier(issueReporterData.extensionId));


previewStart = assertIsDefined(this.editor.getPosition()); } <ins> const endPosition = new Position(previewStart.lineNumber, previewStart.column + text.length); </ins> this.editor.executeEdits(EditorDictation.ID, [ EditOperation.replace(Range.fromPositions(previewStart, previewStart.with(undefined, previewStart.column + lastReplaceTextLength)), text) ], [ <del> Selection.fromPositions(new Position(previewStart.lineNumber, previewStart.column + text.length)) </del> <ins> Selection.fromPositions(endPosition) </ins> ]); if (isPreview) {


lastReplaceTextLength = 0; } <ins> this.editor.revealPositionInCenterIfOutsideViewport(endPosition); </ins> this.widget.layout(); };


LanguageModelSystemMessage: extHostTypes.LanguageModelChatSystemMessage, LanguageModelUserMessage: extHostTypes.LanguageModelChatUserMessage, LanguageModelAssistantMessage: extHostTypes.LanguageModelChatAssistantMessage, <ins> LanguageModelError: extHostTypes.LanguageModelError, </ins> NewSymbolName: extHostTypes.NewSymbolName, NewSymbolNameTag: extHostTypes.NewSymbolNameTag, InlineEdit: extHostTypes.InlineEdit,


import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostLanguageModelsShape, IMainContext, MainContext, MainThreadLanguageModelsShape } from 'vs/workbench/api/common/extHost.protocol'; import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; <ins> import { LanguageModelError } from 'vs/workbench/api/common/extHostTypes'; </ins> import type * as vscode from 'vscode'; import { Progress } from 'vs/platform/progress/common/progress'; import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata } from 'vs/workbench/contrib/chat/common/languageModels';


const metadata = await this._proxy.$prepareChatAccess(from, languageModelId, options.justification); if (!metadata || !this._languageModelIds.has(languageModelId)) { <del> throw new Error(`Language model '${languageModelId}' is unknown.`); </del> <ins> throw LanguageModelError.NotFound(`Language model '${languageModelId}' is unknown.`); </ins> } if (this._isUsingAuth(from, metadata)) { const success = await this._getAuthAccess(extension, { identifier: metadata.extension, displayName: metadata.auth.providerLabel }, options.justification, options.silent); if (!success || !this._modelAccessList.get(from)?.has(metadata.extension)) { <del> throw new Error(`Language model '${languageModelId}' cannot be used by '${from.value}'.`); </del> <ins> throw LanguageModelError.NoPermissions(`Language model '${languageModelId}' cannot be used by '${from.value}'.`); </ins> } }


await barrier.wait(); if (error) { <del> throw new Error(`Language model '${languageModelId}' errored, check cause for more details`, { cause: error }); </del> <ins> throw new LanguageModelError( `Language model '${languageModelId}' errored, check cause for more details`, 'Unknown', error ); </ins> } return res.apiObject;


} } <ins> export class LanguageModelError extends Error { static NotFound(message?: string): LanguageModelError { return new LanguageModelError(message, LanguageModelError.NotFound.name); } static NoPermissions(message?: string): LanguageModelError { return new LanguageModelError(message, LanguageModelError.NoPermissions.name); } readonly code: string; constructor(message?: string, code?: string, cause?: Error) { super(message, { cause }); this.name = 'LanguageModelError'; this.code = code ?? ''; } } </ins> //#endregion //#region ai


} /** <ins> * An error type for language model specific errors. * * Consumers of language models should check the code property to determine specific * failure causes, like `if(someError.code === vscode.LanguageModelError.NotFound.name) {...}` * for the case of referring to an unknown language model. */ export class LanguageModelError extends Error { /** * The language model does not exist. */ static NotFound(message?: string): LanguageModelError; /** * The requestor does not have permissions to use this * language model */ static NoPermissions(message?: string): LanguageModelError; /** * A code that identifies this error. * * Possible values are names of errors, like {@linkcode LanguageModelError.NotFound NotFound}, * or `Unknown` for unspecified errors from the language model itself. In the latter case the * `cause`-property will contain the actual error. */ readonly code: string; } /** </ins> * Options for making a chat request using a language model. * * @see {@link lm.chatRequest}


* @returns A thenable that resolves to a {@link LanguageModelChatResponse}. The promise will reject when making the request failed. */ // TODO@API refine doc <del> // TODO@API define specific error types? // TODO@API NAME: sendChatRequest, fetchChatResponse, makeChatRequest, chat, chatRequest sendChatRequest </del> // TODO@API ExtensionContext#permission#languageModels: { languageModel: string: LanguageModelAccessInformation} <ins> // TODO@API ✅ define specific error types? // TODO@API ✅ NAME: sendChatRequest, fetchChatResponse, makeChatRequest, chat, chatRequest sendChatRequest </ins> // TODO@API ✅ NAME: LanguageModelChatXYZMessage // TODO@API ✅ errors on everything that prevents us to make the actual request // TODO@API ✅ double auth


import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { workbenchConfigurationNodeBase, Extensions as WorkbenchExtensions, IConfigurationMigrationRegistry, ConfigurationKeyValuePairs } from 'vs/workbench/common/configuration'; import { AccessibilityAlertSettingId, AccessibilitySignal } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService'; <del> import { ISpeechService } from 'vs/workbench/contrib/speech/common/speechService'; </del> <ins> import { ISpeechService, SPEECH_LANGUAGES, SPEECH_LANGUAGE_CONFIG } from 'vs/workbench/contrib/speech/common/speechService'; </ins> import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Event } from 'vs/base/common/event';


export const enum AccessibilityVoiceSettingId { SpeechTimeout = 'accessibility.voice.speechTimeout', <del> SpeechLanguage = 'accessibility.voice.speechLanguage' </del> <ins> SpeechLanguage = SPEECH_LANGUAGE_CONFIG </ins> } export const SpeechTimeoutDefault = 1200; <del> const SpeechLanguageDefault = 'en-US'; </del> export class DynamicSpeechAccessibilityConfiguration extends Disposable implements IWorkbenchContribution {


'tags': ['accessibility'] }, [AccessibilityVoiceSettingId.SpeechLanguage]: { <del> 'markdownDescription': localize('voice.speechLanguage', "The language that voice speech recognition should recognize."), </del> <ins> 'markdownDescription': localize('voice.speechLanguage', "The language that voice speech recognition should recognize. Select `auto` to use the configured display language if possible. Note that not all display languages maybe supported by speech recognition"), </ins> 'type': 'string', 'enum': languagesSorted, <del> 'default': SpeechLanguageDefault, </del> <ins> 'default': 'auto', </ins> 'tags': ['accessibility'], 'enumDescriptions': languagesSorted.map(key => languages[key].name), 'enumItemLabels': languagesSorted.map(key => languages[key].name)


private getLanguages(): { [locale: string]: { name: string } } { return { <del> ['da-DK']: { name: localize('speechLanguage.da-DK', "Danish (Denmark)") </del> <ins> ['auto']: { name: localize('speechLanguage.auto', "Auto (Use Display Language)") </ins> }, <del> ['de-DE']: { name: localize('speechLanguage.de-DE', "German (Germany)") }, ['en-AU']: { name: localize('speechLanguage.en-AU', "English (Australia)") }, ['en-CA']: { name: localize('speechLanguage.en-CA', "English (Canada)") }, ['en-GB']: { name: localize('speechLanguage.en-GB', "English (United Kingdom)") }, ['en-IE']: { name: localize('speechLanguage.en-IE', "English (Ireland)") }, ['en-IN']: { name: localize('speechLanguage.en-IN', "English (India)") }, ['en-NZ']: { name: localize('speechLanguage.en-NZ', "English (New Zealand)") }, [SpeechLanguageDefault]: { name: localize('speechLanguage.en-US', "English (United States)") }, ['es-ES']: { name: localize('speechLanguage.es-ES', "Spanish (Spain)") }, ['es-MX']: { name: localize('speechLanguage.es-MX', "Spanish (Mexico)") }, ['fr-CA']: { name: localize('speechLanguage.fr-CA', "French (Canada)") }, ['fr-FR']: { name: localize('speechLanguage.fr-FR', "French (France)") }, ['hi-IN']: { name: localize('speechLanguage.hi-IN', "Hindi (India)") }, ['it-IT']: { name: localize('speechLanguage.it-IT', "Italian (Italy)") }, ['ja-JP']: { name: localize('speechLanguage.ja-JP', "Japanese (Japan)") }, ['ko-KR']: { name: localize('speechLanguage.ko-KR', "Korean (South Korea)") }, ['nl-NL']: { name: localize('speechLanguage.nl-NL', "Dutch (Netherlands)") }, ['pt-PT']: { name: localize('speechLanguage.pt-PT', "Portuguese (Portugal)") }, ['pt-BR']: { name: localize('speechLanguage.pt-BR', "Portuguese (Brazil)") }, ['ru-RU']: { name: localize('speechLanguage.ru-RU', "Russian (Russia)") }, ['sv-SE']: { name: localize('speechLanguage.sv-SE', "Swedish (Sweden)") }, ['tr-TR']: { name: localize('speechLanguage.tr-TR', "Turkish (Turkey)") }, ['zh-CN']: { name: localize('speechLanguage.zh-CN', "Chinese (Simplified, China)") }, ['zh-HK']: { name: localize('speechLanguage.zh-HK', "Chinese (Traditional, Hong Kong)") }, ['zh-TW']: { name: localize('speechLanguage.zh-TW', "Chinese (Traditional, Taiwan)") } </del> <ins> ...SPEECH_LANGUAGES </ins> }; } }


import { ILogService } from 'vs/platform/log/common/log'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { DeferredPromise } from 'vs/base/common/async'; <del> import { ISpeechService, ISpeechProvider, HasSpeechProvider, ISpeechToTextSession, SpeechToTextInProgress, IKeywordRecognitionSession, KeywordRecognitionStatus, SpeechToTextStatus } from 'vs/workbench/contrib/speech/common/speechService'; </del> <ins> import { ISpeechService, ISpeechProvider, HasSpeechProvider, ISpeechToTextSession, SpeechToTextInProgress, IKeywordRecognitionSession, KeywordRecognitionStatus, SpeechToTextStatus, speechLanguageConfigToLanguage, SPEECH_LANGUAGE_CONFIG } from 'vs/workbench/contrib/speech/common/speechService'; </ins> import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';


this.logService.warn(`Multiple speech providers registered. Picking first one: ${provider.metadata.displayName}`); } <del> const language = this.configurationService.getValue<string>('accessibility.voice.speechLanguage'); </del> <ins> const language = speechLanguageConfigToLanguage(this.configurationService.getValue<unknown>(SPEECH_LANGUAGE_CONFIG)); </ins> const session = this._activeSpeechToTextSession = provider.createSpeechToTextSession(token, typeof language === 'string' ? { language } : undefined); const sessionStart = Date.now();


import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; <ins> import { language } from 'vs/base/common/platform'; </ins> export const ISpeechService = createDecorator<ISpeechService>('speechService');


*/ recognizeKeyword(token: CancellationToken): Promise<KeywordRecognitionStatus>; } <ins> export const SPEECH_LANGUAGE_CONFIG = 'accessibility.voice.speechLanguage'; export const SPEECH_LANGUAGES = { ['da-DK']: { name: localize('speechLanguage.da-DK', "Danish (Denmark)") }, ['de-DE']: { name: localize('speechLanguage.de-DE', "German (Germany)") }, ['en-AU']: { name: localize('speechLanguage.en-AU', "English (Australia)") }, ['en-CA']: { name: localize('speechLanguage.en-CA', "English (Canada)") }, ['en-GB']: { name: localize('speechLanguage.en-GB', "English (United Kingdom)") }, ['en-IE']: { name: localize('speechLanguage.en-IE', "English (Ireland)") }, ['en-IN']: { name: localize('speechLanguage.en-IN', "English (India)") }, ['en-NZ']: { name: localize('speechLanguage.en-NZ', "English (New Zealand)") }, ['en-US']: { name: localize('speechLanguage.en-US', "English (United States)") }, ['es-ES']: { name: localize('speechLanguage.es-ES', "Spanish (Spain)") }, ['es-MX']: { name: localize('speechLanguage.es-MX', "Spanish (Mexico)") }, ['fr-CA']: { name: localize('speechLanguage.fr-CA', "French (Canada)") }, ['fr-FR']: { name: localize('speechLanguage.fr-FR', "French (France)") }, ['hi-IN']: { name: localize('speechLanguage.hi-IN', "Hindi (India)") }, ['it-IT']: { name: localize('speechLanguage.it-IT', "Italian (Italy)") }, ['ja-JP']: { name: localize('speechLanguage.ja-JP', "Japanese (Japan)") }, ['ko-KR']: { name: localize('speechLanguage.ko-KR', "Korean (South Korea)") }, ['nl-NL']: { name: localize('speechLanguage.nl-NL', "Dutch (Netherlands)") }, ['pt-PT']: { name: localize('speechLanguage.pt-PT', "Portuguese (Portugal)") }, ['pt-BR']: { name: localize('speechLanguage.pt-BR', "Portuguese (Brazil)") }, ['ru-RU']: { name: localize('speechLanguage.ru-RU', "Russian (Russia)") }, ['sv-SE']: { name: localize('speechLanguage.sv-SE', "Swedish (Sweden)") }, ['tr-TR']: { name: localize('speechLanguage.tr-TR', "Turkish (Turkey)") }, ['zh-CN']: { name: localize('speechLanguage.zh-CN', "Chinese (Simplified, China)") }, ['zh-HK']: { name: localize('speechLanguage.zh-HK', "Chinese (Traditional, Hong Kong)") }, ['zh-TW']: { name: localize('speechLanguage.zh-TW', "Chinese (Traditional, Taiwan)") } }; export function speechLanguageConfigToLanguage(config: unknown, lang = language): string { if (typeof config === 'string') { if (config === 'auto') { if (lang !== 'en') { const langParts = lang.split('-'); return speechLanguageConfigToLanguage(`${langParts[0]}-${(langParts[1] ?? langParts[0]).toUpperCase()}`); } } else { if (SPEECH_LANGUAGES[config as keyof typeof SPEECH_LANGUAGES]) { return config; } } } return 'en-US'; } </ins>


<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { speechLanguageConfigToLanguage } from 'vs/workbench/contrib/speech/common/speechService'; suite('SpeechService', () => { test('resolve language', async () => { assert.strictEqual(speechLanguageConfigToLanguage(undefined), 'en-US'); assert.strictEqual(speechLanguageConfigToLanguage(3), 'en-US'); assert.strictEqual(speechLanguageConfigToLanguage('foo'), 'en-US'); assert.strictEqual(speechLanguageConfigToLanguage('foo-bar'), 'en-US'); assert.strictEqual(speechLanguageConfigToLanguage('tr-TR'), 'tr-TR'); assert.strictEqual(speechLanguageConfigToLanguage('zh-TW'), 'zh-TW'); assert.strictEqual(speechLanguageConfigToLanguage('auto', 'en'), 'en-US'); assert.strictEqual(speechLanguageConfigToLanguage('auto', 'tr'), 'tr-TR'); assert.strictEqual(speechLanguageConfigToLanguage('auto', 'zh-tw'), 'zh-TW'); }); ensureNoDisposablesAreLeakedInTestSuite(); }); </ins>


left: unset !important; } <del> .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-left::after, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-action-off::after, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.tab-actions-left::after, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.close-action-off::after { content: ''; </del> <ins> .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-fade-hider { display: none; } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.tab-actions-left .tab-fade-hider, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-action-off .tab-fade-hider, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.tab-actions-left .tab-fade-hider, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fixed.close-action-off .tab-fade-hider { </ins> display: flex; flex: 0; width: 5px; /* reserve space to hide tab fade when close button is left or off (fixes https://github.com/microsoft/vscode/issues/45728) */


const tabActionBarDisposable = combinedDisposable(tabActionBar, tabActionListener, toDisposable(insert(this.tabActionBars, tabActionBar))); <ins> // Tab Fade Hider // Hides the tab fade to the right when tab action left and sizing shrink/fixed, ::after, ::before are already used const tabShadowHider = document.createElement('div'); tabShadowHider.classList.add('tab-fade-hider'); tabContainer.appendChild(tabShadowHider); </ins> // Tab Border Bottom const tabBorderBottomContainer = document.createElement('div'); tabBorderBottomContainer.classList.add('tab-border-bottom-container');


} })); <ins> // Reset widget height so it's recalculated templateData.inputWidgetHeight = InputRenderer.DEFAULT_HEIGHT; </ins> // Rerender the element whenever the editor content height changes const onDidChangeContentHeight = () => { const contentHeight = templateData.inputWidget.getContentHeight();


} export function fromDetails(coverage: vscode.FileCoverageDetail): CoverageDetails.Serialized { <ins> if (typeof coverage.executed === 'number' && coverage.executed < 0) { throw new Error(`Invalid coverage count ${coverage.executed}`); } </ins> if ('branches' in coverage) { return { count: coverage.executed,


} export function fromFile(id: string, coverage: vscode.FileCoverage): IFileCoverage.Serialized { <ins> types.validateTestCoverageCount(coverage.statementCoverage); types.validateTestCoverageCount(coverage.branchCoverage); types.validateTestCoverageCount(coverage.declarationCoverage); </ins> return { id, uri: coverage.uri,


//#region Test Coverage export class TestCoverageCount implements vscode.TestCoverageCount { constructor(public covered: number, public total: number) { <ins> validateTestCoverageCount(this); </ins> } } <del> const validateCC = (cc?: vscode.TestCoverageCount) => { if (cc && cc.covered > cc.total) { </del> <ins> export function validateTestCoverageCount(cc?: vscode.TestCoverageCount) { if (!cc) { return; } if (cc.covered > cc.total) { </ins> throw new Error(`The total number of covered items (${cc.covered}) cannot be greater than the total (${cc.total})`); } <del> }; </del> <ins> if (cc.total < 0) { throw new Error(`The number of covered items (${cc.total}) cannot be negative`); } } </ins> export class FileCoverage implements vscode.FileCoverage { public static fromDetails(uri: vscode.Uri, details: vscode.FileCoverageDetail[]): vscode.FileCoverage {


public branchCoverage?: vscode.TestCoverageCount, public declarationCoverage?: vscode.TestCoverageCount, ) { <del> validateCC(statementCoverage); validateCC(branchCoverage); validateCC(declarationCoverage); </del> } }


import * as dom from 'vs/base/browser/dom'; import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { mapFindFirst } from 'vs/base/common/arraysFind'; <ins> import { assertNever } from 'vs/base/common/assert'; </ins> import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';


import { testingCoverageMissingBranch } from 'vs/workbench/contrib/testing/browser/icons'; import { FileCoverage } from 'vs/workbench/contrib/testing/common/testCoverage'; import { ITestCoverageService } from 'vs/workbench/contrib/testing/common/testCoverageService'; <del> import { CoverageDetails, DetailType, IStatementCoverage } from 'vs/workbench/contrib/testing/common/testTypes'; </del> <ins> import { CoverageDetails, DetailType, IDeclarationCoverage, IStatementCoverage } from 'vs/workbench/contrib/testing/common/testTypes'; </ins> import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; const MAX_HOVERED_LINES = 30;


/** Gets the markdown description for the given detail */ public describe(detail: CoverageDetailsWithBranch, model: ITextModel): IMarkdownString | undefined { if (detail.type === DetailType.Declaration) { <del> return new MarkdownString().appendMarkdown(localize('coverage.declExecutedCount', '`{0}` was executed {1} time(s).', detail.name, detail.count)); </del> <ins> return namedDetailLabel(detail.name, detail); </ins> } else if (detail.type === DetailType.Statement) { const text = wrapName(model.getValueInRange(tidyLocation(detail.location)).trim() || `<empty statement>`); <del> const str = new MarkdownString(); </del> if (detail.branches?.length) { const covered = detail.branches.filter(b => !!b.count).length; <del> str.appendMarkdown(localize('coverage.branches', '{0} of {1} of branches in {2} were covered.', covered, detail.branches.length, text)); </del> <ins> return new MarkdownString().appendMarkdown(localize('coverage.branches', '{0} of {1} of branches in {2} were covered.', covered, detail.branches.length, text)); </ins> } else { <del> str.appendMarkdown(localize('coverage.codeExecutedCount', '{0} was executed {1} time(s).', text, detail.count)); </del> <ins> return namedDetailLabel(text, detail); </ins> } <del> return str; </del> } else if (detail.type === DetailType.Branch) { const text = wrapName(model.getValueInRange(tidyLocation(detail.detail.location)).trim() || `<empty statement>`); const { count, label } = detail.detail.branches![detail.branch]; const label2 = label ? wrapInBackticks(label) : `#${detail.branch + 1}`; <del> if (count === 0) { </del> <ins> if (!count) { </ins> return new MarkdownString().appendMarkdown(localize('coverage.branchNotCovered', 'Branch {0} in {1} was not covered.', label2, text)); <ins> } else if (count === true) { return new MarkdownString().appendMarkdown(localize('coverage.branchCoveredYes', 'Branch {0} in {1} was executed.', label2, text)); </ins> } else { return new MarkdownString().appendMarkdown(localize('coverage.branchCovered', 'Branch {0} in {1} was executed {2} time(s).', label2, text, count)); } } <del> return undefined; </del> <ins> assertNever(detail); </ins> } } <ins> function namedDetailLabel(name: string, detail: IStatementCoverage | IDeclarationCoverage) { return new MarkdownString().appendMarkdown( !detail.count // 0 or false ? localize('coverage.declExecutedNo', '`{0}` was not executed.', name) : typeof detail.count === 'number' ? localize('coverage.declExecutedCount', '`{0}` was executed {1} time(s).', name, detail.count) : localize('coverage.declExecutedYes', '`{0}` was executed.', name) ); } </ins> // 'tidies' the range by normalizing it into a range and removing leading // and trailing whitespace. function tidyLocation(location: Range | Position): Range {


runHandler: (request: TestRunRequest, token: CancellationToken) => Thenable<void> | void; /** <del> * A function that provides detailed statement and function-level coverage for a file. </del> <ins> * An extension-provided function that provides detailed statement and * function-level coverage for a file. The editor will call this when more * detail is needed for a file, such as when it's opened in an editor or * expanded in the **Test Coverage** view. </ins> * * The {@link FileCoverage} object passed to this function is the same instance * emitted on {@link TestRun.addCoverage} calls associated with this profile.


get cwd(): URI | undefined { return that.cwd; }, <del> createDataStream(): AsyncIterable<string> { </del> <ins> readData(): AsyncIterable<string> { </ins> return that._createDataStream(); } };


* @example * // Log all data written to the terminal for a command * const command = term.shellIntegration.executeCommand({ commandLine: 'echo "Hello world"' }); <del> * const stream = command.createDataStream(); </del> <ins> * const stream = command.readData(); </ins> * for await (const data of stream) { *   console.log(data); * } */ <del> createDataStream(): AsyncIterable<string>; </del> <ins> readData(): AsyncIterable<string>; </ins> } export interface Terminal {


// delete if (fileOperation.type & BulkFileOperationType.Delete) { return { <del> original: { resource: undefined }, modified: { resource: URI.revive(previewUri) } </del> <ins> original: { resource: URI.revive(previewUri) }, modified: { resource: undefined } </ins> }; }


overviewRulerWidth: 10, ignoreBracketedPasteMode: config.ignoreBracketedPasteMode, rescaleOverlappingGlyphs: config.rescaleOverlappingGlyphs, <ins> windowOptions: { getWinSizePixels: true, getCellSizePixels: true, getWinSizeChars: true, }, </ins> })); this._updateSmoothScrolling(); this._core = (this.raw as any)._core as IXtermCore;


*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> import { createCancelablePromise, firstParallel } from 'vs/base/common/async'; </del> <ins> import { createCancelablePromise, firstParallel, timeout } from 'vs/base/common/async'; </ins> import { IDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import * as nls from 'vs/nls';


} else { if (terminal.state.isInteractedWith) { terminal.sendText('u0003'); // Ctrl+C for #106743. Not part of the same command for #107969 <ins> await timeout(200); // mirroring https://github.com/microsoft/vscode/blob/c67ccc70ece5f472ec25464d3eeb874cfccee9f1/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts#L852-L857 </ins> } if (configProvider.getConfiguration('debug.terminal').get<boolean>('clearBeforeReusing')) {


hoverDelegate.onDidHideHover?.(); hoverWidget = undefined; } <ins> htmlElement.removeAttribute('custom-hover-active'); </ins> }; const triggerShowHover = (delay: number, focus?: boolean, target?: IHoverDelegateTarget) => {


if (!hoverWidget || hoverWidget.isDisposed) { hoverWidget = new UpdatableHoverWidget(hoverDelegate, target || htmlElement, delay > 0); await hoverWidget.update(typeof content === 'function' ? content() : content, focus, options); <ins> htmlElement.setAttribute('custom-hover-active', 'true'); </ins> } }, delay); };


this.handleAndRegisterCustomViewContainers(); this.handleAndRegisterCustomViews(); <ins> // Abstract tree has it's own implementation of triggering custom hover // TreeView uses it's own implementation due to setting focus inside the (markdown) </ins> let showTreeHoverCancellation = new CancellationTokenSource(); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'workbench.action.showTreeHover',


} }, true); }, <del> weight: KeybindingWeight.WorkbenchContrib, </del> <ins> weight: KeybindingWeight.WorkbenchContrib + 1, </ins> primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyI), when: ContextKeyExpr.and(RawCustomTreeViewContextKey, WorkbenchListFocusContextKey) });


*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; </del> <ins> import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; </ins> import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { List } from 'vs/base/browser/ui/list/listWidget';


import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { Table } from 'vs/base/browser/ui/table/tableWidget'; import { AbstractTree, TreeFindMatchType, TreeFindMode } from 'vs/base/browser/ui/tree/abstractTree'; <del> import { isActiveElement } from 'vs/base/browser/dom'; </del> <ins> import { EventType, getActiveWindow, isActiveElement } from 'vs/base/browser/dom'; </ins> import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize, localize2 } from 'vs/nls'; <ins> import { IDisposable } from 'vs/base/common/lifecycle'; </ins> function ensureDOMFocus(widget: ListWidget | undefined): void { // it can happen that one of the commands is executed while


return; } <ins> if (activeHover) { toggleCustomHover(activeHover, widget); } </ins> await updateFocus(widget, updateFocusFn); const listFocus = widget.getFocus();


}); KeybindingsRegistry.registerCommandAndKeybindingRule({ <ins> id: 'list.showHover', weight: KeybindingWeight.WorkbenchContrib, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyI), when: WorkbenchListFocusContextKey, handler: async (accessor: ServicesAccessor, ...args: any[]) => { const listService = accessor.get(IListService); const lastFocusedList = listService.lastFocusedList; if (!lastFocusedList) { return; } // Check if a tree element is focused const focus = lastFocusedList.getFocus(); if (!focus || (focus.length === 0)) { return; } // As the tree does not know anything about the rendered DOM elements // we have to traverse the dom to find the HTMLElements const treeDOM = lastFocusedList.getHTMLElement(); const scrollableElement = treeDOM.querySelector('.monaco-scrollable-element'); const listRows = scrollableElement?.querySelector('.monaco-list-rows'); const focusedElement = listRows?.querySelector('.focused'); if (!focusedElement) { return; } // Check if the focused element has a hover, otherwise find the first child with a hover const elementWithHover = focusedElement.matches('[custom-hover="true"]') ? focusedElement : focusedElement.querySelector('[custom-hover="true"]'); if (!elementWithHover) { return; } toggleCustomHover(elementWithHover as HTMLElement, lastFocusedList); }, }); let activeHover: undefined | HTMLElement; let disposable: IDisposable | undefined; function toggleCustomHover(element: HTMLElement, list: WorkbenchListWidget) { const show = !element.getAttribute('custom-hover-active'); const mouseEvent = new MouseEvent(show ? EventType.MOUSE_OVER : EventType.MOUSE_LEAVE, { view: getActiveWindow(), bubbles: true, cancelable: true, }); element.dispatchEvent(mouseEvent); if (activeHover === element && !show) { activeHover = undefined; disposable?.dispose(); disposable = undefined; } else { activeHover = element; disposable = list.onDidBlur(() => { toggleCustomHover(element, list); }); } } KeybindingsRegistry.registerCommandAndKeybindingRule({ </ins> id: 'list.toggleExpand', weight: KeybindingWeight.WorkbenchContrib, when: WorkbenchListFocusContextKey,


return result[0].resource; }); } else if (fileExists && (tasksExistInFile || content)) { <del> if (content) { this._configurationService.updateValue('tasks', json.parse(content), target); </del> <ins> const statResource = stat?.resource; if (content && statResource) { this._configurationService.updateValue('tasks', json.parse(content), { resource: statResource }, target); </ins> } <del> return stat?.resource; </del> <ins> return statResource; </ins> } return undefined; }).then((resource) => {


// Do not trigger state if current state is manual and incoming state is automatic if (!isManualToAutoTransition) { this.setState(newState); <ins> } else { // Reset the new state after getting code actions back. setTimeout(() => { this.setState(newState); }, 500); </ins> } }, undefined); this._codeActionOracle.value.trigger({ type: CodeActionTriggerType.Auto, triggerAction: CodeActionTriggerSource.Default });


localize('window.systemColorTheme.light', "Enforce a light system color theme."), localize('window.systemColorTheme.dark', "Enforce a dark system color theme."), ], <del> markdownDescription: localize({ key: 'window.systemColorTheme', comment: ['{0} and {1} will become links to other settings.'] }, "Overrides the system color theme that is used for native UI elements such as native dialogs, menus and title bar. Even if your OS is configured in light appearance mode, you can select a dark system color theme for the window. You can also configure to automatically adjust based on the {0} setting. Note: Using this setting will disable {1}", formatSettingAsLink(ThemeSettings.COLOR_THEME), formatSettingAsLink(ThemeSettings.DETECT_COLOR_SCHEME)), </del> <ins> markdownDescription: localize({ key: 'window.systemColorTheme', comment: ['{0} and {1} will become links to other settings.'] }, "Overrides the system color theme that is used for native UI elements such as native dialogs, menus and title bar. Even if your OS is configured in light appearance mode, you can select a dark system color theme for the window. You can also configure to automatically adjust based on the {0} setting. Note: Using this setting will disable {1}.", formatSettingAsLink(ThemeSettings.COLOR_THEME), formatSettingAsLink(ThemeSettings.DETECT_COLOR_SCHEME)), </ins> default: 'default', included: ENABLE_SYSTEM_COLOR_SCHEME_SETTING, scope: ConfigurationScope.APPLICATION,


import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IThemeService } from 'vs/platform/theme/common/themeService'; <del> import { IActiveNotebookEditor, ICellViewModel, INotebookEditor, type INotebookViewCellsUpdateEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; </del> <ins> import { IActiveNotebookEditor, ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; </ins> import { CellKind, NotebookCellsChangeType, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookExecutionStateService, NotebookExecutionType } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; import { OutlineChangeEvent, OutlineConfigKeys, OutlineTarget } from 'vs/workbench/services/outline/browser/outline';


private _uri: URI | undefined; private _entries: OutlineEntry[] = []; get entries(): OutlineEntry[] { <ins> if (this.delayedOutlineRecompute.isTriggered()) { this.delayedOutlineRecompute.cancel(); this._recomputeState(); } </ins> return this._entries; }


readonly outlineKind = 'notebookCells'; get activeElement(): OutlineEntry | undefined { <ins> if (this.delayedOutlineRecompute.isTriggered()) { this.delayedOutlineRecompute.cancel(); this._recomputeState(); } </ins> return this._activeEntry; } private readonly _outlineEntryFactory: NotebookOutlineEntryFactory; <del> private readonly delayRecomputeActive: () => void; </del> <ins> private readonly delayedOutlineRecompute: Delayer<void>;; </ins> constructor( private readonly _editor: INotebookEditor, private readonly _target: OutlineTarget,


@IConfigurationService private readonly _configurationService: IConfigurationService, ) { this._outlineEntryFactory = new NotebookOutlineEntryFactory(notebookExecutionStateService); <del> const delayerRecomputeActive = this._disposables.add(new Delayer(10)); this.delayRecomputeActive = () => delayerRecomputeActive.trigger(() => this._recomputeActive()); this._disposables.add(Event.debounce<void, void>( _editor.onDidChangeSelection, (last, _current) => last, 200 )(() => { this.delayRecomputeActive(); </del> <ins> const delayerRecomputeActive = this._disposables.add(new Delayer(200)); this._disposables.add(_editor.onDidChangeSelection(() => { delayerRecomputeActive.trigger(() => this._recomputeActive()); </ins> }, this)) <del> this._disposables.add(Event.debounce<INotebookViewCellsUpdateEvent, INotebookViewCellsUpdateEvent>( _editor.onDidChangeViewCells, (last, _current) => last ?? _current, 200 )(() => { this.delayRecomputeActive(); }, this) ); </del> // .3s of a delay is sufficient, 100-200s is too quick and will unnecessarily block the ui thread. // Given we're only updating the outline when the user types, we can afford to wait a bit. <del> const delayer = this._disposables.add(new Delayer<void>(300)); const delayedRecompute = () => delayer.trigger(() => this._recomputeState()); </del> <ins> this.delayedOutlineRecompute = this._disposables.add(new Delayer<void>(300)); const delayedRecompute = () => { delayerRecomputeActive.cancel(); // Active is always recomputed after a recomputing the outline state. this.delayedOutlineRecompute.trigger(() => this._recomputeState()); }; </ins> this._disposables.add(_configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(NotebookSetting.outlineShowMarkdownHeadersOnly) ||


return; } disposable.add(this._editor.textModel.onDidChangeContent(contentChanges => { <del> if (contentChanges.rawEvents.some(c => c.kind === NotebookCellsChangeType.ChangeCellContent)) { </del> <ins> if (contentChanges.rawEvents.some(c => c.kind === NotebookCellsChangeType.ChangeCellContent || c.kind === NotebookCellsChangeType.ChangeCellInternalMetadata || c.kind === NotebookCellsChangeType.Move || c.kind === NotebookCellsChangeType.ModelChange)) { </ins> delayedRecompute(); } }));


} })); <del> this.delayRecomputeActive(); </del> <ins> this._recomputeActive(); </ins> } private _recomputeActive(): { changeEventTriggered: boolean } {


"url": "./schemas/jsconfig.schema.json" }, { <ins> "fileMatch": ".swcrc", "url": "https://swc.rs/schema.json" }, { </ins> "fileMatch": "typedoc.json", "url": "https://typedoc.org/schema.json" }


// tests already encompass their children. if (!test) { // no-op <del> } else if (!test.item.uri) { queue.push(test.children.values()); continue; } else if (ident.extUri.isEqualOrParent(test.item.uri, uri)) { </del> <ins> } else if (test.item.uri && ident.extUri.isEqualOrParent(test.item.uri, uri)) { </ins> yield test; <del> } else if (ident.extUri.isEqualOrParent(uri, test.item.uri)) { </del> <ins> } else if (!test.item.uri || ident.extUri.isEqualOrParent(uri, test.item.uri)) { </ins> if (test.expand === TestItemExpandState.Expandable) { await testService.collection.expand(test.item.extId, 1); }


use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; <del> use const_format::concatcp; </del> use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Request, Response, Server}; use tokio::io::{AsyncBufReadExt, BufReader};


/// Number of bytes for the secret keys. See workbench.ts for their usage. const SECRET_KEY_BYTES: usize = 32; /// Path to mint the key combining server and client parts. <del> const SECRET_KEY_MINT_PATH: &str = "/_vscode-cli/mint-key"; </del> <ins> const SECRET_KEY_MINT_PATH: &str = "_vscode-cli/mint-key"; </ins> /// Cookie set to the `SECRET_KEY_MINT_PATH` const PATH_COOKIE_NAME: &str = "vscode-secret-key-path"; <del> /// Cookie set to the `SECRET_KEY_MINT_PATH` const PATH_COOKIE_VALUE: &str = concatcp!( PATH_COOKIE_NAME, "=", SECRET_KEY_MINT_PATH, "; SameSite=Strict; Path=/" ); </del> /// HTTP-only cookie where the client's secret half is stored. const SECRET_KEY_COOKIE_NAME: &str = "vscode-cli-secret-half";


/// Handler function for an inbound request async fn handle(ctx: HandleContext, req: Request<Body>) -> Result<Response<Body>, Infallible> { let client_key_half = get_client_key_half(&req); <del> let mut res = match req.uri().path() { SECRET_KEY_MINT_PATH => handle_secret_mint(ctx, req), _ => handle_proxied(ctx, req).await, </del> <ins> let path = req.uri().path(); let mut res = if path.starts_with(&ctx.cm.base_path) && path.get(ctx.cm.base_path.len()..).unwrap_or_default() == SECRET_KEY_MINT_PATH { handle_secret_mint(&ctx, req) } else { handle_proxied(&ctx, req).await </ins> }; <del> append_secret_headers(&mut res, &client_key_half); </del> <ins> append_secret_headers(&ctx.cm.base_path, &mut res, &client_key_half); </ins> Ok(res) } <del> async fn handle_proxied(ctx: HandleContext, req: Request<Body>) -> Response<Body> { </del> <ins> async fn handle_proxied(ctx: &HandleContext, req: Request<Body>) -> Response<Body> { </ins> let release = if let Some((r, _)) = get_release_from_path(req.uri().path(), ctx.cm.platform) { r } else {


} } <del> fn handle_secret_mint(ctx: HandleContext, req: Request<Body>) -> Response<Body> { </del> <ins> fn handle_secret_mint(ctx: &HandleContext, req: Request<Body>) -> Response<Body> { </ins> use sha2::{Digest, Sha256}; let mut hasher = Sha256::new();


/// Appends headers to response to maintain the secret storage of the workbench: /// sets the `PATH_COOKIE_VALUE` so workbench.ts knows about the 'mint' endpoint, /// and maintains the http-only cookie the client will use for cookies. <del> fn append_secret_headers(res: &mut Response<Body>, client_key_half: &SecretKeyPart) { </del> <ins> fn append_secret_headers( base_path: &str, res: &mut Response<Body>, client_key_half: &SecretKeyPart, ) { </ins> let headers = res.headers_mut(); headers.append( hyper::header::SET_COOKIE, <del> PATH_COOKIE_VALUE.parse().unwrap(), </del> <ins> format!( "{}={}{}; SameSite=Strict; Path=/", PATH_COOKIE_NAME, base_path, SECRET_KEY_MINT_PATH, ) .parse() .unwrap(), </ins> ); headers.append( hyper::header::SET_COOKIE,


pub platform: Platform, pub log: log::Logger, args: ServeWebArgs, <ins> /// Server base path, ending in `/` base_path: String, </ins> /// Cache where servers are stored cache: DownloadCache, /// Mapping of (Quality, Commit) to the state each server is in


(release.quality, release.commit.clone()) } <ins> fn normalize_base_path(p: &str) -> String { let p = p.trim_matches('/'); if p.is_empty() { return "/".to_string(); } format!("/{}/", p.trim_matches('/')) } </ins> impl ConnectionManager { pub fn new(ctx: &CommandContext, platform: Platform, args: ServeWebArgs) -> Arc<Self> { <ins> let base_path = normalize_base_path(args.server_base_path.as_deref().unwrap_or_default()); </ins> Arc::new(Self { platform, args, <ins> base_path, </ins> log: ctx.log.clone(), cache: DownloadCache::new(ctx.paths.web_server_storage()), update_service: UpdateService::new(


import { Button } from '../../../../base/browser/ui/button/button.js'; import { ITreeElement } from '../../../../base/browser/ui/tree/tree.js'; import { Action } from '../../../../base/common/actions.js'; <del> import { Delayer } from '../../../../base/common/async.js'; </del> <ins> import { Delayer, raceTimeout } from '../../../../base/common/async.js'; </ins> import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js'; import { fromNow } from '../../../../base/common/date.js'; import { isCancellationError } from '../../../../base/common/errors.js';


import { AbstractSettingRenderer, HeightChangeParams, ISettingLinkClickEvent, resolveConfiguredUntrustedSettings, createTocTreeForExtensionSettings, resolveSettingsTree, SettingsTree, SettingTreeRenderers } from './settingsTree.js'; import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from './settingsTreeModels.js'; import { createTOCIterator, TOCTree, TOCTreeModel } from './tocTree.js'; <del> import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, ENABLE_LANGUAGE_FILTER, EXTENSION_SETTING_TAG, FEATURE_SETTING_TAG, ID_SETTING_TAG, IPreferencesSearchService, ISearchProvider, LANGUAGE_SETTING_TAG, MODIFIED_SETTING_TAG, POLICY_SETTING_TAG, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SUGGEST_FILTERS, WORKSPACE_TRUST_SETTING_TAG, getExperimentalExtensionToggleData } from '../common/preferences.js'; </del> <ins> import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, ENABLE_LANGUAGE_FILTER, EXTENSION_FETCH_TIMEOUT_MS, EXTENSION_SETTING_TAG, FEATURE_SETTING_TAG, ID_SETTING_TAG, IPreferencesSearchService, ISearchProvider, LANGUAGE_SETTING_TAG, MODIFIED_SETTING_TAG, POLICY_SETTING_TAG, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SUGGEST_FILTERS, WORKSPACE_TRUST_SETTING_TAG, getExperimentalExtensionToggleData } from '../common/preferences.js'; </ins> import { settingsHeaderBorder, settingsSashBorder, settingsTextInputBorder } from '../common/settingsEditorColorRegistry.js'; import { IEditorGroup, IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; import { IOpenSettingsOptions, IPreferencesService, ISearchResult, ISetting, ISettingsEditorModel, ISettingsEditorOptions, ISettingsGroup, SettingMatchType, SettingValueType, validateSettingsEditorOptions } from '../../../services/preferences/common/preferences.js';


} const extensionId = extension.identifier.id; <ins> // prevent race between extension update handler and this (onConfigUpdate) handler await this.refreshInstalledExtensionsList(); </ins> const extensionInstalled = this.installedExtensionIds.includes(extensionId); // Drill down to see whether the group and setting already exist


// Create the entry. extensionInstalled is false in this case. let manifest: IExtensionManifest | null = null; try { <del> manifest = await this.extensionGalleryService.getManifest(extension, CancellationToken.None); </del> <ins> manifest = await raceTimeout( this.extensionGalleryService.getManifest(extension, CancellationToken.None), EXTENSION_FETCH_TIMEOUT_MS ) ?? null; </ins> } catch (e) { // Likely a networking issue. // Skip adding a button for this extension to the Settings editor. continue; } <ins> if (manifest === null) { continue; } </ins> const contributesConfiguration = manifest?.contributes?.configuration; let groupTitle: string | undefined;


*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <ins> import { raceTimeout } from '../../../../base/common/async.js'; </ins> import { CancellationToken } from '../../../../base/common/cancellation.js'; import { IStringDictionary } from '../../../../base/common/collections.js'; import { IExtensionRecommendations } from '../../../../base/common/product.js';


export const ENABLE_LANGUAGE_FILTER = true; export const ENABLE_EXTENSION_TOGGLE_SETTINGS = true; <ins> export const EXTENSION_FETCH_TIMEOUT_MS = 1000; </ins> export type ExtensionToggleData = { settingsEditorRecommendedExtensions: IStringDictionary<IExtensionRecommendations>;


// Recommend prerelease if not on Stable. const isStable = productService.quality === 'stable'; try { <del> const [extension] = await extensionGalleryService.getExtensions([{ id: extensionId, preRelease: !isStable }], CancellationToken.None); if (extension) { recommendedExtensionsGalleryInfo[key] = extension; </del> <ins> const extensions = await raceTimeout(extensionGalleryService.getExtensions([{ id: extensionId, preRelease: !isStable }], CancellationToken.None), EXTENSION_FETCH_TIMEOUT_MS); if (extensions?.length === 1) { recommendedExtensionsGalleryInfo[key] = extensions[0]; </ins> } else { // same as network connection fail. we do not want a blank settings page: https://github.com/microsoft/vscode/issues/195722 // so instead of returning partial data we return undefined here