From b9dc1b6a96f2b6ef228f310b380921d0b1e0b856 Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Mon, 9 Oct 2023 12:05:52 +0200 Subject: [PATCH 001/290] turn setting into enum --- src/vs/workbench/browser/contextkeys.ts | 2 +- src/vs/workbench/browser/layout.ts | 4 +- .../workbench/browser/parts/editor/editor.ts | 2 +- .../browser/parts/editor/editorDropTarget.ts | 2 +- .../browser/parts/editor/editorGroupView.ts | 6 +- .../browser/parts/editor/editorTabsControl.ts | 4 +- .../parts/editor/editorTitleControl.ts | 27 ++++---- .../parts/editor/noEditorTabsControl.ts | 62 +++++++++++++++++++ .../browser/workbench.contribution.ts | 21 ++++--- src/vs/workbench/common/editor.ts | 2 +- src/vs/workbench/common/theme.ts | 2 +- .../test/browser/editorGroupsService.test.ts | 6 +- 12 files changed, 104 insertions(+), 36 deletions(-) create mode 100644 src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index feca5c8da58..205f570c15f 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -265,7 +265,7 @@ export class WorkbenchContextKeysHandler extends Disposable { } private updateEditorAreaContextKeys(): void { - this.editorTabsVisibleContext.set(!!this.editorGroupService.partOptions.showTabs); + this.editorTabsVisibleContext.set(this.editorGroupService.partOptions.showTabs === 'multiple'); } private updateEditorContextKeys(): void { diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 1ccffa5770e..01d611d63a4 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -1227,8 +1227,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.state.runtime.zenMode.transitionDisposables.add(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off'))); } - if (config.hideTabs && this.editorGroupService.partOptions.showTabs) { - this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: false })); + if (config.hideTabs && this.editorGroupService.partOptions.showTabs === 'multiple') { + this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: 'single' })); } if (config.silentNotifications && zenModeExitInfo.handleNotificationsDoNotDisturbMode) { diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index a2a26d6f7ad..a0edbc678d6 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -25,7 +25,7 @@ export const DEFAULT_EDITOR_MIN_DIMENSIONS = new Dimension(220, 70); export const DEFAULT_EDITOR_MAX_DIMENSIONS = new Dimension(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = { - showTabs: true, + showTabs: 'multiple', highlightModifiedTabs: false, tabCloseButton: 'right', tabSizing: 'fit', diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index db792c89da9..6ba5020526d 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -530,7 +530,7 @@ class DropOverlay extends Themable { private getOverlayOffsetHeight(): number { // With tabs and opened editors: use the area below tabs as drop target - if (!this.groupView.isEmpty && this.editorGroupService.partOptions.showTabs) { + if (!this.groupView.isEmpty && this.editorGroupService.partOptions.showTabs === 'multiple') { return this.groupView.titleHeight.offset; } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 495b28c2684..4ebd1ae2571 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -463,7 +463,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } private updateTitleContainer(): void { - this.titleContainer.classList.toggle('tabs', this.groupsView.partOptions.showTabs); + this.titleContainer.classList.toggle('tabs', this.groupsView.partOptions.showTabs === 'multiple'); this.titleContainer.classList.toggle('show-file-icons', this.groupsView.partOptions.showIcons); } @@ -699,7 +699,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Title control switch between singleEditorTabs, multiEditorTabs and multiRowEditorTabs if ( event.oldPartOptions.showTabs !== event.newPartOptions.showTabs || - (event.oldPartOptions.showTabs && event.oldPartOptions.pinnedTabsOnSeparateRow !== event.newPartOptions.pinnedTabsOnSeparateRow) + (event.oldPartOptions.showTabs === 'multiple' && event.oldPartOptions.pinnedTabsOnSeparateRow !== event.newPartOptions.pinnedTabsOnSeparateRow) ) { // Re-layout @@ -1885,7 +1885,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } const { showTabs } = this.groupsView.partOptions; - this.titleContainer.style.backgroundColor = this.getColor(showTabs ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND) || ''; + this.titleContainer.style.backgroundColor = this.getColor(showTabs === 'multiple' ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND) || ''; // Editor container this.editorContainer.style.backgroundColor = this.getColor(editorBackground) || ''; diff --git a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts index e862a401765..fc75ae4bfde 100644 --- a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts @@ -290,7 +290,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC // Drag all tabs of the group if tabs are enabled let hasDataTransfer = false; - if (this.groupsView.partOptions.showTabs) { + if (this.groupsView.partOptions.showTabs === 'multiple') { hasDataTransfer = this.doFillResourceDataTransfers(this.groupView.getEditors(EditorsOrder.SEQUENTIAL), e); } @@ -309,7 +309,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC // Drag Image if (this.groupView.activeEditor) { let label = this.groupView.activeEditor.getName(); - if (this.groupsView.partOptions.showTabs && this.groupView.count > 1) { + if (this.groupsView.partOptions.showTabs === 'multiple' && this.groupView.count > 1) { label = localize('draggedEditorGroup', "{0} (+{1})", label, this.groupView.count - 1); } diff --git a/src/vs/workbench/browser/parts/editor/editorTitleControl.ts b/src/vs/workbench/browser/parts/editor/editorTitleControl.ts index 69aa10b14b7..38ea136a2a0 100644 --- a/src/vs/workbench/browser/parts/editor/editorTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorTitleControl.ts @@ -17,6 +17,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { MultiRowEditorControl } from 'vs/workbench/browser/parts/editor/multiRowEditorTabsControl'; import { IReadonlyEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel'; +import { NoEditorTabsControl } from 'vs/workbench/browser/parts/editor/noEditorTabsControl'; export interface IEditorTitleControlDimensions { @@ -57,22 +58,26 @@ export class EditorTitleControl extends Themable { } private createEditorTabsControl(): IEditorTabsControl { - let control: IEditorTabsControl; - if (this.groupsView.partOptions.showTabs) { - if (this.groupsView.partOptions.pinnedTabsOnSeparateRow) { - control = this.instantiationService.createInstance(MultiRowEditorControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model); - } else { - control = this.instantiationService.createInstance(MultiEditorTabsControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model); - } - } else { - control = this.instantiationService.createInstance(SingleEditorTabsControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model); + let tabsControlType; + switch (this.groupsView.partOptions.showTabs) { + case 'none': + tabsControlType = NoEditorTabsControl; + break; + case 'single': + tabsControlType = SingleEditorTabsControl; + break; + case 'multiple': + default: + tabsControlType = this.groupsView.partOptions.pinnedTabsOnSeparateRow ? MultiRowEditorControl : MultiEditorTabsControl; + break; } + const control = this.instantiationService.createInstance(tabsControlType, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model); return this.editorTabsControlDisposable.add(control); } private createBreadcrumbsControl(): BreadcrumbsControlFactory | undefined { - if (!this.groupsView.partOptions.showTabs) { + if (this.groupsView.partOptions.showTabs !== 'multiple') { return undefined; // single tabs have breadcrumbs inlined } @@ -170,7 +175,7 @@ export class EditorTitleControl extends Themable { // Update editor tabs control if options changed if ( oldOptions.showTabs !== newOptions.showTabs || - (newOptions.showTabs && oldOptions.pinnedTabsOnSeparateRow !== newOptions.pinnedTabsOnSeparateRow) + (newOptions.showTabs === 'multiple' && oldOptions.pinnedTabsOnSeparateRow !== newOptions.pinnedTabsOnSeparateRow) ) { // Clear old this.editorTabsControlDisposable.clear(); diff --git a/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts b/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts new file mode 100644 index 00000000000..4d426dcf52f --- /dev/null +++ b/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/singleeditortabscontrol'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { EditorTabsControl, IToolbarActions } from 'vs/workbench/browser/parts/editor/editorTabsControl'; +import { Dimension } from 'vs/base/browser/dom'; +import { IEditorTitleControlDimensions } from 'vs/workbench/browser/parts/editor/editorTitleControl'; + +export class NoEditorTabsControl extends EditorTabsControl { + + protected override create(parent: HTMLElement): void { + super.create(parent); + } + + protected override prepareEditorActions(editorActions: IToolbarActions): IToolbarActions { + return { + primary: [], + secondary: [] + }; + } + + openEditor(editor: EditorInput): boolean { + return false; + } + + openEditors(editors: EditorInput[]): boolean { + return false; + } + + beforeCloseEditor(editor: EditorInput): void { } + + closeEditor(editor: EditorInput): void { } + + closeEditors(editors: EditorInput[]): void { } + + moveEditor(editor: EditorInput, fromIndex: number, targetIndex: number): void { } + + pinEditor(editor: EditorInput): void { } + + stickEditor(editor: EditorInput): void { } + + unstickEditor(editor: EditorInput): void { } + + setActive(isActive: boolean): void { } + + updateEditorLabel(editor: EditorInput): void { } + + updateEditorDirty(editor: EditorInput): void { } + + override updateStyles(): void { } + + getHeight(): number { + return 0; + } + + layout(dimensions: IEditorTitleControlDimensions): Dimension { + return new Dimension(dimensions.container.width, this.getHeight()); + } +} diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 2017f37c3b9..c4c8f6f8895 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -38,23 +38,24 @@ const registry = Registry.as(ConfigurationExtensions.Con default: 'default', }, 'workbench.editor.showTabs': { - 'type': 'boolean', + 'type': 'string', + 'enum': ['multiple', 'single', 'none'], 'description': localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."), - 'default': true + 'default': 'multiple' }, 'workbench.editor.wrapTabs': { 'type': 'boolean', - 'markdownDescription': localize('wrapTabs', "Controls whether tabs should be wrapped over multiple lines when exceeding available space or whether a scrollbar should appear instead. This value is ignored when `#workbench.editor.showTabs#` is disabled."), + 'markdownDescription': localize('wrapTabs', "Controls whether tabs should be wrapped over multiple lines when exceeding available space or whether a scrollbar should appear instead. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."), 'default': false }, 'workbench.editor.scrollToSwitchTabs': { 'type': 'boolean', - 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls whether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behavior for that duration. This value is ignored when `#workbench.editor.showTabs#` is disabled."), + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls whether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behavior for that duration. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."), 'default': false }, 'workbench.editor.highlightModifiedTabs': { 'type': 'boolean', - 'markdownDescription': localize('highlightModifiedTabs', "Controls whether a top border is drawn on tabs for editors that have unsaved changes. This value is ignored when `#workbench.editor.showTabs#` is disabled."), + 'markdownDescription': localize('highlightModifiedTabs', "Controls whether a top border is drawn on tabs for editors that have unsaved changes. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."), 'default': false }, 'workbench.editor.decorations.badges': { @@ -140,7 +141,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'type': 'string', 'enum': ['left', 'right', 'off'], 'default': 'right', - 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'. This value is ignored when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.") }, 'workbench.editor.tabSizing': { 'type': 'string', @@ -151,7 +152,7 @@ const registry = Registry.as(ConfigurationExtensions.Con localize('workbench.editor.tabSizing.shrink', "Allow tabs to get smaller when the available space is not enough to show all tabs at once."), localize('workbench.editor.tabSizing.fixed', "Make all tabs the same size, while allowing them to get smaller when the available space is not enough to show all tabs at once.") ], - 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the size of editor tabs. This value is ignored when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the size of editor tabs. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.") }, 'workbench.editor.tabSizingFixedMinWidth': { 'type': 'number', @@ -169,7 +170,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'type': 'string', 'enum': ['default', 'compact'], 'default': 'default', - 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.editor.tabHeight' }, "Controls the height of editor tabs. Also applies to the title control bar when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.editor.tabHeight' }, "Controls the height of editor tabs. Also applies to the title control bar when `#workbench.editor.showTabs#` is not set to `multiple`.") }, 'workbench.editor.pinnedTabSizing': { 'type': 'string', @@ -180,7 +181,7 @@ const registry = Registry.as(ConfigurationExtensions.Con localize('workbench.editor.pinnedTabSizing.compact', "A pinned tab will show in a compact form with only icon or first letter of the editor name."), localize('workbench.editor.pinnedTabSizing.shrink', "A pinned tab shrinks to a compact fixed size showing parts of the editor name.") ], - 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'pinnedTabSizing' }, "Controls the size of pinned editor tabs. Pinned tabs are sorted to the beginning of all opened tabs and typically do not close until unpinned. This value is ignored when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'pinnedTabSizing' }, "Controls the size of pinned editor tabs. Pinned tabs are sorted to the beginning of all opened tabs and typically do not close until unpinned. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.") }, 'workbench.editor.pinnedTabsOnSeparateRow': { 'type': 'boolean', @@ -317,7 +318,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'workbench.editor.doubleClickTabToToggleEditorGroupSizes': { 'type': 'boolean', 'default': true, - 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'doubleClickTabToToggleEditorGroupSizes' }, "Controls whether to maximize/restore the editor group when double clicking on a tab. This value is ignored when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'doubleClickTabToToggleEditorGroupSizes' }, "Controls whether to maximize/restore the editor group when double clicking on a tab. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.") }, 'workbench.editor.limit.enabled': { 'type': 'boolean', diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 41664fd79f8..5c3e8230881 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -1090,7 +1090,7 @@ export interface IWorkbenchEditorConfiguration { } interface IEditorPartConfiguration { - showTabs?: boolean; + showTabs?: 'multiple' | 'single' | 'none'; wrapTabs?: boolean; scrollToSwitchTabs?: boolean; highlightModifiedTabs?: boolean; diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 9d31beaefc2..9de1bf36c1b 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -256,7 +256,7 @@ export const EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND = registerColor('editorGroup light: editorBackground, hcDark: editorBackground, hcLight: editorBackground -}, localize('editorGroupHeaderBackground', "Background color of the editor group title header when tabs are disabled (`\"workbench.editor.showTabs\": false`). Editor groups are the containers of editors.")); +}, localize('editorGroupHeaderBackground', "Background color of the editor group title header when `workbench.editor.showTabs` is not set to multiple. Editor groups are the containers of editors.")); export const EDITOR_GROUP_HEADER_BORDER = registerColor('editorGroupHeader.border', { dark: null, diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 200a6e33a42..02d63db45ad 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -408,9 +408,9 @@ suite('EditorGroupsService', () => { const currentOptions = part.partOptions; assert.ok(currentOptions); - disposables.add(part.enforcePartOptions({ showTabs: false })); - assert.strictEqual(part.partOptions.showTabs, false); - assert.strictEqual(newOptions.showTabs, false); + disposables.add(part.enforcePartOptions({ showTabs: 'single' })); + assert.strictEqual(part.partOptions.showTabs, 'single'); + assert.strictEqual(newOptions.showTabs, 'single'); assert.strictEqual(oldOptions, currentOptions); }); From 2e04ce400a4664e7c162a831c1cfa0f9c1405b52 Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Mon, 9 Oct 2023 14:45:07 +0200 Subject: [PATCH 002/290] Migration support --- src/vs/workbench/browser/parts/editor/editor.ts | 8 ++++++++ src/vs/workbench/browser/workbench.contribution.ts | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index a0edbc678d6..6a462490090 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -80,6 +80,14 @@ export function getEditorPartOptions(configurationService: IConfigurationService } } + // showTabs ensure correct enum value + if (typeof options.showTabs === 'boolean') { + // Migration service kicks in very late and can cause a flicker otherwise + options.showTabs = options.showTabs ? 'multiple' : 'single'; + } else if (options.showTabs !== 'multiple' && options.showTabs !== 'single' && options.showTabs !== 'none') { + options.showTabs = 'multiple'; + } + const windowConfig = configurationService.getValue(); if (windowConfig?.window?.density?.editorTabHeight) { options.tabHeight = windowConfig.window.density.editorTabHeight; diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index de682c9af53..6cc79eea671 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -766,3 +766,14 @@ Registry.as(Extensions.ConfigurationMigration) return result; } }]); + +Registry.as(Extensions.ConfigurationMigration) + .registerConfigurationMigrations([{ + key: 'workbench.editor.showTabs', migrateFn: (value: any) => { + const result: ConfigurationKeyValuePairs = [['workbench.editor.showTabs', { value: value }]]; + if (value === false) { + result.push(['workbench.editor.showTabs', { value: 'single' }]); + } + return result; + } + }]); From ed87c37135154ed3b50a4e60b97443c25faafc59 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:16:30 -0700 Subject: [PATCH 003/290] Ensure terminal is not detached when clearing old input Part of microsoft/vscode-internalbacklog#4626 --- .../contrib/terminal/browser/terminalEditor.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index 23719c3bb76..8b38e35a16e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -85,7 +85,9 @@ export class TerminalEditor extends EditorPane { override clearInput(): void { super.clearInput(); - this._editorInput?.terminalInstance?.detachFromElement(); + if (this._overflowGuardElement && this._editorInput?.terminalInstance?.domElement === this._overflowGuardElement) { + this._editorInput?.detachInstance(); + } this._editorInput = undefined; } @@ -188,7 +190,11 @@ export class TerminalEditor extends EditorPane { } layout(dimension: dom.Dimension): void { - this._editorInput?.terminalInstance?.layout(dimension); + const instance = this._editorInput?.terminalInstance; + if (instance) { + instance.attachToElement(this._overflowGuardElement!); + instance.layout(dimension); + } this._lastDimension = dimension; } From 30871cbe2dae534e2ff85a2bb97c2345d16a3c6d Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Tue, 10 Oct 2023 09:25:49 +0200 Subject: [PATCH 004/290] :lipstick: --- .../browser/parts/editor/media/singleeditortabscontrol.css | 2 +- .../workbench/browser/parts/editor/singleEditorTabsControl.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/media/singleeditortabscontrol.css b/src/vs/workbench/browser/parts/editor/media/singleeditortabscontrol.css index 893920c71c5..f3a7d7b2484 100644 --- a/src/vs/workbench/browser/parts/editor/media/singleeditortabscontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/singleeditortabscontrol.css @@ -28,7 +28,7 @@ /* Breadcrumbs (inline next to single editor tab) */ -.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .no-tabs.title-label { +.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .single-tab.title-label { flex: none; } diff --git a/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts b/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts index 8efda41b36d..0ea58b717d2 100644 --- a/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts @@ -317,7 +317,7 @@ export class SingleEditorTabsControl extends EditorTabsControl { { title, italic: !isEditorPinned, - extraClasses: ['no-tabs', 'title-label'].concat(editor.getLabelExtraClasses()), + extraClasses: ['single-tab', 'title-label'].concat(editor.getLabelExtraClasses()), fileDecorations: { colors: Boolean(options.decorations?.colors), badges: Boolean(options.decorations?.badges) From 5c9a261b6adbc284ab62a02117fd25eb6c75cbf8 Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Tue, 10 Oct 2023 09:48:04 +0200 Subject: [PATCH 005/290] :lipstick: --- .../workbench/browser/parts/editor/editor.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index 6a462490090..2d0ce727b05 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -80,6 +80,17 @@ export function getEditorPartOptions(configurationService: IConfigurationService } } + const windowConfig = configurationService.getValue(); + if (windowConfig?.window?.density?.editorTabHeight) { + options.tabHeight = windowConfig.window.density.editorTabHeight; + } + + validateEditorPartOptions(options); + + return options; +} + +function validateEditorPartOptions(options: IEditorPartOptions) { // showTabs ensure correct enum value if (typeof options.showTabs === 'boolean') { // Migration service kicks in very late and can cause a flicker otherwise @@ -87,13 +98,6 @@ export function getEditorPartOptions(configurationService: IConfigurationService } else if (options.showTabs !== 'multiple' && options.showTabs !== 'single' && options.showTabs !== 'none') { options.showTabs = 'multiple'; } - - const windowConfig = configurationService.getValue(); - if (windowConfig?.window?.density?.editorTabHeight) { - options.tabHeight = windowConfig.window.density.editorTabHeight; - } - - return options; } /** From 6a0b43656e6c0e18b637d5c7dbb460658aee5f58 Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Tue, 10 Oct 2023 10:00:26 +0200 Subject: [PATCH 006/290] :lipstick: --- src/vs/workbench/common/theme.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 9de1bf36c1b..a2d462a28c7 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -256,7 +256,7 @@ export const EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND = registerColor('editorGroup light: editorBackground, hcDark: editorBackground, hcLight: editorBackground -}, localize('editorGroupHeaderBackground', "Background color of the editor group title header when `workbench.editor.showTabs` is not set to multiple. Editor groups are the containers of editors.")); +}, localize('editorGroupHeaderBackground', "Background color of the editor group title header when (`\"workbench.editor.showTabs\": \"single\"`). Editor groups are the containers of editors.")); export const EDITOR_GROUP_HEADER_BORDER = registerColor('editorGroupHeader.border', { dark: null, From 18a25cd5d6ceec8c1112be4985ca4f9f81bb57d7 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 11 Oct 2023 09:05:00 -0700 Subject: [PATCH 007/290] Clarify pipeline actions (#195197) --- .../azure-pipelines/cli/cli-compile-and-publish.yml | 5 +++++ build/azure-pipelines/cli/cli-darwin-sign.yml | 1 + build/azure-pipelines/cli/cli-win32-sign.yml | 7 +++++-- build/azure-pipelines/distro/download-distro.yml | 8 ++++---- build/azure-pipelines/linux/product-build-linux.yml | 6 +++--- build/azure-pipelines/product-compile.yml | 13 +++++++------ build/azure-pipelines/product-publish.yml | 4 +++- build/azure-pipelines/product-release.yml | 2 ++ .../azure-pipelines/publish-types/publish-types.yml | 2 +- build/azure-pipelines/win32/product-build-win32.yml | 4 ++-- 10 files changed, 33 insertions(+), 19 deletions(-) diff --git a/build/azure-pipelines/cli/cli-compile-and-publish.yml b/build/azure-pipelines/cli/cli-compile-and-publish.yml index 37d68e2c51e..af9960d7f5b 100644 --- a/build/azure-pipelines/cli/cli-compile-and-publish.yml +++ b/build/azure-pipelines/cli/cli-compile-and-publish.yml @@ -57,8 +57,10 @@ steps: Write-Host "##vso[task.setvariable variable=VSCODE_CLI_APPLICATION_NAME]$env:VSCODE_CLI_APPLICATION_NAME" Move-Item -Path $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code.exe -Destination "$(Build.ArtifactStagingDirectory)/${env:VSCODE_CLI_APPLICATION_NAME}.exe" + displayName: Stage CLI - task: ArchiveFiles@2 + displayName: Archive CLI inputs: rootFolderOrFile: $(Build.ArtifactStagingDirectory)/$(VSCODE_CLI_APPLICATION_NAME).exe includeRootFolder: false @@ -76,9 +78,11 @@ steps: echo "##vso[task.setvariable variable=VSCODE_CLI_APPLICATION_NAME]$VSCODE_CLI_APPLICATION_NAME" mv $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code $(Build.ArtifactStagingDirectory)/$VSCODE_CLI_APPLICATION_NAME + displayName: Stage CLI - ${{ if contains(parameters.VSCODE_CLI_TARGET, '-darwin') }}: - task: ArchiveFiles@2 + displayName: Archive CLI inputs: rootFolderOrFile: $(Build.ArtifactStagingDirectory)/$(VSCODE_CLI_APPLICATION_NAME) includeRootFolder: false @@ -91,6 +95,7 @@ steps: - ${{ else }}: - task: ArchiveFiles@2 + displayName: Archive CLI inputs: rootFolderOrFile: $(Build.ArtifactStagingDirectory)/$(VSCODE_CLI_APPLICATION_NAME) includeRootFolder: false diff --git a/build/azure-pipelines/cli/cli-darwin-sign.yml b/build/azure-pipelines/cli/cli-darwin-sign.yml index 7d4cbdaecbf..b4cfdc8f10f 100644 --- a/build/azure-pipelines/cli/cli-darwin-sign.yml +++ b/build/azure-pipelines/cli/cli-darwin-sign.yml @@ -41,4 +41,5 @@ steps: displayName: Set asset id variable - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$(ASSET_ID).zip + displayName: Publish signed artifact with ID $(ASSET_ID) artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/cli/cli-win32-sign.yml b/build/azure-pipelines/cli/cli-win32-sign.yml index fe46171aaac..2880eafb85d 100644 --- a/build/azure-pipelines/cli/cli-win32-sign.yml +++ b/build/azure-pipelines/cli/cli-win32-sign.yml @@ -20,12 +20,13 @@ steps: - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - task: DownloadPipelineArtifact@2 - displayName: Download artifacts + displayName: Download artifact inputs: artifact: ${{ target }} path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} - task: ExtractFiles@1 + displayName: Extract artifact inputs: archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }} @@ -42,7 +43,7 @@ steps: displayName: Find ESRP CLI - powershell: node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/sign "*.exe" - displayName: "Code sign" + displayName: Codesign executable - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - powershell: | @@ -51,6 +52,7 @@ steps: displayName: Set asset id variable - task: ArchiveFiles@2 + displayName: Archive signed files inputs: rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }} includeRootFolder: false @@ -58,4 +60,5 @@ steps: archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip - publish: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip + displayName: Publish signed artifact with ID $(ASSET_ID) artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/distro/download-distro.yml b/build/azure-pipelines/distro/download-distro.yml index 2e727b28b4d..a703992aab2 100644 --- a/build/azure-pipelines/distro/download-distro.yml +++ b/build/azure-pipelines/distro/download-distro.yml @@ -10,7 +10,7 @@ steps: - pwsh: | "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$Home/_netrc" -Encoding ASCII condition: and(succeeded(), contains(variables['Agent.OS'], 'windows')) - displayName: Setup distro auth + displayName: Setup distro auth (Windows) - pwsh: | $ErrorActionPreference = "Stop" @@ -26,7 +26,7 @@ steps: Expand-Archive -Path $ArchivePath -DestinationPath .build Rename-Item -Path ".build/microsoft-vscode-distro-$DistroVersion" -NewName distro condition: and(succeeded(), contains(variables['Agent.OS'], 'windows')) - displayName: Download distro + displayName: Download distro (Windows) - script: | mkdir -p .build @@ -36,7 +36,7 @@ steps: password $(github-distro-mixin-password) EOF condition: and(succeeded(), not(contains(variables['Agent.OS'], 'windows'))) - displayName: Setup distro auth + displayName: Setup distro auth (non-Windows) - script: | set -e @@ -53,4 +53,4 @@ steps: mv .build/microsoft-vscode-distro-$DistroVersion .build/distro cp remote/.yarnrc .build/distro/npm/remote/.yarnrc condition: and(succeeded(), not(contains(variables['Agent.OS'], 'windows'))) - displayName: Download distro + displayName: Download distro (non-Windows) diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 2f43515414f..3923d7d105f 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -144,7 +144,7 @@ steps: VSCODE_HOST_MOUNT: "/mnt/vss/_work/1/s" ${{ if or(eq(parameters.VSCODE_ARCH, 'x64'), eq(parameters.VSCODE_ARCH, 'arm64')) }}: VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME: vscodehub.azurecr.io/vscode-linux-build-agent:centos7-devtoolset8-$(VSCODE_ARCH) - displayName: Install dependencies + displayName: Install dependencies (non-OSS) condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) - script: node build/azure-pipelines/distro/mixin-npm @@ -173,7 +173,7 @@ steps: ELECTRON_SKIP_BINARY_DOWNLOAD: 1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 GITHUB_TOKEN: "$(github-distro-mixin-password)" - displayName: Install dependencies + displayName: Install dependencies (OSS) condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) - script: | @@ -252,7 +252,7 @@ steps: - script: yarn gulp "transpile-client-swc" "transpile-extensions" env: GITHUB_TOKEN: "$(github-distro-mixin-password)" - displayName: Transpile + displayName: Transpile client and extensions - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - template: product-build-linux-test.yml diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 5b5be806934..f089eced728 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -103,22 +103,23 @@ steps: - script: yarn npm-run-all -lp core-ci-pr extensions-ci-pr hygiene eslint valid-layers-check vscode-dts-compile-check tsec-compile-check env: GITHUB_TOKEN: "$(github-distro-mixin-password)" - displayName: Compile & Hygiene + displayName: Compile & Hygiene (OSS) - ${{ else }}: - script: yarn npm-run-all -lp core-ci extensions-ci hygiene eslint valid-layers-check vscode-dts-compile-check tsec-compile-check env: GITHUB_TOKEN: "$(github-distro-mixin-password)" - displayName: Compile & Hygiene + displayName: Compile & Hygiene (non-OSS) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - script: | set -e yarn --cwd test/smoke compile yarn --cwd test/integration/browser compile - displayName: Compile test suites + displayName: Compile test suites (non-OSS) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - task: AzureCLI@2 + displayName: Fetch secrets inputs: azureSubscription: "vscode-builds-subscription" scriptType: pscore @@ -136,10 +137,10 @@ steps: AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ node build/azure-pipelines/upload-sourcemaps - displayName: Upload sourcemaps + displayName: Upload sourcemaps to Azure - script: ./build/azure-pipelines/common/extract-telemetry.sh - displayName: Extract Telemetry + displayName: Generate lists of telemetry events - script: tar -cz --ignore-failed-read --exclude='.build/node_modules_cache' --exclude='.build/node_modules_list.txt' --exclude='.build/distro' -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz .build out-* test/integration/browser/out test/smoke/out test/automation/out displayName: Compress compilation artifact @@ -153,7 +154,7 @@ steps: - script: yarn download-builtin-extensions-cg env: GITHUB_TOKEN: "$(github-distro-mixin-password)" - displayName: Built-in extensions component details + displayName: Download component details of built-in extensions - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: "Component Detection" diff --git a/build/azure-pipelines/product-publish.yml b/build/azure-pipelines/product-publish.yml index aa4736874fc..32b0f730551 100644 --- a/build/azure-pipelines/product-publish.yml +++ b/build/azure-pipelines/product-publish.yml @@ -24,6 +24,7 @@ steps: displayName: Download all artifacts_processed text files - task: AzureCLI@2 + displayName: Fetch secrets inputs: azureSubscription: "vscode-builds-subscription" scriptType: pscore @@ -35,6 +36,7 @@ steps: Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" - task: AzureCLI@2 + displayName: Fetch Mooncake secrets inputs: azureSubscription: "vscode-builds-mooncake-subscription" scriptType: pscore @@ -76,7 +78,7 @@ steps: - publish: $(Pipeline.Workspace)/artifacts_processed_$(System.StageAttempt)/artifacts_processed_$(System.StageAttempt).txt artifact: artifacts_processed_$(System.StageAttempt) - displayName: Publish what artifacts were published for this stage attempt + displayName: Publish the artifacts processed for this stage attempt condition: always() - pwsh: | diff --git a/build/azure-pipelines/product-release.yml b/build/azure-pipelines/product-release.yml index 93f5fe9568a..7ab077f3699 100644 --- a/build/azure-pipelines/product-release.yml +++ b/build/azure-pipelines/product-release.yml @@ -9,6 +9,7 @@ steps: versionFilePath: .nvmrc - task: AzureCLI@2 + displayName: Fetch secrets inputs: azureSubscription: "vscode-builds-subscription" scriptType: pscore @@ -26,3 +27,4 @@ steps: AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ node build/azure-pipelines/common/releaseBuild.js ${{ parameters.VSCODE_RELEASE }} + displayName: Release build diff --git a/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml index 6e2e6bedac1..fadb7c8381f 100644 --- a/build/azure-pipelines/publish-types/publish-types.yml +++ b/build/azure-pipelines/publish-types/publish-types.yml @@ -80,4 +80,4 @@ steps: --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE2"'"}' \ https://slack.com/api/chat.postMessage - displayName: Send message on Slack + displayName: Send message linking to changes on Slack diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 7391638cf68..ebfbc701146 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -152,7 +152,7 @@ steps: - powershell: yarn gulp "transpile-client-swc" "transpile-extensions" env: GITHUB_TOKEN: "$(github-distro-mixin-password)" - displayName: Transpile + displayName: Transpile client and extensions - ${{ else }}: - ${{ if and(ne(parameters.VSCODE_CIBUILD, true), eq(parameters.VSCODE_QUALITY, 'insider')) }}: @@ -241,7 +241,7 @@ steps: displayName: Find ESRP CLI - powershell: node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(CodeSigningFolderPath) '*.dll,*.exe,*.node' - displayName: Codesign + displayName: Codesign executables and shared libraries - ${{ if eq(parameters.VSCODE_QUALITY, 'insider') }}: - powershell: node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows-appx $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(CodeSigningFolderPath) '*.appx' From 453e5466943799f275764ae4ec1d120251dd3e46 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 11 Oct 2023 18:09:34 +0200 Subject: [PATCH 008/290] fix padding (#195356) --- src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css index 8f410bc87f6..8934987b817 100644 --- a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css +++ b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css @@ -74,6 +74,7 @@ } .monaco-workbench .sidebar.pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .badge .badge-content { + padding-top: 2px; font-size: 9px; min-width: 11px; height: 16px; From f5b58ec7eb8ef4ebd30d5c5257c8377ae2d2fd7e Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 11 Oct 2023 08:43:49 -0700 Subject: [PATCH 009/290] check the correct variable --- .../workbench/contrib/notebook/browser/view/notebookCellList.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 760303df2a0..1b3ad2962c3 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -1208,7 +1208,7 @@ export class NotebookCellList extends WorkbenchList implements ID const focus = focused.length ? focused[0] : null; // If the cell is growing, we should favor anchoring to the focused cell - if (focused) { + if (focus) { const cellEditorIsFocused = this.view.element(focused[0]).focusMode === CellFocusMode.Editor; const anchorFocusedSetting = this.configurationService.getValue(NotebookSetting.anchorToFocusedCell); const growing = this.view.elementHeight(index) < size; From 33876c27f082973adbddc027e0e532c3648099dd Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 11 Oct 2023 09:44:48 -0700 Subject: [PATCH 010/290] Add suppression comment (#195379) --- src/vs/base/common/htmlContent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index b62f09f07ca..d16621579af 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -57,7 +57,7 @@ export class MarkdownString implements IMarkdownString { } appendText(value: string, newlineStyle: MarkdownStringTextNewlineStyle = MarkdownStringTextNewlineStyle.Paragraph): MarkdownString { - this.value += escapeMarkdownSyntaxTokens(this.supportThemeIcons ? escapeIcons(value) : value) + this.value += escapeMarkdownSyntaxTokens(this.supportThemeIcons ? escapeIcons(value) : value) // CodeQL [SM02383] The Markdown is fully sanitized after being rendered. .replace(/([ \t]+)/g, (_match, g1) => ' '.repeat(g1.length)) // CodeQL [SM02383] The Markdown is fully sanitized after being rendered. .replace(/\>/gm, '\\>') // CodeQL [SM02383] The Markdown is fully sanitized after being rendered. .replace(/\n/g, newlineStyle === MarkdownStringTextNewlineStyle.Break ? '\\\n' : '\n\n'); // CodeQL [SM02383] The Markdown is fully sanitized after being rendered. From 12ae4bf471aac14b512252e0152cb938469a5ed5 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Oct 2023 11:41:01 -0700 Subject: [PATCH 011/290] break from polling if object is disposed of --- .../common/capabilities/commandDetectionCapability.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 39169a64fbc..0dfab15d243 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -71,6 +71,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe private _handleCommandStartOptions?: IHandleCommandOptions; private _commandStartedWindowsBarrier?: Barrier; private _windowsPromptPollingInProcess: boolean = false; + private _isDisposed: boolean = false; get commands(): readonly ITerminalCommand[] { return this._commands; } get executingCommand(): string | undefined { return this._currentCommand.command; } @@ -363,6 +364,11 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._logService.debug('CommandDetectionCapability#handleCommandStart', this._currentCommand.commandStartX, this._currentCommand.commandStartMarker?.line); } + override dispose() { + super.dispose(); + this._isDisposed = true; + } + private async _handleCommandStartWindows(): Promise { if (this._windowsPromptPollingInProcess) { this._windowsPromptPollingInProcess = false; @@ -380,7 +386,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe let i = 0; for (; i < 20; i++) { await timeout(10); - if (!this._windowsPromptPollingInProcess || this._cursorOnNextLine() && this._cursorLineLooksLikeWindowsPrompt()) { + if (this._isDisposed || !this._windowsPromptPollingInProcess || this._cursorOnNextLine() && this._cursorLineLooksLikeWindowsPrompt()) { if (!this._windowsPromptPollingInProcess) { this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling cancelled'); } From 70e0ddd5a116bb51b7524bcb60f60294a9da5a31 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Oct 2023 11:58:14 -0700 Subject: [PATCH 012/290] fix #195374 --- .../browser/terminal.accessibility.contribution.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts index cca36e5c80e..649ef681da3 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts @@ -37,6 +37,7 @@ class TextAreaSyncContribution extends DisposableStore implements ITerminalContr static get(instance: ITerminalInstance): TextAreaSyncContribution | null { return instance.getContribution(TextAreaSyncContribution.ID); } + private _addon: TextAreaSyncAddon | undefined; constructor( private readonly _instance: ITerminalInstance, processManager: ITerminalProcessManager, @@ -45,10 +46,13 @@ class TextAreaSyncContribution extends DisposableStore implements ITerminalContr ) { super(); } - xtermReady(xterm: IXtermTerminal & { raw: Terminal }): void { - const addon = this._instantiationService.createInstance(TextAreaSyncAddon, this._instance.capabilities); - xterm.raw.loadAddon(addon); - addon.activate(xterm.raw); + layout(xterm: IXtermTerminal & { raw: Terminal }): void { + if (this._addon) { + return; + } + this._addon = this.add(this._instantiationService.createInstance(TextAreaSyncAddon, this._instance.capabilities)); + xterm.raw.loadAddon(this._addon); + this._addon.activate(xterm.raw); } } registerTerminalContribution(TextAreaSyncContribution.ID, TextAreaSyncContribution); From 648864cef9ad9c628cd84bfc98dd32f7cbcdb94b Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 11 Oct 2023 12:10:40 -0700 Subject: [PATCH 013/290] must call canActivityBarBeHidden after state is set (#195392) --- src/vs/workbench/browser/layout.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 3f9a6c1b71b..4f33c7fc37d 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -491,11 +491,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.stateModel.setRuntimeValue(LayoutStateKeys.EDITOR_HIDDEN, false); } - // Activity bar cannot be hidden - if (this.stateModel.getRuntimeValue(LayoutStateKeys.ACTIVITYBAR_HIDDEN) && !this.canActivityBarBeHidden()) { - this.stateModel.setRuntimeValue(LayoutStateKeys.ACTIVITYBAR_HIDDEN, false); - } - this.stateModel.onDidChangeState(change => { if (change.key === LayoutStateKeys.ACTIVITYBAR_HIDDEN) { this.setActivityBarHidden(change.value as boolean); @@ -598,6 +593,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } } + // 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); + } + // Window border this.updateWindowBorder(true); } From 10d7700314bdacb2b73206b2a3cb8c557fca5037 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Oct 2023 12:21:23 -0700 Subject: [PATCH 014/290] fix #195401 --- .../accessibility/browser/terminalAccessibilityHelp.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibilityHelp.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibilityHelp.ts index 07597055c0c..7815d8776e8 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibilityHelp.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibilityHelp.ts @@ -76,6 +76,7 @@ export class TerminalAccessibilityHelpProvider extends Disposable implements IAc provideContent(): string { const content = []; content.push(this._descriptionForCommand(TerminalCommandId.FocusAccessibleBuffer, localize('focusAccessibleBuffer', 'The Focus Accessible Buffer ({0}) command enables screen readers to read terminal contents.'), localize('focusAccessibleBufferNoKb', 'The Focus Accessible Buffer command enables screen readers to read terminal contents and is currently not triggerable by a keybinding.'))); + content.push(localize('preserveCursor', 'Customize the behavior of the cursor when toggling between the terminal and accessible view with `terminal.integrated.accessibleViewPreserveCursorPosition.`')); if (this._instance.shellType === WindowsShellType.CommandPrompt) { content.push(localize('commandPromptMigration', "Consider using powershell instead of command prompt for an improved experience")); } From 7479c6917213ca5005fc29502077893c1c8aefbd Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 11 Oct 2023 12:31:59 -0700 Subject: [PATCH 015/290] feat: render welcome message questions near input (#195405) --- src/vs/workbench/api/browser/mainThreadChat.ts | 3 +++ .../workbench/api/common/extHost.protocol.ts | 1 + src/vs/workbench/api/common/extHostChat.ts | 18 ++++++++++++++++++ .../contrib/chat/browser/chatWidget.ts | 2 ++ .../workbench/contrib/chat/common/chatModel.ts | 4 +++- .../contrib/chat/common/chatService.ts | 1 + .../contrib/chat/common/chatServiceImpl.ts | 5 ++++- .../contrib/chat/common/chatViewModel.ts | 1 + .../vscode.proposed.interactive.d.ts | 1 + 9 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadChat.ts b/src/vs/workbench/api/browser/mainThreadChat.ts index 8ccce9f3b1f..630ea5116d2 100644 --- a/src/vs/workbench/api/browser/mainThreadChat.ts +++ b/src/vs/workbench/api/browser/mainThreadChat.ts @@ -109,6 +109,9 @@ export class MainThreadChat extends Disposable implements MainThreadChatShape { provideWelcomeMessage: (token) => { return this._proxy.$provideWelcomeMessage(handle, token); }, + provideSampleQuestions: (token) => { + return this._proxy.$provideSampleQuestions(handle, token); + }, provideSlashCommands: (session, token) => { return this._proxy.$provideSlashCommands(handle, session.id, token); }, diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 1dbe62c996d..710db490444 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1241,6 +1241,7 @@ export interface MainThreadChatShape extends IDisposable { export interface ExtHostChatShape { $prepareChat(handle: number, initialState: any, token: CancellationToken): Promise; $provideWelcomeMessage(handle: number, token: CancellationToken): Promise<(string | IChatReplyFollowup[])[] | undefined>; + $provideSampleQuestions(handle: number, token: CancellationToken): Promise; $provideFollowups(handle: number, sessionId: number, token: CancellationToken): Promise; $provideReply(handle: number, sessionId: number, request: IChatRequestDto, token: CancellationToken): Promise; $removeRequest(handle: number, sessionId: number, requestId: string): void; diff --git a/src/vs/workbench/api/common/extHostChat.ts b/src/vs/workbench/api/common/extHostChat.ts index b4b3ce2b22c..efa6d30c49d 100644 --- a/src/vs/workbench/api/common/extHostChat.ts +++ b/src/vs/workbench/api/common/extHostChat.ts @@ -140,6 +140,24 @@ export class ExtHostChat implements ExtHostChatShape { return rawFollowups?.map(f => typeConvert.ChatFollowup.from(f)); } + async $provideSampleQuestions(handle: number, token: CancellationToken): Promise { + const entry = this._chatProvider.get(handle); + if (!entry) { + return undefined; + } + + if (!entry.provider.provideSampleQuestions) { + return undefined; + } + + const rawFollowups = await entry.provider.provideSampleQuestions(token); + if (!rawFollowups) { + return undefined; + } + + return rawFollowups?.map(f => typeConvert.ChatReplyFollowup.from(f)); + } + $removeRequest(handle: number, sessionId: number, requestId: string): void { const entry = this._chatProvider.get(handle); if (!entry) { diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index ece9f0fd488..706319d7b6f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -264,6 +264,8 @@ export class ChatWidget extends Disposable implements IChatWidget { const lastItem = treeItems[treeItems.length - 1]?.element; if (lastItem && isResponseVM(lastItem) && lastItem.isComplete) { this.renderFollowups(lastItem.replyFollowups); + } else if (lastItem && isWelcomeVM(lastItem)) { + this.renderFollowups(lastItem.sampleQuestions); } else { this.renderFollowups(undefined); } diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index f9ea5dc62cc..58e534489e3 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -551,7 +551,7 @@ export class ChatModel extends Disposable implements IChatModel { if (obj.welcomeMessage) { const content = obj.welcomeMessage.map(item => typeof item === 'string' ? new MarkdownString(item) : item); - this._welcomeMessage = new ChatWelcomeMessageModel(this, content); + this._welcomeMessage = new ChatWelcomeMessageModel(this, content, []); } try { @@ -796,6 +796,7 @@ export type IChatWelcomeMessageContent = IMarkdownString | IChatReplyFollowup[]; export interface IChatWelcomeMessageModel { readonly id: string; readonly content: IChatWelcomeMessageContent[]; + readonly sampleQuestions: IChatReplyFollowup[]; readonly username: string; readonly avatarIconUri?: URI; @@ -812,6 +813,7 @@ export class ChatWelcomeMessageModel implements IChatWelcomeMessageModel { constructor( private readonly session: ChatModel, public readonly content: IChatWelcomeMessageContent[], + public readonly sampleQuestions: IChatReplyFollowup[] ) { this._id = 'welcome_' + ChatWelcomeMessageModel.nextId++; } diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 73a0b7a7381..3d280772e1e 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -108,6 +108,7 @@ export interface IChatProvider { readonly iconUrl?: string; prepareSession(initialState: IPersistedChatState | undefined, token: CancellationToken): ProviderResult; provideWelcomeMessage?(token: CancellationToken): ProviderResult<(string | IChatReplyFollowup[])[] | undefined>; + provideSampleQuestions?(token: CancellationToken): ProviderResult; provideFollowups?(session: IChat, token: CancellationToken): ProviderResult; provideReply(request: IChatRequest, progress: (progress: IChatProgress) => void, token: CancellationToken): ProviderResult; provideSlashCommands?(session: IChat, token: CancellationToken): ProviderResult; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 1ffbac44916..14ed5988349 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -362,7 +362,10 @@ export class ChatService extends Disposable implements IChatService { const welcomeMessage = model.welcomeMessage ? undefined : await provider.provideWelcomeMessage?.(token) ?? undefined; const welcomeModel = welcomeMessage && new ChatWelcomeMessageModel( - model, welcomeMessage.map(item => typeof item === 'string' ? new MarkdownString(item) : item as IChatReplyFollowup[])); + model, + welcomeMessage.map(item => typeof item === 'string' ? new MarkdownString(item) : item as IChatReplyFollowup[]), + await provider.provideSampleQuestions?.(token) ?? [] + ); model.initialize(session, welcomeModel); } catch (err) { diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index 10cfa2b719b..09aa29178b2 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -373,5 +373,6 @@ export interface IChatWelcomeMessageViewModel { readonly username: string; readonly avatarIconUri?: URI; readonly content: IChatWelcomeMessageContent[]; + readonly sampleQuestions: IChatReplyFollowup[]; currentRenderedHeight?: number; } diff --git a/src/vscode-dts/vscode.proposed.interactive.d.ts b/src/vscode-dts/vscode.proposed.interactive.d.ts index e9161140c33..a3c2fd927bf 100644 --- a/src/vscode-dts/vscode.proposed.interactive.d.ts +++ b/src/vscode-dts/vscode.proposed.interactive.d.ts @@ -204,6 +204,7 @@ declare module 'vscode' { export interface InteractiveSessionProvider { provideWelcomeMessage?(token: CancellationToken): ProviderResult; + provideSampleQuestions?(token: CancellationToken): ProviderResult; provideFollowups?(session: S, token: CancellationToken): ProviderResult<(string | InteractiveSessionFollowup)[]>; provideSlashCommands?(session: S, token: CancellationToken): ProviderResult; From 60310a66e475b8d2e2f34d1d2ea4864e05bc28af Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Oct 2023 14:20:11 -0700 Subject: [PATCH 016/290] fix #195280 --- .../contrib/accessibility/browser/accessibleViewActions.ts | 4 ++-- .../contrib/chat/browser/actions/chatCodeblockActions.ts | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts index 0721b08a570..23bea8fe3a2 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts @@ -184,8 +184,8 @@ class AccessibleViewAcceptInlineCompletionAction extends Action2 { id: AccessibilityCommandId.AccessibleViewAcceptInlineCompletion, precondition: ContextKeyExpr.and(accessibleViewIsShown, ContextKeyExpr.equals(accessibleViewCurrentProviderId.key, AccessibleViewProviderId.InlineCompletions)), keybinding: { - primary: KeyMod.CtrlCmd | KeyCode.Slash, - mac: { primary: KeyMod.WinCtrl | KeyCode.Slash }, + primary: KeyMod.CtrlCmd | KeyCode.Enter, + mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, weight: KeybindingWeight.WorkbenchContrib }, icon: Codicon.check, diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index 6899e66a113..58a5874b726 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -180,7 +180,12 @@ export function registerChatCodeBlockActions() { menu: { id: MenuId.ChatCodeBlock, group: 'navigation', - } + }, + keybinding: { + primary: KeyMod.CtrlCmd | KeyCode.Enter, + mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, + weight: KeybindingWeight.WorkbenchContrib + }, }); } From ebf16fa676b806ee7a3655d0038f8812556d1ba0 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Oct 2023 14:26:43 -0700 Subject: [PATCH 017/290] fix #195281 Open --- .../contrib/chat/browser/actions/chatCodeblockActions.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index 6899e66a113..9b9c6d130c9 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -474,7 +474,8 @@ export function registerChatCodeBlockActions() { original: 'Next Code Block' }, keybinding: { - primary: KeyCode.F9, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageDown, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageDown, }, weight: KeybindingWeight.WorkbenchContrib, when: CONTEXT_IN_CHAT_SESSION, }, @@ -498,7 +499,8 @@ export function registerChatCodeBlockActions() { original: 'Previous Code Block' }, keybinding: { - primary: KeyMod.Shift | KeyCode.F9, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageUp, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageUp, }, weight: KeybindingWeight.WorkbenchContrib, when: CONTEXT_IN_CHAT_SESSION, }, From a15b22924c06bd9c12de559dd8e9061ae42c0737 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Oct 2023 14:45:25 -0700 Subject: [PATCH 018/290] other approach --- .../chat/browser/actions/chatCodeblockActions.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index 58a5874b726..ac4e4cb76d7 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -17,8 +17,10 @@ import { ITextModel } from 'vs/editor/common/model'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { CopyAction } from 'vs/editor/contrib/clipboard/browser/clipboard'; import { localize } from 'vs/nls'; +import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { TerminalLocation } from 'vs/platform/terminal/common/terminal'; import { IUntitledTextResourceEditorInput } from 'vs/workbench/common/editor'; @@ -182,6 +184,7 @@ export function registerChatCodeBlockActions() { group: 'navigation', }, keybinding: { + when: CONTEXT_ACCESSIBILITY_MODE_ENABLED, primary: KeyMod.CtrlCmd | KeyCode.Enter, mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, weight: KeybindingWeight.WorkbenchContrib @@ -388,14 +391,20 @@ export function registerChatCodeBlockActions() { group: 'navigation', isHiddenByDefault: true, }, - keybinding: { + keybinding: [{ primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter, mac: { primary: KeyMod.WinCtrl | KeyCode.Enter, }, weight: KeybindingWeight.EditorContrib, - when: CONTEXT_IN_CHAT_SESSION - } + when: ContextKeyExpr.and(CONTEXT_IN_CHAT_SESSION, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), + }, + { + primary: KeyMod.CtrlCmd | KeyCode.Slash, + mac: { primary: KeyMod.WinCtrl | KeyCode.Slash }, + weight: KeybindingWeight.WorkbenchContrib, + when: ContextKeyExpr.and(CONTEXT_IN_CHAT_SESSION, CONTEXT_ACCESSIBILITY_MODE_ENABLED), + }] }); } From 9db355460b2860482d6fc73bf3816649770d562b Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Oct 2023 14:53:20 -0700 Subject: [PATCH 019/290] use todisposable --- .../commandDetectionCapability.ts | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 0dfab15d243..1fb5f28abaf 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -6,7 +6,7 @@ import { Barrier, timeout } from 'vs/base/common/async'; import { debounce } from 'vs/base/common/decorators'; import { Emitter } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { ICommandDetectionCapability, TerminalCapability, ITerminalCommand, IHandleCommandOptions, ICommandInvalidationRequest, CommandInvalidationReason, ISerializedTerminalCommand, ISerializedCommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ITerminalOutputMatch, ITerminalOutputMatcher } from 'vs/platform/terminal/common/terminal'; @@ -71,7 +71,6 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe private _handleCommandStartOptions?: IHandleCommandOptions; private _commandStartedWindowsBarrier?: Barrier; private _windowsPromptPollingInProcess: boolean = false; - private _isDisposed: boolean = false; get commands(): readonly ITerminalCommand[] { return this._commands; } get executingCommand(): string | undefined { return this._currentCommand.command; } @@ -364,11 +363,6 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._logService.debug('CommandDetectionCapability#handleCommandStart', this._currentCommand.commandStartX, this._currentCommand.commandStartMarker?.line); } - override dispose() { - super.dispose(); - this._isDisposed = true; - } - private async _handleCommandStartWindows(): Promise { if (this._windowsPromptPollingInProcess) { this._windowsPromptPollingInProcess = false; @@ -383,20 +377,22 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe if (!this._cursorOnNextLine() || !this._cursorLineLooksLikeWindowsPrompt()) { this._windowsPromptPollingInProcess = true; // Poll for 200ms until the cursor position is correct. - let i = 0; - for (; i < 20; i++) { - await timeout(10); - if (this._isDisposed || !this._windowsPromptPollingInProcess || this._cursorOnNextLine() && this._cursorLineLooksLikeWindowsPrompt()) { - if (!this._windowsPromptPollingInProcess) { - this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling cancelled'); + this._register(toDisposable(async () => { + let i = 0; + for (; i < 20; i++) { + await timeout(10); + if (!this._windowsPromptPollingInProcess || this._cursorOnNextLine() && this._cursorLineLooksLikeWindowsPrompt()) { + if (!this._windowsPromptPollingInProcess) { + this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling cancelled'); + } + break; } - break; } - } - this._windowsPromptPollingInProcess = false; - if (i === 20) { - this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); - } + this._windowsPromptPollingInProcess = false; + if (i === 20) { + this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); + } + })); } else { // HACK: Fire command started on the following frame on Windows to allow the cursor // position to update as conpty often prints the sequence on a different line to the From e01c0a2a8edcd6c2526e4451c48efec77372b46b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:04:39 -0700 Subject: [PATCH 020/290] Defer applying env vars until first prompt Fixes #184009 --- .../fish/vendor_conf.d/shellIntegration.fish | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish b/src/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish index d395be291de..dea46e191da 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish +++ b/src/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish @@ -28,30 +28,37 @@ if status --is-login; and set -q VSCODE_PATH_PREFIX end set -e VSCODE_PATH_PREFIX -# Apply EnvironmentVariableCollections if needed -if test -n "$VSCODE_ENV_REPLACE" - set ITEMS (string split : $VSCODE_ENV_REPLACE) - for B in $ITEMS - set split (string split = $B) - set -gx "$split[1]" (echo -e "$split[2]") +set -g __vsc_applied_env_vars 0 +function __vsc_apply_env_vars + if test $__vsc_applied_env_vars -eq 1; + return end - set -e VSCODE_ENV_REPLACE -end -if test -n "$VSCODE_ENV_PREPEND" - set ITEMS (string split : $VSCODE_ENV_PREPEND) - for B in $ITEMS - set split (string split = $B) - set -gx "$split[1]" (echo -e "$split[2]")"$$split[1]" # avoid -p as it adds a space + set -l __vsc_applied_env_vars 1 + # Apply EnvironmentVariableCollections if needed + if test -n "$VSCODE_ENV_REPLACE" + set ITEMS (string split : $VSCODE_ENV_REPLACE) + for B in $ITEMS + set split (string split = $B) + set -gx "$split[1]" (echo -e "$split[2]") + end + set -e VSCODE_ENV_REPLACE end - set -e VSCODE_ENV_PREPEND -end -if test -n "$VSCODE_ENV_APPEND" - set ITEMS (string split : $VSCODE_ENV_APPEND) - for B in $ITEMS - set split (string split = $B) - set -gx "$split[1]" "$$split[1]"(echo -e "$split[2]") # avoid -a as it adds a space + if test -n "$VSCODE_ENV_PREPEND" + set ITEMS (string split : $VSCODE_ENV_PREPEND) + for B in $ITEMS + set split (string split = $B) + set -gx "$split[1]" (echo -e "$split[2]")"$$split[1]" # avoid -p as it adds a space + end + set -e VSCODE_ENV_PREPEND + end + if test -n "$VSCODE_ENV_APPEND" + set ITEMS (string split : $VSCODE_ENV_APPEND) + for B in $ITEMS + set split (string split = $B) + set -gx "$split[1]" "$$split[1]"(echo -e "$split[2]") # avoid -a as it adds a space + end + set -e VSCODE_ENV_APPEND end - set -e VSCODE_ENV_APPEND end # Handle the shell integration nonce @@ -140,6 +147,9 @@ end # Sent at the start of the prompt. # Marks the beginning of the prompt (and, implicitly, a new line). function __vsc_fish_prompt_start + # Applying environment variables is deferred to after config.fish has been + # evaluated + __vsc_apply_env_vars __vsc_esc A end From fb83c7a46dbdedf47528edfc2b0af1aee9797474 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:26:13 -0700 Subject: [PATCH 021/290] Reparent the quick input when opened from aux window Part of #10121 --- .../quickinput/browser/quickInputController.ts | 10 +++++++++- .../platform/quickinput/browser/quickInputService.ts | 3 ++- .../quickinput/test/browser/quickinput.test.ts | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/quickinput/browser/quickInputController.ts b/src/vs/platform/quickinput/browser/quickInputController.ts index cd748881d21..8578dc5ce1e 100644 --- a/src/vs/platform/quickinput/browser/quickInputController.ts +++ b/src/vs/platform/quickinput/browser/quickInputController.ts @@ -52,7 +52,8 @@ export class QuickInputController extends Disposable { private previousFocusElement?: HTMLElement; constructor(private options: IQuickInputOptions, - private readonly themeService: IThemeService) { + private readonly themeService: IThemeService, + private readonly layoutService: ILayoutService) { super(); this.idPrefix = options.idPrefix; this.parentElement = options.container; @@ -72,6 +73,13 @@ export class QuickInputController extends Disposable { private getUI() { if (this.ui) { + // In order to support aux windows, re-parent the controller if the original event is + // from a different document + if (this.parentElement.ownerDocument !== this.layoutService.activeContainer.ownerDocument) { + this.parentElement = this.layoutService.activeContainer; + dom.append(this.parentElement, this.ui.container); + } + return this.ui; } diff --git a/src/vs/platform/quickinput/browser/quickInputService.ts b/src/vs/platform/quickinput/browser/quickInputService.ts index 924e6b83ef6..a5892ba0281 100644 --- a/src/vs/platform/quickinput/browser/quickInputService.ts +++ b/src/vs/platform/quickinput/browser/quickInputService.ts @@ -93,7 +93,8 @@ export class QuickInputService extends Themable implements IQuickInputService { ...defaultOptions, ...options }, - this.themeService)); + this.themeService, + this.layoutService)); controller.layout(host.dimension, host.offset.quickPickTop); diff --git a/src/vs/platform/quickinput/test/browser/quickinput.test.ts b/src/vs/platform/quickinput/test/browser/quickinput.test.ts index abab15421d7..dd3ef20eafd 100644 --- a/src/vs/platform/quickinput/test/browser/quickinput.test.ts +++ b/src/vs/platform/quickinput/test/browser/quickinput.test.ts @@ -84,7 +84,8 @@ suite('QuickInput', () => { // https://github.com/microsoft/vscode/issues/147543 } } }, - new TestThemeService())); + new TestThemeService(), + { activeContainer: { ownerDocument: null } } as any)); // initial layout controller.layout({ height: 20, width: 40 }, 0); From b97005b9e08afca8be16df9879636916e62c23e8 Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 11 Oct 2023 11:15:56 -0700 Subject: [PATCH 022/290] no need for cell output to update the editor height --- .../contrib/notebook/browser/view/cellParts/cellOutput.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts index b675ee6250c..39491a8f5c9 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts @@ -716,9 +716,6 @@ export class CellOutputContainer extends CellContentPart { DOM.hide(this.templateData.outputShowMoreContainer.domNode); } - const editorHeight = this.templateData.editor.getContentHeight(); - this.viewCell.editorHeight = editorHeight; - this._relayoutCell(); // if it's clearing all outputs, or outputs are all rendered synchronously // shrink immediately as the final output height will be zero. From 901ac65ea9f906d6996ad8e7639ba81acecf1d7c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 11 Oct 2023 20:23:51 -0700 Subject: [PATCH 023/290] Implement chatAgent2 proposal (#194635) * Add notes on chat agent API * Add request ID to context * variables * Add partial implementation for another option for a chat agent API * update * Notes from api sync * More notes * Can invoke an agent and get the response * Provide a real request * Notes * add `slashCommandProvider` - not yet hooked up * add metadata properties inline, some comments * some more notes * Put the new API side-by-side with the old one * Fix agent title in response * Fix agent display * Send slashCommand to request * Hook up variables * Get rid of package.json registration option * Start to implement followups provider * Add comment * make it `slashCommandProvider` all the way, use updateAgent for updates icon, fullName, description * update docs * only ask for slash command completions when completing a slash-word * use complex completion item label for command/agent completions * add `promptText` to `IParsedChatRequestPart` so that some parts don't make it into the prompt (like agent and slash commands) * only allow agent and slash command at the beginning of the prompt * remove unused method * some jsdoc, many renames so that stuff starts with `ChatAgent...` * reduce `createChatAgent` to the minimum, let the rest be set via setters * in the renderer know if an agent has slash command and follow ups, safes IPC calls * use `iconPath` to align with other APIs * more jsdoc and more obvious TODOs * fix chat parser with "late" command * handle error so that the request stops. where is the rendering tho? * Show error message in response properly * Don't blow up global / list * Change proposal name * Inline followup types * fix type * Remove brace in error msg --------- Co-authored-by: Johannes --- build/lib/compilation.js | 4 +- build/lib/compilation.ts | 2 +- .../api/browser/extensionHost.contribution.ts | 1 + .../api/browser/mainThreadChatAgents.ts | 49 ++-- .../api/browser/mainThreadChatAgents2.ts | 80 ++++++ .../workbench/api/common/extHost.api.impl.ts | 7 +- .../workbench/api/common/extHost.protocol.ts | 24 +- src/vs/workbench/api/common/extHostChat.ts | 2 +- .../api/common/extHostChatAgents2.ts | 252 ++++++++++++++++++ .../contrib/chat/browser/chatVariables.ts | 8 +- .../browser/contrib/chatInputEditorContrib.ts | 32 ++- .../contrib/chat/common/chatAgents.ts | 185 ++++--------- .../contrib/chat/common/chatModel.ts | 8 +- .../contrib/chat/common/chatParserTypes.ts | 29 +- .../contrib/chat/common/chatRequestParser.ts | 30 ++- .../contrib/chat/common/chatServiceImpl.ts | 29 +- .../ChatRequestParser_agent_not_first.0.snap | 14 +- ...uestParser_agent_with_question_mark.0.snap | 32 +-- .../ChatRequestParser_agents.0.snap | 10 +- ...hatRequestParser_agents__subCommand.0.snap | 68 +++++ ..._agents_and_variables_and_multiline.0.snap | 49 ++-- ..._and_variables_and_multiline__part2.0.snap | 109 ++++++++ .../test/common/chatRequestParser.test.ts | 39 ++- .../common/extensionsApiProposals.ts | 1 + .../vscode.proposed.chatAgents2.d.ts | 146 ++++++++++ .../vscode.proposed.interactive.d.ts | 2 + ...scode.proposed.interactiveUserActions.d.ts | 4 + 27 files changed, 960 insertions(+), 256 deletions(-) create mode 100644 src/vs/workbench/api/browser/mainThreadChatAgents2.ts create mode 100644 src/vs/workbench/api/common/extHostChatAgents2.ts create mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap create mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap create mode 100644 src/vscode-dts/vscode.proposed.chatAgents2.d.ts diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 64e27dcf45c..5fecfc82ca3 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -237,7 +237,7 @@ function generateApiProposalNames() { catch { eol = os.EOL; } - const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts$/; + const pattern = /vscode\.proposed\.([a-zA-Z\d]+)\.d\.ts$/; const proposalNames = new Set(); const input = es.through(); const output = input @@ -287,4 +287,4 @@ exports.watchApiProposalNamesTask = task.define('watch-api-proposal-names', () = .pipe(util.debounce(task)) .pipe(gulp.dest('src')); }); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGlsYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjb21waWxhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7OztBQUVoRyxtQ0FBbUM7QUFDbkMseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3Qiw2QkFBNkI7QUFDN0IsMENBQTBDO0FBQzFDLDZCQUE2QjtBQUM3Qix5Q0FBNEM7QUFDNUMsK0JBQStCO0FBQy9CLHNDQUFzQztBQUN0QywwQ0FBMEM7QUFDMUMseUJBQXlCO0FBQ3pCLGlDQUFrQztBQUNsQyw4QkFBOEI7QUFDOUIsK0JBQStCO0FBQy9CLDBDQUF5QztBQUV6QyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7QUFHakMsdUVBQXVFO0FBRXZFLE1BQU0sUUFBUSxHQUFHLElBQUEseUJBQWMsR0FBRSxDQUFDO0FBRWxDLFNBQVMsNEJBQTRCLENBQUMsR0FBVztJQUNoRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDckQsTUFBTSxPQUFPLEdBQXVCLEVBQUUsQ0FBQztJQUN2QyxPQUFPLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUN4QixPQUFPLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztJQUN6QixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUMsRUFBRSxDQUFDLENBQUMsc0NBQXNDO1FBQy9FLE9BQU8sQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO0lBQzNCLENBQUM7SUFDRCxPQUFPLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUMxQixPQUFPLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUMxQixPQUFPLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0MsT0FBTyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNFLE9BQU8sT0FBTyxDQUFDO0FBQ2hCLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxHQUFXLEVBQUUsS0FBYyxFQUFFLFNBQWtCLEVBQUUsYUFBeUM7SUFDaEgsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBMkIsQ0FBQztJQUN2RCxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQXFDLENBQUM7SUFHbEYsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxlQUFlLENBQUMsQ0FBQztJQUN6RSxNQUFNLGVBQWUsR0FBRyxFQUFFLEdBQUcsNEJBQTRCLENBQUMsR0FBRyxDQUFDLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO0lBQ2hHLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNaLGVBQWUsQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDO0lBQ3hDLENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxlQUFlLEVBQUU7UUFDNUQsT0FBTyxFQUFFLEtBQUs7UUFDZCxhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQztRQUNyQyxnQkFBZ0IsRUFBRSxPQUFPLGFBQWEsS0FBSyxTQUFTLElBQUksYUFBYSxDQUFDLEdBQUc7S0FDekUsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRXpCLFNBQVMsUUFBUSxDQUFDLEtBQStCO1FBQ2hELE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQThCLENBQUM7UUFFN0QsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDOUQsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFPLEVBQUUsRUFBRSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEUsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDeEYsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVoRixNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDM0IsTUFBTSxNQUFNLEdBQUcsS0FBSzthQUNsQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLHlFQUF5RTthQUMzRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSSxXQUFXLEVBQUUsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUMsQ0FBQzthQUNwRSxJQUFJLENBQUMsUUFBUSxDQUFDO2FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQzthQUMzQixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ3hCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQzthQUMxQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDaEMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQzthQUNsQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLGFBQWEsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRTtZQUNwRCxVQUFVLEVBQUUsS0FBSztZQUNqQixjQUFjLEVBQUUsQ0FBQyxDQUFDLEtBQUs7WUFDdkIsVUFBVSxFQUFFLGVBQWUsQ0FBQyxVQUFVO1NBQ3RDLENBQUMsQ0FBQyxDQUFDO2FBQ0gsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7YUFDdEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFFbEMsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBQ0QsUUFBUSxDQUFDLFlBQVksR0FBRyxHQUFHLEVBQUU7UUFDNUIsT0FBTyxXQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDdkMsQ0FBQyxDQUFDO0lBQ0YsUUFBUSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7SUFDbkMsT0FBTyxRQUFRLENBQUM7QUFDakIsQ0FBQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxHQUFXLEVBQUUsR0FBVyxFQUFFLEdBQVk7SUFFbkUsTUFBTSxJQUFJLEdBQUcsR0FBRyxFQUFFO1FBRWpCLE1BQU0sU0FBUyxHQUFHLGFBQWEsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDM0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEdBQUcsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRTFELE9BQU8sT0FBTzthQUNaLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQzthQUNqQixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLENBQUMsQ0FBQztJQUVGLElBQUksQ0FBQyxRQUFRLEdBQUcsYUFBYSxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7SUFDbEQsT0FBTyxJQUFJLENBQUM7QUFDYixDQUFDO0FBZEQsc0NBY0M7QUFFRCxTQUFnQixXQUFXLENBQUMsR0FBVyxFQUFFLEdBQVcsRUFBRSxLQUFjLEVBQUUsVUFBdUMsRUFBRTtJQUU5RyxNQUFNLElBQUksR0FBRyxHQUFHLEVBQUU7UUFFakIsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFLEdBQUcsVUFBYSxFQUFFLENBQUM7WUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEdBQUcsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzFELE1BQU0sU0FBUyxHQUFHLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdDLElBQUksR0FBRyxLQUFLLEtBQUssRUFBRSxDQUFDO1lBQ25CLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNyQixDQUFDO1FBRUQsbUNBQW1DO1FBQ25DLElBQUksWUFBWSxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNoQyxJQUFJLEtBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNyQyxJQUFJLFlBQVksR0FBRyxJQUFJLGVBQU8sQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFDdEssTUFBTSxxQkFBcUIsR0FBRyxZQUFZLENBQUMsc0JBQXNCLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDMUYsWUFBWSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxVQUFVLEtBQUssQ0FBQyxJQUF5QztnQkFFdkYsTUFBTSxZQUFZLEdBQW1CLEVBQUcsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNsRSxNQUFNLFdBQVcsR0FBRyxDQUFDLE1BQU0scUJBQXFCLENBQUMsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQ3BFLElBQUksV0FBVyxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUMvQixJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUM3QyxJQUFJLENBQUMsU0FBUyxHQUFHLFdBQVcsQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQzdFLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNqQixDQUFDLEVBQUUsS0FBSyxVQUFVLEdBQUc7Z0JBQ3BCLGlCQUFpQjtnQkFDakIsQ0FBQyxNQUFNLHFCQUFxQixDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBRXRDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ1YsWUFBYSxHQUFHLFNBQVMsQ0FBQztZQUNqQyxDQUFDLENBQUMsQ0FBQztRQUNKLENBQUM7UUFFRCxPQUFPLE9BQU87YUFDWixJQUFJLENBQUMsWUFBWSxDQUFDO2FBQ2xCLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO2FBQ3RCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQzthQUNmLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDeEIsQ0FBQyxDQUFDO0lBRUYsSUFBSSxDQUFDLFFBQVEsR0FBRyxXQUFXLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztJQUNoRCxPQUFPLElBQUksQ0FBQztBQUNiLENBQUM7QUEvQ0Qsa0NBK0NDO0FBRUQsU0FBZ0IsU0FBUyxDQUFDLEdBQVcsRUFBRSxLQUFjO0lBRXBELE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRTtRQUNqQixNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFMUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUNoRCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUVsRSxNQUFNLFNBQVMsR0FBRyxJQUFJLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM1QyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFcEIsT0FBTyxRQUFRO2FBQ2IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7YUFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUMxQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLENBQUMsQ0FBQztJQUNGLElBQUksQ0FBQyxRQUFRLEdBQUcsU0FBUyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7SUFDOUMsT0FBTyxJQUFJLENBQUM7QUFDYixDQUFDO0FBbEJELDhCQWtCQztBQUVELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBRTFELE1BQU0sZUFBZTtJQUNILFFBQVEsQ0FBVTtJQUNuQixNQUFNLENBQXlCO0lBRTlCLGFBQWEsQ0FBa0M7SUFDL0MsV0FBVyxDQUF1QjtJQUNsQyxvQkFBb0IsQ0FBZ0M7SUFFckUsWUFBWSxPQUFnQjtRQUMzQixJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQztRQUN4QixJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQztRQUN4QixNQUFNLGNBQWMsR0FBRyxDQUFDLFFBQWdCLEVBQUUsUUFBZ0IsRUFBRSxFQUFFO1lBQzdELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ3BCLE9BQU87WUFDUixDQUFDO1lBQ0QsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7Z0JBQ2xDLE9BQU87WUFDUixDQUFDO1lBQ0QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUM7WUFFcEMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsR0FBRyxFQUFFO2dCQUMzQixJQUFJLENBQUMsb0JBQW9CLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUNwRCxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDckIsQ0FBQyxDQUFDLENBQUM7UUFDSixDQUFDLENBQUM7UUFDRixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksS0FBTSxTQUFRLFNBQVMsQ0FBQyxVQUFVO1lBQ2pELFlBQVksQ0FBQyxRQUFnQixFQUFFLFFBQWdCO2dCQUNyRCxjQUFjLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUNuQyxPQUFPLEtBQUssQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQy9DLENBQUM7U0FDRCxDQUFDO1FBQ0YsSUFBSSxDQUFDLG9CQUFvQixHQUFHLElBQUksU0FBUyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVoRixJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNuQixFQUFFLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFO2dCQUN4QyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDckIsQ0FBQyxDQUFDLENBQUM7UUFDSixDQUFDO0lBQ0YsQ0FBQztJQUVPLGlCQUFpQixHQUF3QixJQUFJLENBQUM7SUFDOUMsWUFBWTtRQUNuQixJQUFJLElBQUksQ0FBQyxpQkFBaUIsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUNyQyxZQUFZLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDckMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztRQUMvQixDQUFDO1FBQ0QsSUFBSSxDQUFDLGlCQUFpQixHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDeEMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztZQUM5QixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDaEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ1IsQ0FBQztJQUVPLElBQUk7UUFDWCxNQUFNLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3BELElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDMUIsNERBQTREO1lBQzVELE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBQ0QsT0FBTyxDQUFDLENBQUM7SUFDVixDQUFDO0lBRU8sSUFBSSxDQUFDLE9BQVksRUFBRSxHQUFHLElBQVc7UUFDeEMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVNLE9BQU87UUFDYixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNiLHlCQUF5QjtZQUN6QixPQUFPO1FBQ1IsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3RCLE9BQU87UUFDUixDQUFDO1FBRUQsRUFBRSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsRCxFQUFFLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLGdEQUFnRCxDQUFDLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdHLElBQUksQ0FBQyxJQUFJLENBQUMsNENBQTRDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLEtBQUssQ0FBQyxDQUFDO1FBQ25GLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDcEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLHFGQUFxRixDQUFDLENBQUM7UUFDbEgsQ0FBQztJQUNGLENBQUM7Q0FDRDtBQUVELFNBQVMsd0JBQXdCO0lBQ2hDLElBQUksR0FBVyxDQUFDO0lBRWhCLElBQUksQ0FBQztRQUNKLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsdUVBQXVFLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDOUcsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNqQyxHQUFHLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUM7SUFDakMsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNSLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ2QsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLHVDQUF1QyxDQUFDO0lBQ3hELE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFFeEMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzNCLE1BQU0sTUFBTSxHQUFHLEtBQUs7U0FDbEIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7U0FDcEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFPLEVBQUUsRUFBRTtRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuQyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWpDLElBQUksS0FBSyxFQUFFLENBQUM7WUFDWCxhQUFhLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdCLENBQUM7SUFDRixDQUFDLEVBQUU7UUFDRixNQUFNLEtBQUssR0FBRyxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDakQsTUFBTSxRQUFRLEdBQUc7WUFDaEIsaUdBQWlHO1lBQ2pHLCtEQUErRDtZQUMvRCxrR0FBa0c7WUFDbEcsa0dBQWtHO1lBQ2xHLEVBQUU7WUFDRixvREFBb0Q7WUFDcEQsRUFBRTtZQUNGLGdEQUFnRDtZQUNoRCxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLElBQUksNkZBQTZGLElBQUksUUFBUSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxFQUFFLENBQUMsRUFBRTtZQUMxSixLQUFLO1lBQ0wsNkRBQTZEO1lBQzdELEVBQUU7U0FDRixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVaLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDO1lBQzFCLElBQUksRUFBRSxtRUFBbUU7WUFDekUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1NBQy9CLENBQUMsQ0FBQyxDQUFDO1FBQ0osSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNsQixDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRUwsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztBQUNqQyxDQUFDO0FBRUQsTUFBTSx3QkFBd0IsR0FBRyxJQUFBLHlCQUFjLEVBQUMsb0JBQW9CLENBQUMsQ0FBQztBQUV6RCxRQUFBLDJCQUEyQixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsNEJBQTRCLEVBQUUsR0FBRyxFQUFFO0lBQ3pGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQztTQUNsQyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztTQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUN0QixJQUFJLENBQUMsd0JBQXdCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDNUMsQ0FBQyxDQUFDLENBQUM7QUFFVSxRQUFBLHlCQUF5QixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxFQUFFO0lBQ3JGLE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsbUJBQW1CLENBQUM7U0FDOUMsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7U0FDaEMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBRTNDLE9BQU8sS0FBSyxDQUFDLG1CQUFtQixFQUFFLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDO1NBQ25ELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3pCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDMUIsQ0FBQyxDQUFDLENBQUMifQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGlsYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjb21waWxhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7OztBQUVoRyxtQ0FBbUM7QUFDbkMseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3Qiw2QkFBNkI7QUFDN0IsMENBQTBDO0FBQzFDLDZCQUE2QjtBQUM3Qix5Q0FBNEM7QUFDNUMsK0JBQStCO0FBQy9CLHNDQUFzQztBQUN0QywwQ0FBMEM7QUFDMUMseUJBQXlCO0FBQ3pCLGlDQUFrQztBQUNsQyw4QkFBOEI7QUFDOUIsK0JBQStCO0FBQy9CLDBDQUF5QztBQUV6QyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7QUFHakMsdUVBQXVFO0FBRXZFLE1BQU0sUUFBUSxHQUFHLElBQUEseUJBQWMsR0FBRSxDQUFDO0FBRWxDLFNBQVMsNEJBQTRCLENBQUMsR0FBVztJQUNoRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDckQsTUFBTSxPQUFPLEdBQXVCLEVBQUUsQ0FBQztJQUN2QyxPQUFPLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUN4QixPQUFPLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztJQUN6QixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUMsRUFBRSxDQUFDLENBQUMsc0NBQXNDO1FBQy9FLE9BQU8sQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO0lBQzNCLENBQUM7SUFDRCxPQUFPLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUMxQixPQUFPLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUMxQixPQUFPLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0MsT0FBTyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNFLE9BQU8sT0FBTyxDQUFDO0FBQ2hCLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxHQUFXLEVBQUUsS0FBYyxFQUFFLFNBQWtCLEVBQUUsYUFBeUM7SUFDaEgsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBMkIsQ0FBQztJQUN2RCxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQXFDLENBQUM7SUFHbEYsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxlQUFlLENBQUMsQ0FBQztJQUN6RSxNQUFNLGVBQWUsR0FBRyxFQUFFLEdBQUcsNEJBQTRCLENBQUMsR0FBRyxDQUFDLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO0lBQ2hHLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNaLGVBQWUsQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDO0lBQ3hDLENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxlQUFlLEVBQUU7UUFDNUQsT0FBTyxFQUFFLEtBQUs7UUFDZCxhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQztRQUNyQyxnQkFBZ0IsRUFBRSxPQUFPLGFBQWEsS0FBSyxTQUFTLElBQUksYUFBYSxDQUFDLEdBQUc7S0FDekUsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRXpCLFNBQVMsUUFBUSxDQUFDLEtBQStCO1FBQ2hELE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQThCLENBQUM7UUFFN0QsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDOUQsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFPLEVBQUUsRUFBRSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEUsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDeEYsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVoRixNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDM0IsTUFBTSxNQUFNLEdBQUcsS0FBSzthQUNsQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLHlFQUF5RTthQUMzRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSSxXQUFXLEVBQUUsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUMsQ0FBQzthQUNwRSxJQUFJLENBQUMsUUFBUSxDQUFDO2FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQzthQUMzQixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ3hCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQzthQUMxQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDaEMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQzthQUNsQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLGFBQWEsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRTtZQUNwRCxVQUFVLEVBQUUsS0FBSztZQUNqQixjQUFjLEVBQUUsQ0FBQyxDQUFDLEtBQUs7WUFDdkIsVUFBVSxFQUFFLGVBQWUsQ0FBQyxVQUFVO1NBQ3RDLENBQUMsQ0FBQyxDQUFDO2FBQ0gsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7YUFDdEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFFbEMsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBQ0QsUUFBUSxDQUFDLFlBQVksR0FBRyxHQUFHLEVBQUU7UUFDNUIsT0FBTyxXQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDdkMsQ0FBQyxDQUFDO0lBQ0YsUUFBUSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7SUFDbkMsT0FBTyxRQUFRLENBQUM7QUFDakIsQ0FBQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxHQUFXLEVBQUUsR0FBVyxFQUFFLEdBQVk7SUFFbkUsTUFBTSxJQUFJLEdBQUcsR0FBRyxFQUFFO1FBRWpCLE1BQU0sU0FBUyxHQUFHLGFBQWEsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDM0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEdBQUcsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRTFELE9BQU8sT0FBTzthQUNaLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQzthQUNqQixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLENBQUMsQ0FBQztJQUVGLElBQUksQ0FBQyxRQUFRLEdBQUcsYUFBYSxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7SUFDbEQsT0FBTyxJQUFJLENBQUM7QUFDYixDQUFDO0FBZEQsc0NBY0M7QUFFRCxTQUFnQixXQUFXLENBQUMsR0FBVyxFQUFFLEdBQVcsRUFBRSxLQUFjLEVBQUUsVUFBdUMsRUFBRTtJQUU5RyxNQUFNLElBQUksR0FBRyxHQUFHLEVBQUU7UUFFakIsSUFBSSxFQUFFLENBQUMsUUFBUSxFQUFFLEdBQUcsVUFBYSxFQUFFLENBQUM7WUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEdBQUcsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzFELE1BQU0sU0FBUyxHQUFHLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdDLElBQUksR0FBRyxLQUFLLEtBQUssRUFBRSxDQUFDO1lBQ25CLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNyQixDQUFDO1FBRUQsbUNBQW1DO1FBQ25DLElBQUksWUFBWSxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNoQyxJQUFJLEtBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNyQyxJQUFJLFlBQVksR0FBRyxJQUFJLGVBQU8sQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFDdEssTUFBTSxxQkFBcUIsR0FBRyxZQUFZLENBQUMsc0JBQXNCLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDMUYsWUFBWSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxVQUFVLEtBQUssQ0FBQyxJQUF5QztnQkFFdkYsTUFBTSxZQUFZLEdBQW1CLEVBQUcsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNsRSxNQUFNLFdBQVcsR0FBRyxDQUFDLE1BQU0scUJBQXFCLENBQUMsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQ3BFLElBQUksV0FBVyxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUMvQixJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUM3QyxJQUFJLENBQUMsU0FBUyxHQUFHLFdBQVcsQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQzdFLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNqQixDQUFDLEVBQUUsS0FBSyxVQUFVLEdBQUc7Z0JBQ3BCLGlCQUFpQjtnQkFDakIsQ0FBQyxNQUFNLHFCQUFxQixDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBRXRDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ1YsWUFBYSxHQUFHLFNBQVMsQ0FBQztZQUNqQyxDQUFDLENBQUMsQ0FBQztRQUNKLENBQUM7UUFFRCxPQUFPLE9BQU87YUFDWixJQUFJLENBQUMsWUFBWSxDQUFDO2FBQ2xCLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO2FBQ3RCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQzthQUNmLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDeEIsQ0FBQyxDQUFDO0lBRUYsSUFBSSxDQUFDLFFBQVEsR0FBRyxXQUFXLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztJQUNoRCxPQUFPLElBQUksQ0FBQztBQUNiLENBQUM7QUEvQ0Qsa0NBK0NDO0FBRUQsU0FBZ0IsU0FBUyxDQUFDLEdBQVcsRUFBRSxLQUFjO0lBRXBELE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRTtRQUNqQixNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFMUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUNoRCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUVsRSxNQUFNLFNBQVMsR0FBRyxJQUFJLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM1QyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFcEIsT0FBTyxRQUFRO2FBQ2IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7YUFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUMxQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLENBQUMsQ0FBQztJQUNGLElBQUksQ0FBQyxRQUFRLEdBQUcsU0FBUyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7SUFDOUMsT0FBTyxJQUFJLENBQUM7QUFDYixDQUFDO0FBbEJELDhCQWtCQztBQUVELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBRTFELE1BQU0sZUFBZTtJQUNILFFBQVEsQ0FBVTtJQUNuQixNQUFNLENBQXlCO0lBRTlCLGFBQWEsQ0FBa0M7SUFDL0MsV0FBVyxDQUF1QjtJQUNsQyxvQkFBb0IsQ0FBZ0M7SUFFckUsWUFBWSxPQUFnQjtRQUMzQixJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQztRQUN4QixJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQztRQUN4QixNQUFNLGNBQWMsR0FBRyxDQUFDLFFBQWdCLEVBQUUsUUFBZ0IsRUFBRSxFQUFFO1lBQzdELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ3BCLE9BQU87WUFDUixDQUFDO1lBQ0QsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7Z0JBQ2xDLE9BQU87WUFDUixDQUFDO1lBQ0QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUM7WUFFcEMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsR0FBRyxFQUFFO2dCQUMzQixJQUFJLENBQUMsb0JBQW9CLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUNwRCxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDckIsQ0FBQyxDQUFDLENBQUM7UUFDSixDQUFDLENBQUM7UUFDRixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksS0FBTSxTQUFRLFNBQVMsQ0FBQyxVQUFVO1lBQ2pELFlBQVksQ0FBQyxRQUFnQixFQUFFLFFBQWdCO2dCQUNyRCxjQUFjLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUNuQyxPQUFPLEtBQUssQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQy9DLENBQUM7U0FDRCxDQUFDO1FBQ0YsSUFBSSxDQUFDLG9CQUFvQixHQUFHLElBQUksU0FBUyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVoRixJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNuQixFQUFFLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFO2dCQUN4QyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDckIsQ0FBQyxDQUFDLENBQUM7UUFDSixDQUFDO0lBQ0YsQ0FBQztJQUVPLGlCQUFpQixHQUF3QixJQUFJLENBQUM7SUFDOUMsWUFBWTtRQUNuQixJQUFJLElBQUksQ0FBQyxpQkFBaUIsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUNyQyxZQUFZLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDckMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztRQUMvQixDQUFDO1FBQ0QsSUFBSSxDQUFDLGlCQUFpQixHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDeEMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztZQUM5QixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDaEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ1IsQ0FBQztJQUVPLElBQUk7UUFDWCxNQUFNLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3BELElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDMUIsNERBQTREO1lBQzVELE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBQ0QsT0FBTyxDQUFDLENBQUM7SUFDVixDQUFDO0lBRU8sSUFBSSxDQUFDLE9BQVksRUFBRSxHQUFHLElBQVc7UUFDeEMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVNLE9BQU87UUFDYixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNiLHlCQUF5QjtZQUN6QixPQUFPO1FBQ1IsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3RCLE9BQU87UUFDUixDQUFDO1FBRUQsRUFBRSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsRCxFQUFFLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLGdEQUFnRCxDQUFDLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdHLElBQUksQ0FBQyxJQUFJLENBQUMsNENBQTRDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLEtBQUssQ0FBQyxDQUFDO1FBQ25GLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDcEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLHFGQUFxRixDQUFDLENBQUM7UUFDbEgsQ0FBQztJQUNGLENBQUM7Q0FDRDtBQUVELFNBQVMsd0JBQXdCO0lBQ2hDLElBQUksR0FBVyxDQUFDO0lBRWhCLElBQUksQ0FBQztRQUNKLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsdUVBQXVFLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDOUcsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNqQyxHQUFHLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUM7SUFDakMsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNSLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ2QsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLHlDQUF5QyxDQUFDO0lBQzFELE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFFeEMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzNCLE1BQU0sTUFBTSxHQUFHLEtBQUs7U0FDbEIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7U0FDcEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFPLEVBQUUsRUFBRTtRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuQyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWpDLElBQUksS0FBSyxFQUFFLENBQUM7WUFDWCxhQUFhLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdCLENBQUM7SUFDRixDQUFDLEVBQUU7UUFDRixNQUFNLEtBQUssR0FBRyxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDakQsTUFBTSxRQUFRLEdBQUc7WUFDaEIsaUdBQWlHO1lBQ2pHLCtEQUErRDtZQUMvRCxrR0FBa0c7WUFDbEcsa0dBQWtHO1lBQ2xHLEVBQUU7WUFDRixvREFBb0Q7WUFDcEQsRUFBRTtZQUNGLGdEQUFnRDtZQUNoRCxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLElBQUksNkZBQTZGLElBQUksUUFBUSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxFQUFFLENBQUMsRUFBRTtZQUMxSixLQUFLO1lBQ0wsNkRBQTZEO1lBQzdELEVBQUU7U0FDRixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVaLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDO1lBQzFCLElBQUksRUFBRSxtRUFBbUU7WUFDekUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1NBQy9CLENBQUMsQ0FBQyxDQUFDO1FBQ0osSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNsQixDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRUwsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztBQUNqQyxDQUFDO0FBRUQsTUFBTSx3QkFBd0IsR0FBRyxJQUFBLHlCQUFjLEVBQUMsb0JBQW9CLENBQUMsQ0FBQztBQUV6RCxRQUFBLDJCQUEyQixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsNEJBQTRCLEVBQUUsR0FBRyxFQUFFO0lBQ3pGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQztTQUNsQyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztTQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUN0QixJQUFJLENBQUMsd0JBQXdCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDNUMsQ0FBQyxDQUFDLENBQUM7QUFFVSxRQUFBLHlCQUF5QixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxFQUFFO0lBQ3JGLE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsbUJBQW1CLENBQUM7U0FDOUMsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7U0FDaEMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBRTNDLE9BQU8sS0FBSyxDQUFDLG1CQUFtQixFQUFFLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDO1NBQ25ELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3pCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDMUIsQ0FBQyxDQUFDLENBQUMifQ== \ No newline at end of file diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index cf2ab921f1c..ebc9dedf2e5 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -277,7 +277,7 @@ function generateApiProposalNames() { eol = os.EOL; } - const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts$/; + const pattern = /vscode\.proposed\.([a-zA-Z\d]+)\.d\.ts$/; const proposalNames = new Set(); const input = es.through(); diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index 4f886cbde2c..85063e0987a 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -21,6 +21,7 @@ import './mainThreadLocalization'; import './mainThreadBulkEdits'; import './mainThreadChatProvider'; import './mainThreadChatAgents'; +import './mainThreadChatAgents2'; import './mainThreadChatVariables'; import './mainThreadCodeInsets'; import './mainThreadCLICommands'; diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents.ts b/src/vs/workbench/api/browser/mainThreadChatAgents.ts index 52b8106cba8..82e0f735c6d 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents.ts @@ -7,7 +7,8 @@ import { DisposableMap } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; import { IProgress } from 'vs/platform/progress/common/progress'; import { ExtHostChatAgentsShape, ExtHostContext, MainContext, MainThreadChatAgentsShape } from 'vs/workbench/api/common/extHost.protocol'; -import { IChatAgentMetadata, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatAgentCommand, IChatAgentMetadata, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatProgress } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatSlashFragment } from 'vs/workbench/contrib/chat/common/chatSlashCommands'; import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; @@ -16,7 +17,7 @@ import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/ext export class MainThreadChatAgents implements MainThreadChatAgentsShape { private readonly _agents = new DisposableMap; - private readonly _pendingProgress = new Map>(); + private readonly _pendingProgress = new Map>(); private readonly _proxy: ExtHostChatAgentsShape; constructor( @@ -34,29 +35,37 @@ export class MainThreadChatAgents implements MainThreadChatAgentsShape { this._agents.clearAndDisposeAll(); } - $registerAgent(handle: number, name: string, metadata: IChatAgentMetadata): void { - if (!this._chatAgentService.hasAgent(name)) { - // dynamic! - this._chatAgentService.registerAgentData({ - id: name, - metadata: revive(metadata) - }); - } - - const d = this._chatAgentService.registerAgentCallback(name, async (prompt, progress, history, token) => { - const requestId = Math.random(); - this._pendingProgress.set(requestId, progress); - try { - return await this._proxy.$invokeAgent(handle, requestId, prompt, { history }, token); - } finally { - this._pendingProgress.delete(requestId); - } + $registerAgent(handle: number, name: string, metadata: IChatAgentMetadata & { subCommands: IChatAgentCommand[] }): void { + const d = this._chatAgentService.registerAgent({ + id: name, + metadata: revive(metadata), + invoke: async (request, progress, history, token) => { + const requestId = Math.random(); + this._pendingProgress.set(requestId, progress); + try { + const result = await this._proxy.$invokeAgent(handle, requestId, request.message, { history }, token); + return { + followUp: result?.followUp ?? [], + }; + } finally { + this._pendingProgress.delete(requestId); + } + }, + async provideSlashCommands() { + return metadata.subCommands; + }, }); this._agents.set(handle, d); } async $handleProgressChunk(requestId: number, chunk: IChatSlashFragment): Promise { - this._pendingProgress.get(requestId)?.report(revive(chunk)); + // An extra step because TS really struggles with type inference in the Revived generic parameter? + const revived = revive(chunk); + if (typeof revived.content === 'string') { + this._pendingProgress.get(requestId)?.report({ content: revived.content }); + } else { + this._pendingProgress.get(requestId)?.report(revived.content); + } } $unregisterCommand(handle: number): void { diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts new file mode 100644 index 00000000000..1e389f6ff7b --- /dev/null +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DisposableMap, IDisposable } from 'vs/base/common/lifecycle'; +import { revive } from 'vs/base/common/marshalling'; +import { IProgress } from 'vs/platform/progress/common/progress'; +import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IExtensionChatAgentMetadata, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; +import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatProgress } from 'vs/workbench/contrib/chat/common/chatService'; +import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; + + +type AgentData = { + dispose: () => void; + name: string; + hasSlashCommands?: boolean; + hasFollowups?: boolean; +}; + +@extHostNamedCustomer(MainContext.MainThreadChatAgents2) +export class MainThreadChatAgents implements MainThreadChatAgentsShape2, IDisposable { + + private readonly _agents = new DisposableMap; + private readonly _pendingProgress = new Map>(); + private readonly _proxy: ExtHostChatAgentsShape2; + + constructor( + extHostContext: IExtHostContext, + @IChatAgentService private readonly _chatAgentService: IChatAgentService + ) { + this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents2); + } + + $unregisterAgent(handle: number): void { + this._agents.deleteAndDispose(handle); + } + + dispose(): void { + this._agents.clearAndDisposeAll(); + } + + $registerAgent(handle: number, name: string, metadata: IExtensionChatAgentMetadata): void { + const d = this._chatAgentService.registerAgent({ + id: name, + metadata: revive(metadata), + invoke: async (request, progress, history, token) => { + const requestId = Math.random(); // Make this a guid + this._pendingProgress.set(requestId, progress); + try { + return await this._proxy.$invokeAgent(handle, requestId, request, { history }, token) ?? {}; + } finally { + this._pendingProgress.delete(requestId); + } + }, + provideSlashCommands: async (token) => { + if (!this._agents.get(handle)?.hasSlashCommands) { + return []; // safe an IPC call + } + return this._proxy.$provideSlashCommands(handle, token); + } + }); + this._agents.set(handle, { name, dispose: d.dispose, hasSlashCommands: metadata.hasSlashCommands }); + } + + $updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void { + const data = this._agents.get(handle); + if (!data) { + throw new Error(`No agent with handle ${handle} registered`); + } + data.hasSlashCommands = metadataUpdate.hasSlashCommands; + this._chatAgentService.updateAgent(data.name, revive(metadataUpdate)); + } + + async $handleProgressChunk(requestId: number, chunk: IChatResponseProgressDto): Promise { + // TODO copy/move $acceptResponseProgress from MainThreadChat + this._pendingProgress.get(requestId)?.report(revive(chunk) as any); + } +} diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 8840c9eb225..a894d5c01ce 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -108,6 +108,7 @@ import { ExtHostChatVariables } from 'vs/workbench/api/common/extHostChatVariabl import { ExtHostRelatedInformation } from 'vs/workbench/api/common/extHostAiRelatedInformation'; import { ExtHostAiEmbeddingVector } from 'vs/workbench/api/common/extHostEmbeddingVector'; import { ExtHostChatAgents } from 'vs/workbench/api/common/extHostChatAgents'; +import { ExtHostChatAgents2 } from 'vs/workbench/api/common/extHostChatAgents2'; export interface IExtensionRegistries { mine: ExtensionDescriptionRegistry; @@ -209,6 +210,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostInteractiveEditor = rpcProtocol.set(ExtHostContext.ExtHostInlineChat, new ExtHostInteractiveEditor(rpcProtocol, extHostCommands, extHostDocuments, extHostLogService)); const extHostChatProvider = rpcProtocol.set(ExtHostContext.ExtHostChatProvider, new ExtHostChatProvider(rpcProtocol, extHostLogService)); const extHostChatAgents = rpcProtocol.set(ExtHostContext.ExtHostChatAgents, new ExtHostChatAgents(rpcProtocol, extHostChatProvider, extHostLogService)); + const extHostChatAgents2 = rpcProtocol.set(ExtHostContext.ExtHostChatAgents2, new ExtHostChatAgents2(rpcProtocol, extHostChatProvider, extHostLogService)); const extHostChatVariables = rpcProtocol.set(ExtHostContext.ExtHostChatVariables, new ExtHostChatVariables(rpcProtocol)); const extHostChat = rpcProtocol.set(ExtHostContext.ExtHostChat, new ExtHostChat(rpcProtocol, extHostLogService)); const extHostAiRelatedInformation = rpcProtocol.set(ExtHostContext.ExtHostAiRelatedInformation, new ExtHostRelatedInformation(rpcProtocol)); @@ -1366,11 +1368,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension, 'mappedEditsProvider'); return extHostLanguageFeatures.registerMappedEditsProvider(extension, selector, provider); }, + createChatAgent(name: string, handler: vscode.ChatAgentHandler) { + checkProposedApiEnabled(extension, 'chatAgents2'); + return extHostChatAgents2.createChatAgent(extension.identifier, name, handler); + }, registerAgent(name: string, agent: vscode.ChatAgent, metadata: vscode.ChatAgentMetadata) { checkProposedApiEnabled(extension, 'chatAgents'); return extHostChatAgents.registerAgent(extension.identifier, name, agent, metadata); } - }; return { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 710db490444..48d318c3795 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -50,7 +50,7 @@ import * as tasks from 'vs/workbench/api/common/shared/tasks'; import { SaveReason } from 'vs/workbench/common/editor'; import { IRevealOptions, ITreeItem, IViewBadge } from 'vs/workbench/common/views'; import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; -import { IChatAgentMetadata } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatAgentCommand, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents'; import { IChatMessage, IChatResponseFragment, IChatResponseProviderMetadata } from 'vs/workbench/contrib/chat/common/chatProvider'; import { IChatDynamicRequest, IChatFollowup, IChatReplyFollowup, IChatResponseErrorDetails, IChatUserActionEvent, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatSlashFragment } from 'vs/workbench/contrib/chat/common/chatSlashCommands'; @@ -1147,15 +1147,33 @@ export interface ExtHostChatProviderShape { } export interface MainThreadChatAgentsShape extends IDisposable { - $registerAgent(handle: number, name: string, metadata: IChatAgentMetadata): void; + $registerAgent(handle: number, name: string, metadata: IChatAgentMetadata & { subCommands: IChatAgentCommand[] }): void; $unregisterAgent(handle: number): void; $handleProgressChunk(requestId: number, chunk: IChatSlashFragment): Promise; } +export interface IExtensionChatAgentMetadata extends Dto { + hasSlashCommands?: boolean; + hasFollowup?: boolean; +} + +export interface MainThreadChatAgentsShape2 extends IDisposable { + $registerAgent(handle: number, name: string, metadata: IExtensionChatAgentMetadata): void; + $updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void; + $unregisterAgent(handle: number): void; + $handleProgressChunk(requestId: number, chunk: IChatResponseProgressDto): Promise; +} + export interface ExtHostChatAgentsShape { $invokeAgent(handle: number, requestId: number, prompt: string, context: { history: IChatMessage[] }, token: CancellationToken): Promise; } +export interface ExtHostChatAgentsShape2 { + $invokeAgent(handle: number, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise; + $provideSlashCommands(handle: number, token: CancellationToken): Promise; + $provideFollowups(handle: number, requestId: number, token: CancellationToken): Promise; +} + export interface MainThreadChatVariablesShape extends IDisposable { $registerVariable(handle: number, data: IChatVariableData): void; $unregisterVariable(handle: number): void; @@ -2665,6 +2683,7 @@ export const MainContext = { MainThreadBulkEdits: createProxyIdentifier('MainThreadBulkEdits'), MainThreadChatProvider: createProxyIdentifier('MainThreadChatProvider'), MainThreadChatAgents: createProxyIdentifier('MainThreadChatAgents'), + MainThreadChatAgents2: createProxyIdentifier('MainThreadChatAgents2'), MainThreadChatVariables: createProxyIdentifier('MainThreadChatVariables'), MainThreadClipboard: createProxyIdentifier('MainThreadClipboard'), MainThreadCommands: createProxyIdentifier('MainThreadCommands'), @@ -2786,6 +2805,7 @@ export const ExtHostContext = { ExtHostInlineChat: createProxyIdentifier('ExtHostInlineChatShape'), ExtHostChat: createProxyIdentifier('ExtHostChat'), ExtHostChatAgents: createProxyIdentifier('ExtHostChatAgents'), + ExtHostChatAgents2: createProxyIdentifier('ExtHostChatAgents'), ExtHostChatVariables: createProxyIdentifier('ExtHostChatVariables'), ExtHostChatProvider: createProxyIdentifier('ExtHostChatProvider'), ExtHostAiRelatedInformation: createProxyIdentifier('ExtHostAiRelatedInformation'), diff --git a/src/vs/workbench/api/common/extHostChat.ts b/src/vs/workbench/api/common/extHostChat.ts index efa6d30c49d..683cff67437 100644 --- a/src/vs/workbench/api/common/extHostChat.ts +++ b/src/vs/workbench/api/common/extHostChat.ts @@ -278,7 +278,7 @@ export class ExtHostChat implements ExtHostChatShape { } async $onDidPerformUserAction(event: IChatUserActionEvent): Promise { - this._onDidPerformUserAction.fire(event); + this._onDidPerformUserAction.fire(event as any); } //#endregion diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts new file mode 100644 index 00000000000..365d4d0d91d --- /dev/null +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -0,0 +1,252 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DeferredPromise, raceCancellation } from 'vs/base/common/async'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { assertType } from 'vs/base/common/types'; +import { URI } from 'vs/base/common/uri'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; +import { Progress } from 'vs/platform/progress/common/progress'; +import { ExtHostChatAgentsShape2, IMainContext, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostChatProvider } from 'vs/workbench/api/common/extHostChatProvider'; +import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; +import { IChatAgentCommand, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; +import { IChatFollowup } from 'vs/workbench/contrib/chat/common/chatService'; +import type * as vscode from 'vscode'; + +export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { + + private static _idPool = 0; + + private readonly _agents = new Map(); + private readonly _proxy: MainThreadChatAgentsShape2; + + constructor( + mainContext: IMainContext, + private readonly _extHostChatProvider: ExtHostChatProvider, + private readonly _logService: ILogService, + ) { + this._proxy = mainContext.getProxy(MainContext.MainThreadChatAgents2); + } + + createChatAgent(extension: ExtensionIdentifier, name: string, handler: vscode.ChatAgentHandler): vscode.ChatAgent2 { + const handle = ExtHostChatAgents2._idPool++; + const agent = new ExtHostChatAgent(extension, name, this._proxy, handle, handler); + this._agents.set(handle, agent); + + this._proxy.$registerAgent(handle, name, {}); + return agent.apiAgent; + } + + async $invokeAgent(handle: number, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise { + const agent = this._agents.get(handle); + if (!agent) { + throw new Error(`[CHAT](${handle}) CANNOT invoke agent because the agent is not registered`); + } + + let done = false; + function throwIfDone() { + if (done) { + throw new Error('Only valid while executing the command'); + } + } + + const commandExecution = new DeferredPromise(); + token.onCancellationRequested(() => commandExecution.complete()); + setTimeout(() => commandExecution.complete(), 3 * 1000); + this._extHostChatProvider.allowListExtensionWhile(agent.extension, commandExecution.p); + + const slashCommand = request.command + ? await agent.validateSlashCommand(request.command) + : undefined; + + + try { + + const task = agent.invoke( + { prompt: request.message, variables: {}, slashCommand }, + { history: context.history.map(typeConvert.ChatMessage.to) }, + new Progress(p => { + throwIfDone(); + const convertedProgress = typeConvert.ChatResponseProgress.from(p); + this._proxy.$handleProgressChunk(requestId, convertedProgress); + }), + token + ); + + return await raceCancellation(Promise.resolve(task).then((result) => { + if (result) { + // An option would be to call provideFollowups here and send the result back to the renderer, rather than store the result + // and wait for the renderer to ask for followups + // agent.provideFollowups(result, token); + return { errorDetails: result.errorDetails }; // TODO timings here + } + + return undefined; + }), token); + + } catch (e) { + this._logService.error(e, agent.extension); + return { + errorDetails: { + message: toErrorMessage(e) + } + }; + + } finally { + done = true; + commandExecution.complete(); + } + } + + async $provideSlashCommands(handle: number, token: CancellationToken): Promise { + const agent = this._agents.get(handle); + if (!agent) { + // this is OK, the agent might have disposed while the request was in flight + return []; + } + return agent.provideSlashCommand(token); + } + + async $provideFollowups(handle: number, requestId: number, token: CancellationToken): Promise { + const agent = this._agents.get(handle); + if (!agent) { + // this is OK, the agent might have disposed while the request was in flight + return []; + } + + // TODO look up result object based on requestId + return agent.provideFollowups(null!, token); + } +} + +class ExtHostChatAgent { + + private _slashCommandProvider: vscode.ChatAgentSlashCommandProvider | undefined; + private _lastSlashCommands: vscode.ChatAgentSlashCommand[] | undefined; + private _followupProvider: vscode.FollowupProvider | undefined; + private _description: string | undefined; + private _fullName: string | undefined; + private _iconPath: URI | undefined; + + constructor( + public readonly extension: ExtensionIdentifier, + private readonly _id: string, + private readonly _proxy: MainThreadChatAgentsShape2, + private readonly _handle: number, + private readonly _callback: vscode.ChatAgentHandler, + ) { } + + + async validateSlashCommand(command: string) { + if (!this._lastSlashCommands) { + await this.provideSlashCommand(CancellationToken.None); + assertType(this._lastSlashCommands); + } + const result = this._lastSlashCommands.find(candidate => candidate.name === command); + if (!result) { + throw new Error(`Unknown slashCommand: ${command}`); + + } + return result; + } + + async provideSlashCommand(token: CancellationToken): Promise { + if (!this._slashCommandProvider) { + return []; + } + const result = await this._slashCommandProvider.provideSlashCommands(token); + if (!result) { + return []; + } + this._lastSlashCommands = result; + return result.map(c => ({ name: c.name, description: c.description })); + } + + async provideFollowups(result: vscode.ChatAgentResult2, token: CancellationToken): Promise { + if (!this._followupProvider) { + return []; + } + const followups = await this._followupProvider.provideFollowups(result, token); + if (!followups) { + return []; + } + return followups.map(f => typeConvert.ChatFollowup.from(f)); + } + + get apiAgent(): vscode.ChatAgent2 { + + let updateScheduled = false; + const updateMetadataSoon = () => { + if (updateScheduled) { + return; + } + updateScheduled = true; + queueMicrotask(() => { + this._proxy.$updateAgent(this._handle, { + description: this._description ?? '', + fullName: this._fullName, + icon: this._iconPath, + hasSlashCommands: this._slashCommandProvider !== undefined, + hasFollowup: this._followupProvider !== undefined, + }); + updateScheduled = false; + }); + }; + + const that = this; + return { + get name() { + return that._id; + }, + get description() { + return that._description ?? ''; + }, + set description(v) { + that._description = v; + updateMetadataSoon(); + }, + get fullName() { + return that._fullName ?? that.extension.value; + }, + set fullName(v) { + that._fullName = v; + updateMetadataSoon(); + }, + get iconPath() { + return that._iconPath; + }, + set iconPath(v) { + that._iconPath = v; + updateMetadataSoon(); + }, + // onDidPerformAction + get slashCommandProvider() { + return that._slashCommandProvider; + }, + set slashCommandProvider(v) { + that._slashCommandProvider = v; + updateMetadataSoon(); + }, + get followupProvider() { + return that._followupProvider; + }, + set followupProvider(v) { + that._followupProvider = v; + updateMetadataSoon(); + }, + dispose() { + that._proxy.$unregisterAgent(that._handle); + }, + } satisfies vscode.ChatAgent2; + } + + invoke(request: vscode.ChatAgentRequest, context: vscode.ChatAgentContext, progress: Progress, token: CancellationToken): vscode.ProviderResult { + return this._callback(request, context, progress, token); + } +} diff --git a/src/vs/workbench/contrib/chat/browser/chatVariables.ts b/src/vs/workbench/contrib/chat/browser/chatVariables.ts index 09e53ac0b3a..90ed4ac45b3 100644 --- a/src/vs/workbench/contrib/chat/browser/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/chatVariables.ts @@ -43,16 +43,16 @@ export class ChatVariablesService implements IChatVariablesService { resolvedVariables[part.variableName] = value; parsedPrompt[i] = `[${part.text}](values:${part.variableName})`; } else { - parsedPrompt[i] = part.text; + parsedPrompt[i] = part.promptText; } }).catch(onUnexpectedExternalError)); } } else if (part instanceof ChatRequestDynamicReferencePart) { // Maybe the dynamic reference should include a full IChatRequestVariableValue[] at the time it is inserted? resolvedVariables[part.referenceText] = [{ level: 'full', value: part.data.toString() }]; - parsedPrompt[i] = `[${part.text}](values:${part.referenceText})`; + parsedPrompt[i] = part.promptText; } else { - parsedPrompt[i] = part.text; + parsedPrompt[i] = part.promptText; } }); @@ -60,7 +60,7 @@ export class ChatVariablesService implements IChatVariablesService { return { variables: resolvedVariables, - prompt: parsedPrompt.join('') + prompt: parsedPrompt.join('').trim() }; } diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index 44ebbee7bf3..2880bd122a3 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { raceCancellation } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Disposable } from 'vs/base/common/lifecycle'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -346,12 +347,17 @@ class AgentCompletions extends Disposable { this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { _debugDisplayName: 'chatAgentSubcommand', triggerCharacters: ['/'], - provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { + provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken) => { const widget = this.chatWidgetService.getWidgetByInputUri(model.uri); if (!widget || !widget.viewModel) { return; } + const range = computeCompletionRanges(model, position, /\/\w*/g); + if (!range) { + return null; + } + const parsedRequest = (await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(widget.viewModel.sessionId, model.getValue())).parts; const usedAgent = parsedRequest.find((p): p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart); if (!usedAgent) { @@ -364,14 +370,16 @@ class AgentCompletions extends Disposable { return; } + const commands = await usedAgent.agent.provideSlashCommands(token); + return { - suggestions: usedAgent.agent.metadata.subCommands.map((c, i) => { + suggestions: commands.map((c, i) => { const withSlash = `/${c.name}`; return { label: withSlash, insertText: `${withSlash} `, detail: c.description, - range: new Range(1, position.column - 1, 1, position.column - 1), + range, kind: CompletionItemKind.Text, // The icons are disabled here anyway }; }) @@ -383,7 +391,7 @@ class AgentCompletions extends Disposable { this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { _debugDisplayName: 'chatAgentAndSubcommand', triggerCharacters: ['/'], - provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { + provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken) => { const widget = this.chatWidgetService.getWidgetByInputUri(model.uri); if (!widget) { return; @@ -395,13 +403,21 @@ class AgentCompletions extends Disposable { } const agents = this.chatAgentService.getAgents(); + const all = agents.map(agent => agent.provideSlashCommands(token)); + const commands = await raceCancellation(Promise.all(all), token); + + if (!commands) { + return; + } + return { - suggestions: agents.flatMap(a => a.metadata.subCommands.map((c, i) => { + suggestions: agents.flatMap((agent, i) => commands[i].map((c, i) => { + const agentLabel = `@${agent.id}`; const withSlash = `/${c.name}`; return { - label: withSlash, - insertText: `@${a.id} ${withSlash} `, - detail: `(@${a.id}) ${c.description}`, + label: { label: withSlash, description: agentLabel }, + insertText: `${agentLabel} ${withSlash} `, + detail: `(${agentLabel}) ${c.description}`, range: new Range(1, 1, 1, 1), kind: CompletionItemKind.Text, // The icons are disabled here anyway }; diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index dcf7c2d4f9e..e6a33f88f88 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -4,68 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from 'vs/base/common/cancellation'; -import { Event, Emitter } from 'vs/base/common/event'; -import { Iterable } from 'vs/base/common/iterator'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { Disposable, DisposableStore, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { localize } from 'vs/nls'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProgress } from 'vs/platform/progress/common/progress'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; -import { IChatFollowup, IChatResponseProgressFileTreeData } from 'vs/workbench/contrib/chat/common/chatService'; -import { IExtensionService, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; -import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; - -//#region extension point - -const agentItem: IJSONSchema = { - type: 'object', - required: ['agent', 'detail'], - properties: { - agent: { - type: 'string', - markdownDescription: localize('agent', "The name of the agent which will be used as prefix.") - }, - detail: { - type: 'string', - markdownDescription: localize('details', "The details of the agent.") - }, - } -}; - -const agentItems: IJSONSchema = { - description: localize('vscode.extension.contributes.slashes', "Contributes agents to chat"), - oneOf: [ - agentItem, - { - type: 'array', - items: agentItem - } - ] -}; - -export const agentsExtPoint = ExtensionsRegistry.registerExtensionPoint({ - extensionPoint: 'agents', - jsonSchema: agentItems -}); +import { IChatFollowup, IChatProgress, IChatResponseErrorDetails, IChatResponseProgressFileTreeData } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables'; //#region agent service, commands etc -export interface IChatAgentData { +export interface IChatAgent { id: string; metadata: IChatAgentMetadata; -} - -function isAgentData(data: any): data is IChatAgentData { - return typeof data === 'object' && data && - typeof data.id === 'string' && - typeof data.detail === 'string'; - // (typeof data.sortText === 'undefined' || typeof data.sortText === 'string') && - // (typeof data.executeImmediately === 'undefined' || typeof data.executeImmediately === 'boolean'); + invoke(request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise; + // provideFollowups?: IChatAgentFollowupProvider; + provideSlashCommands(token: CancellationToken): Promise; } export interface IChatAgentFragment { @@ -78,138 +33,112 @@ export interface IChatAgentCommand { } export interface IChatAgentMetadata { - description: string; - subCommands: IChatAgentCommand[]; + description?: string; + // subCommands: IChatAgentCommand[]; requireCommand?: boolean; // Do some agents not have a default action? isImplicit?: boolean; // Only @workspace. slash commands get promoted to the top-level and this agent is invoked when those are used fullName?: string; icon?: URI; } -export type IChatAgentCallback = { (prompt: string, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise<{ followUp: IChatFollowup[] } | void> }; +export interface IChatAgentRequest { + requestId: string; + command?: string; + message: string; + variables: Record; +} + +export interface IChatAgentResult { + // delete, keep while people are still using the previous API + followUp?: IChatFollowup[]; + errorDetails?: IChatResponseErrorDetails; + timings?: { + firstProgress: number; + totalElapsed: number; + }; +} export const IChatAgentService = createDecorator('chatAgentService'); export interface IChatAgentService { _serviceBrand: undefined; readonly onDidChangeAgents: Event; - registerAgentData(data: IChatAgentData): IDisposable; - registerAgentCallback(id: string, callback: IChatAgentCallback): IDisposable; - registerAgent(data: IChatAgentData, callback: IChatAgentCallback): IDisposable; - invokeAgent(id: string, prompt: string, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise<{ followUp: IChatFollowup[] } | void>; - getAgents(): Array; - getAgent(id: string): IChatAgentData | undefined; + registerAgent(agent: IChatAgent): IDisposable; + invokeAgent(id: string, request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise; + getFollowups(id: string, requestId: string): IChatFollowup[]; + getAgents(): Array; + getAgent(id: string): IChatAgent | undefined; hasAgent(id: string): boolean; + updateAgent(id: string, updateMetadata: IChatAgentMetadata): void; } -type Tuple = { data: IChatAgentData; callback?: IChatAgentCallback }; - export class ChatAgentService extends Disposable implements IChatAgentService { public static readonly AGENT_LEADER = '@'; declare _serviceBrand: undefined; - private readonly _agents = new Map(); + private readonly _agents = new Map(); private readonly _onDidChangeAgents = this._register(new Emitter()); readonly onDidChangeAgents: Event = this._onDidChangeAgents.event; - constructor(@IExtensionService private readonly _extensionService: IExtensionService) { - super(); - } - override dispose(): void { super.dispose(); this._agents.clear(); } - registerAgentData(data: IChatAgentData): IDisposable { - if (this._agents.has(data.id)) { - throw new Error(`Already registered an agent with id ${data.id}}`); + registerAgent(agent: IChatAgent): IDisposable { + if (this._agents.has(agent.id)) { + throw new Error(`Already registered an agent with id ${agent.id}`); } - this._agents.set(data.id, { data }); + this._agents.set(agent.id, { agent }); this._onDidChangeAgents.fire(); return toDisposable(() => { - if (this._agents.delete(data.id)) { + if (this._agents.delete(agent.id)) { this._onDidChangeAgents.fire(); } }); } - registerAgentCallback(id: string, agentCallback: IChatAgentCallback): IDisposable { + updateAgent(id: string, updateMetadata: IChatAgentMetadata): void { const data = this._agents.get(id); if (!data) { throw new Error(`No agent with id ${id} registered`); } - data.callback = agentCallback; - return toDisposable(() => data.callback = undefined); + data.agent.metadata = { ...data.agent.metadata, ...updateMetadata }; + this._onDidChangeAgents.fire(); } - registerAgent(data: IChatAgentData, callback: IChatAgentCallback): IDisposable { - return combinedDisposable( - this.registerAgentData(data), - this.registerAgentCallback(data.id, callback) - ); - } - - getAgents(): Array { - return Array.from(this._agents.values(), v => v.data); + getAgents(): Array { + return Array.from(this._agents.values(), v => v.agent); } hasAgent(id: string): boolean { return this._agents.has(id); } - getAgent(id: string): IChatAgentData | undefined { + getAgent(id: string): IChatAgent | undefined { const data = this._agents.get(id); - return data?.data; + return data?.agent; } - async invokeAgent(id: string, prompt: string, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise<{ followUp: IChatFollowup[] } | void> { + async invokeAgent(id: string, request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise { const data = this._agents.get(id); if (!data) { - throw new Error('No agent with id ${id} NOT registered'); - } - if (!data.callback) { - await this._extensionService.activateByEvent(`onChatAgent:${id}`); - } - if (!data.callback) { - throw new Error(`No agent with id ${id} NOT resolved`); + throw new Error(`No agent with id ${id}`); } - return await data.callback(prompt, progress, history, token); + return await data.agent.invoke(request, progress, history, token); + } + + getFollowups(id: string, requestId: string): IChatFollowup[] { + const data = this._agents.get(id); + if (!data) { + throw new Error(`No agent with id ${id}`); + } + + return []; } } - -class ChatAgentContribution implements IWorkbenchContribution { - constructor(@IChatAgentService chatAgentService: IChatAgentService) { - const contributions = new DisposableStore(); - - agentsExtPoint.setHandler(extensions => { - contributions.clear(); - - for (const entry of extensions) { - if (!isProposedApiEnabled(entry.description, 'chatAgents')) { - entry.collector.error(`The ${agentsExtPoint.name} is proposed API`); - continue; - } - - const { value } = entry; - - for (const candidate of Iterable.wrap(value)) { - - if (!isAgentData(candidate)) { - entry.collector.error(localize('invalid', "Invalid {0}: {1}", agentsExtPoint.name, JSON.stringify(candidate))); - continue; - } - - contributions.add(chatAgentService.registerAgentData({ ...candidate })); - } - } - }); - } -} - -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ChatAgentContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 58e534489e3..bdcb7101521 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -13,7 +13,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { OffsetRange } from 'vs/editor/common/core/offsetRange'; import { ILogService } from 'vs/platform/log/common/log'; -import { IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChat, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatProgress, IChatReplyFollowup, IChatResponse, IChatResponseErrorDetails, IChatResponseProgressFileTreeData, IUsedContext, InteractiveSessionVoteDirection, isIUsedContext } from 'vs/workbench/contrib/chat/common/chatService'; @@ -291,7 +291,7 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel constructor( _response: IMarkdownString | ReadonlyArray, public readonly session: ChatModel, - public readonly agent: IChatAgentData | undefined, + public readonly agent: IChatAgent | undefined, private _isComplete: boolean = false, private _isCanceled = false, private _vote?: InteractiveSessionVoteDirection, @@ -362,7 +362,7 @@ export interface ISerializableChatsData { export interface ISerializableChatAgentData { id: string; - description: string; + description?: string; fullName?: string; icon?: UriComponents; } @@ -644,7 +644,7 @@ export class ChatModel extends Disposable implements IChatModel { return this._requests; } - addRequest(message: IParsedChatRequest | IChatReplyFollowup, chatAgent?: IChatAgentData): ChatRequestModel { + addRequest(message: IParsedChatRequest | IChatReplyFollowup, chatAgent?: IChatAgent): ChatRequestModel { if (!this._session) { throw new Error('addRequest: No session'); } diff --git a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts index e5df0780f4c..0dea56c5e22 100644 --- a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts @@ -6,7 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { IOffsetRange, OffsetRange } from 'vs/editor/common/core/offsetRange'; import { IRange } from 'vs/editor/common/core/range'; -import { IChatAgentData, IChatAgentCommand } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatAgent, IChatAgentCommand } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService'; // These are in a separate file to avoid circular dependencies with the dependencies of the parser @@ -21,12 +21,17 @@ export interface IParsedChatRequestPart { readonly range: IOffsetRange; readonly editorRange: IRange; readonly text: string; + readonly promptText: string; } export class ChatRequestTextPart implements IParsedChatRequestPart { static readonly Kind = 'text'; readonly kind = ChatRequestTextPart.Kind; constructor(readonly range: OffsetRange, readonly editorRange: IRange, readonly text: string) { } + + get promptText(): string { + return this.text; + } } export const chatVariableLeader = '#'; // warning, this also shows up in a regex in the parser @@ -43,6 +48,10 @@ export class ChatRequestVariablePart implements IParsedChatRequestPart { const argPart = this.variableArg ? `:${this.variableArg}` : ''; return `${chatVariableLeader}${this.variableName}${argPart}`; } + + get promptText(): string { + return this.text; + } } /** @@ -51,11 +60,15 @@ export class ChatRequestVariablePart implements IParsedChatRequestPart { export class ChatRequestAgentPart implements IParsedChatRequestPart { static readonly Kind = 'agent'; readonly kind = ChatRequestAgentPart.Kind; - constructor(readonly range: OffsetRange, readonly editorRange: IRange, readonly agent: IChatAgentData) { } + constructor(readonly range: OffsetRange, readonly editorRange: IRange, readonly agent: IChatAgent) { } get text(): string { return `@${this.agent.id}`; } + + get promptText(): string { + return ''; + } } /** @@ -69,6 +82,10 @@ export class ChatRequestAgentSubcommandPart implements IParsedChatRequestPart { get text(): string { return `/${this.command.name}`; } + + get promptText(): string { + return ''; + } } /** @@ -82,6 +99,10 @@ export class ChatRequestSlashCommandPart implements IParsedChatRequestPart { get text(): string { return `/${this.slashCommand.command}`; } + + get promptText(): string { + return ''; + } } /** @@ -99,6 +120,10 @@ export class ChatRequestDynamicReferencePart implements IParsedChatRequestPart { get text(): string { return `$${this.referenceText}`; } + + get promptText(): string { + return `[${this.text}](values:${this.referenceText})`; + } } export function reviveParsedChatRequest(serialized: IParsedChatRequest): IParsedChatRequest { diff --git a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts index 64cb389fb15..6b322bdea63 100644 --- a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts +++ b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts @@ -7,7 +7,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { OffsetRange } from 'vs/editor/common/core/offsetRange'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicReferencePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, IParsedChatRequest, IParsedChatRequestPart, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables'; @@ -79,6 +79,29 @@ export class ChatRequestParser { message.slice(lastPartEnd, message.length))); } + + // fix up parts: + // * only one agent at the beginning of the message + // * only one agent command after the agent or at the beginning of the message + let agentIndex = -1; + for (let i = 0; i < parts.length; i++) { + const part = parts[i]; + if (part instanceof ChatRequestAgentPart) { + if (i === 0) { + agentIndex = 0; + } else { + // agent not first -> make text part + parts[i] = new ChatRequestTextPart(part.range, part.editorRange, part.text); + } + } + if (part instanceof ChatRequestAgentSubcommandPart) { + if (!(i === 0 || agentIndex === 0 && i === 2 && /^\s+$/.test(parts[1].text))) { + // agent command not after agent nor first -> make text part + parts[i] = new ChatRequestTextPart(part.range, part.editorRange, part.text); + } + } + } + return { parts, text: message, @@ -95,7 +118,7 @@ export class ChatRequestParser { const varRange = new OffsetRange(offset, offset + full.length); const varEditorRange = new Range(position.lineNumber, position.column, position.lineNumber, position.column + full.length); - let agent: IChatAgentData | undefined; + let agent: IChatAgent | undefined; if ((agent = this.agentService.getAgent(name))) { if (parts.some(p => p instanceof ChatRequestAgentPart)) { // Only one agent allowed @@ -143,7 +166,8 @@ export class ChatRequestParser { const usedAgent = parts.find((p): p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart); if (usedAgent) { - const subCommand = usedAgent.agent.metadata.subCommands.find(c => c.name === command); + const subCommands = await usedAgent.agent.provideSlashCommands(CancellationToken.None); + const subCommand = subCommands.find(c => c.name === command); if (subCommand) { // Valid agent subcommand return new ChatRequestAgentSubcommandPart(slashRange, slashEditorRange, subCommand); diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 14ed5988349..9586faeb1c3 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -12,6 +12,7 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle' import { revive } from 'vs/base/common/marshalling'; import { StopWatch } from 'vs/base/common/stopwatch'; import { URI, UriComponents } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; import { localize } from 'vs/nls'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -21,10 +22,10 @@ import { Progress } from 'vs/platform/progress/common/progress'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatAgentRequest, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; import { ChatModel, ChatModelInitState, ChatRequestModel, ChatWelcomeMessageModel, IChatModel, ISerializableChatData, ISerializableChatsData, isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel'; -import { ChatRequestAgentPart, ChatRequestSlashCommandPart, IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; +import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser'; import { IChat, IChatCompleteResponse, IChatDetail, IChatDynamicRequest, IChatFollowup, IChatProgress, IChatProvider, IChatProviderInfo, IChatReplyFollowup, IChatRequest, IChatResponse, IChatService, IChatTransferredSessionData, IChatUserActionEvent, ISlashCommand, InteractiveSessionCopyKind, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; @@ -442,6 +443,7 @@ export class ChatService extends Disposable implements IChatService { let request: ChatRequestModel; const agentPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestAgentPart => r instanceof ChatRequestAgentPart); + const agentSlashCommandPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestAgentSubcommandPart => r instanceof ChatRequestAgentSubcommandPart); const commandPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestSlashCommandPart => r instanceof ChatRequestSlashCommandPart); let gotProgress = false; @@ -502,7 +504,7 @@ export class ChatService extends Disposable implements IChatService { let slashCommandFollowups: IChatFollowup[] | void = []; if (typeof message === 'string' && agentPart) { - request = model.addRequest(parsedRequest); + request = model.addRequest(parsedRequest, agentPart.agent); const history: IChatMessage[] = []; for (const request of model.getRequests()) { if (!request.response) { @@ -512,13 +514,24 @@ export class ChatService extends Disposable implements IChatService { history.push({ role: ChatMessageRole.User, content: 'text' in request.message ? request.message.text : request.message.message }); history.push({ role: ChatMessageRole.Assistant, content: request.response.response.asString() }); } - const agentResult = await this.chatAgentService.invokeAgent(agentPart.agent.id, message.substring(agentPart.agent.id.length + 1).trimStart(), new Progress(p => { - const { content } = p; - const data = isCompleteInteractiveProgressTreeData(content) ? content : { content }; - progressCallback(data); + + const requestProps: IChatAgentRequest = { + requestId: generateUuid(), + message: message, + variables: {}, + command: agentSlashCommandPart?.command.name ?? '', + }; + if ('parts' in parsedRequest) { + const varResult = await this.chatVariablesService.resolveVariables(parsedRequest, model, token); + requestProps.variables = varResult.variables; + requestProps.message = varResult.prompt; + } + + const agentResult = await this.chatAgentService.invokeAgent(agentPart.agent.id, requestProps, new Progress(p => { + progressCallback(p); }), history, token); slashCommandFollowups = agentResult?.followUp; - rawResponse = { session: model.session! }; + rawResponse = { session: model.session!, errorDetails: agentResult.errorDetails, timings: agentResult.timings }; } else if (commandPart && typeof message === 'string' && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) { request = model.addRequest(parsedRequest); // contributed slash commands diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap index a6a8d0d1516..0ac17204ee0 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap @@ -25,14 +25,8 @@ endLineNumber: 1, endColumn: 17 }, - agent: { - id: "agent", - metadata: { - description: "", - subCommands: [ { name: "subCommand" } ] - } - }, - kind: "agent" + text: "@agent", + kind: "text" }, { range: { @@ -59,8 +53,8 @@ endLineNumber: 1, endColumn: 29 }, - command: { name: "subCommand" }, - kind: "subcommand" + text: "/subCommand", + kind: "text" }, { range: { diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap index 9c3a2372627..65e2aa78ac0 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap @@ -3,51 +3,35 @@ { range: { start: 0, - endExclusive: 14 + endExclusive: 6 }, editorRange: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, - endColumn: 15 - }, - text: "Are you there ", - kind: "text" - }, - { - range: { - start: 14, - endExclusive: 20 - }, - editorRange: { - startLineNumber: 1, - startColumn: 15, - endLineNumber: 1, - endColumn: 21 + endColumn: 7 }, agent: { id: "agent", - metadata: { - description: "", - subCommands: [ { name: "subCommand" } ] - } + metadata: { description: "" }, + provideSlashCommands: [Function provideSlashCommands] }, kind: "agent" }, { range: { - start: 20, + start: 6, endExclusive: 21 }, editorRange: { startLineNumber: 1, - startColumn: 21, + startColumn: 7, endLineNumber: 1, endColumn: 22 }, - text: "?", + text: "? Are you there", kind: "text" } ], - text: "Are you there @agent?" + text: "@agent? Are you there" } \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents.0.snap index f89e75eabf3..8a83800323f 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents.0.snap @@ -13,10 +13,8 @@ }, agent: { id: "agent", - metadata: { - description: "", - subCommands: [ { name: "subCommand" } ] - } + metadata: { description: "" }, + provideSlashCommands: [Function provideSlashCommands] }, kind: "agent" }, @@ -45,8 +43,8 @@ endLineNumber: 1, endColumn: 29 }, - command: { name: "subCommand" }, - kind: "subcommand" + text: "/subCommand", + kind: "text" }, { range: { diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap new file mode 100644 index 00000000000..ca9a0569fcd --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap @@ -0,0 +1,68 @@ +{ + parts: [ + { + range: { + start: 0, + endExclusive: 6 + }, + editorRange: { + startLineNumber: 1, + startColumn: 1, + endLineNumber: 1, + endColumn: 7 + }, + agent: { + id: "agent", + metadata: { description: "" }, + provideSlashCommands: [Function provideSlashCommands] + }, + kind: "agent" + }, + { + range: { + start: 6, + endExclusive: 7 + }, + editorRange: { + startLineNumber: 1, + startColumn: 7, + endLineNumber: 1, + endColumn: 8 + }, + text: " ", + kind: "text" + }, + { + range: { + start: 7, + endExclusive: 18 + }, + editorRange: { + startLineNumber: 1, + startColumn: 8, + endLineNumber: 1, + endColumn: 19 + }, + command: { + name: "subCommand", + description: "" + }, + kind: "subcommand" + }, + { + range: { + start: 18, + endExclusive: 35 + }, + editorRange: { + startLineNumber: 1, + startColumn: 19, + endLineNumber: 1, + endColumn: 36 + }, + text: " Please do thanks", + kind: "text" + } + ], + text: "@agent /subCommand Please do thanks" +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap index 27a7c90ce8c..750f1bc39f6 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap @@ -13,53 +13,54 @@ }, agent: { id: "agent", - metadata: { - description: "", - subCommands: [ { name: "subCommand" } ] - } + metadata: { description: "" }, + provideSlashCommands: [Function provideSlashCommands] }, kind: "agent" }, { range: { start: 6, - endExclusive: 18 + endExclusive: 7 }, editorRange: { startLineNumber: 1, startColumn: 7, - endLineNumber: 2, - endColumn: 4 + endLineNumber: 1, + endColumn: 8 }, - text: " Please \ndo ", + text: " ", kind: "text" }, { range: { - start: 18, - endExclusive: 29 + start: 7, + endExclusive: 18 }, editorRange: { - startLineNumber: 2, - startColumn: 4, - endLineNumber: 2, - endColumn: 15 + startLineNumber: 1, + startColumn: 8, + endLineNumber: 1, + endColumn: 19 + }, + command: { + name: "subCommand", + description: "" }, - command: { name: "subCommand" }, kind: "subcommand" }, { range: { - start: 29, + start: 18, endExclusive: 35 }, editorRange: { - startLineNumber: 2, - startColumn: 15, + startLineNumber: 1, + startColumn: 19, endLineNumber: 2, - endColumn: 21 + endColumn: 16 }, - text: " with ", + text: " \nPlease do with ", kind: "text" }, { @@ -69,9 +70,9 @@ }, editorRange: { startLineNumber: 2, - startColumn: 21, + startColumn: 16, endLineNumber: 2, - endColumn: 31 + endColumn: 26 }, variableName: "selection", variableArg: "", @@ -84,7 +85,7 @@ }, editorRange: { startLineNumber: 2, - startColumn: 31, + startColumn: 26, endLineNumber: 3, endColumn: 5 }, @@ -107,5 +108,5 @@ kind: "var" } ], - text: "@agent Please \ndo /subCommand with #selection\nand #debugConsole" + text: "@agent /subCommand \nPlease do with #selection\nand #debugConsole" } \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap new file mode 100644 index 00000000000..3708cf78541 --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap @@ -0,0 +1,109 @@ +{ + parts: [ + { + range: { + start: 0, + endExclusive: 6 + }, + editorRange: { + startLineNumber: 1, + startColumn: 1, + endLineNumber: 1, + endColumn: 7 + }, + agent: { + id: "agent", + metadata: { description: "" }, + provideSlashCommands: [Function provideSlashCommands] + }, + kind: "agent" + }, + { + range: { + start: 6, + endExclusive: 18 + }, + editorRange: { + startLineNumber: 1, + startColumn: 7, + endLineNumber: 2, + endColumn: 4 + }, + text: " Please \ndo ", + kind: "text" + }, + { + range: { + start: 18, + endExclusive: 29 + }, + editorRange: { + startLineNumber: 2, + startColumn: 4, + endLineNumber: 2, + endColumn: 15 + }, + text: "/subCommand", + kind: "text" + }, + { + range: { + start: 29, + endExclusive: 35 + }, + editorRange: { + startLineNumber: 2, + startColumn: 15, + endLineNumber: 2, + endColumn: 21 + }, + text: " with ", + kind: "text" + }, + { + range: { + start: 35, + endExclusive: 45 + }, + editorRange: { + startLineNumber: 2, + startColumn: 21, + endLineNumber: 2, + endColumn: 31 + }, + variableName: "selection", + variableArg: "", + kind: "var" + }, + { + range: { + start: 45, + endExclusive: 50 + }, + editorRange: { + startLineNumber: 2, + startColumn: 31, + endLineNumber: 3, + endColumn: 5 + }, + text: "\nand ", + kind: "text" + }, + { + range: { + start: 50, + endExclusive: 63 + }, + editorRange: { + startLineNumber: 3, + startColumn: 5, + endLineNumber: 3, + endColumn: 18 + }, + variableName: "debugConsole", + variableArg: "", + kind: "var" + } + ], + text: "@agent Please \ndo /subCommand with #selection\nand #debugConsole" +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts index 90b31b1ace9..78317a10496 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts @@ -9,7 +9,7 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/uti import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { ChatAgentService, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { ChatAgentService, IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables'; @@ -111,7 +111,7 @@ suite('ChatRequestParser', () => { test('agents', async () => { const agentsService = mockObject()({}); - agentsService.getAgent.returns({ id: 'agent', metadata: { description: '', subCommands: [{ name: 'subCommand' }] } }); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); instantiationService.stub(IChatAgentService, agentsService as any); parser = instantiationService.createInstance(ChatRequestParser); @@ -119,19 +119,29 @@ suite('ChatRequestParser', () => { await assertSnapshot(result); }); - test('agent with question mark', async () => { + test('agents, subCommand', async () => { const agentsService = mockObject()({}); - agentsService.getAgent.returns({ id: 'agent', metadata: { description: '', subCommands: [{ name: 'subCommand' }] } }); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); instantiationService.stub(IChatAgentService, agentsService as any); parser = instantiationService.createInstance(ChatRequestParser); - const result = await parser.parseChatRequest('1', 'Are you there @agent?'); + const result = await parser.parseChatRequest('1', '@agent /subCommand Please do thanks'); + await assertSnapshot(result); + }); + + test('agent with question mark', async () => { + const agentsService = mockObject()({}); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); + instantiationService.stub(IChatAgentService, agentsService as any); + + parser = instantiationService.createInstance(ChatRequestParser); + const result = await parser.parseChatRequest('1', '@agent? Are you there'); await assertSnapshot(result); }); test('agent not first', async () => { const agentsService = mockObject()({}); - agentsService.getAgent.returns({ id: 'agent', metadata: { description: '', subCommands: [{ name: 'subCommand' }] } }); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); instantiationService.stub(IChatAgentService, agentsService as any); parser = instantiationService.createInstance(ChatRequestParser); @@ -141,7 +151,21 @@ suite('ChatRequestParser', () => { test('agents and variables and multiline', async () => { const agentsService = mockObject()({}); - agentsService.getAgent.returns({ id: 'agent', metadata: { description: '', subCommands: [{ name: 'subCommand' }] } }); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); + instantiationService.stub(IChatAgentService, agentsService as any); + + const variablesService = mockObject()({}); + variablesService.hasVariable.returns(true); + instantiationService.stub(IChatVariablesService, variablesService as any); + + parser = instantiationService.createInstance(ChatRequestParser); + const result = await parser.parseChatRequest('1', '@agent /subCommand \nPlease do with #selection\nand #debugConsole'); + await assertSnapshot(result); + }); + + test('agents and variables and multiline, part2', async () => { + const agentsService = mockObject()({}); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); instantiationService.stub(IChatAgentService, agentsService as any); const variablesService = mockObject()({}); @@ -153,4 +177,3 @@ suite('ChatRequestParser', () => { await assertSnapshot(result); }); }); - diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 18a609800a8..ed45aadd56d 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -12,6 +12,7 @@ export const allApiProposals = Object.freeze({ canonicalUriProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.canonicalUriProvider.d.ts', chat: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chat.d.ts', chatAgents: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents.d.ts', + chatAgents2: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents2.d.ts', chatProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatProvider.d.ts', chatRequestAccess: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatRequestAccess.d.ts', chatVariables: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatVariables.d.ts', diff --git a/src/vscode-dts/vscode.proposed.chatAgents2.d.ts b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts new file mode 100644 index 00000000000..830cb37a67c --- /dev/null +++ b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts @@ -0,0 +1,146 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + export interface ChatAgentContext { + /** + * All of the chat messages so far in the current chat session. + */ + history: ChatMessage[]; + } + + export interface ChatAgentErrorDetails { + message: string; + responseIsIncomplete?: boolean; + responseIsFiltered?: boolean; + } + + export interface ChatAgentResult2 { + errorDetails?: ChatAgentErrorDetails; + } + + export interface ChatAgentSlashCommand { + + /** + * A short name by which this command is referred to in the UI, e.g. `fix` or + * `explain` for commands that fix an issue or explain code. + */ + readonly name: string; + + /** + * Human-readable description explaining what this command does. + */ + readonly description: string; + } + + export interface ChatAgentSlashCommandProvider { + + /** + * Returns a list of slash commands that its agent is capable of handling. A slash command + * and be selected by the user and will then be passed to the {@link ChatAgentHandler handler} + * via the {@link ChatAgentRequest.slashCommand slashCommand} property. + * + * + * @param token A cancellation token. + * @returns A list of slash commands. The lack of a result can be signaled by returning `undefined`, `null`, or + * an empty array. + */ + provideSlashCommands(token: CancellationToken): ProviderResult; + } + + export interface ChatAgentCommandFollowup { + commandId: string; + args?: any[]; + title: string; // supports codicon strings + when?: string; + } + + export interface ChatAgentReplyFollowup { + message: string; + tooltip?: string; + title?: string; + } + + export type ChatAgentFollowup = ChatAgentCommandFollowup | ChatAgentReplyFollowup; + + export interface FollowupProvider { + provideFollowups(result: ChatAgentResult2, token: CancellationToken): ProviderResult; + } + + export interface ChatAgent2 { + + /** + * The short name by which this agent is referred to in the UI, e.g `workspace` + */ + readonly name: string; + + /** + * The full name of this agent + */ + fullName: string; + + /** + * A human-readable description explaining what this agent does. + */ + description: string; + + /** + * Icon for the agent shown in UI. + */ + iconPath?: Uri; + + slashCommandProvider?: ChatAgentSlashCommandProvider; + + followupProvider?: FollowupProvider; + + // TODO@API We need this- can't handle telemetry on the vscode side yet + // onDidPerformAction: Event<{ action: InteractiveSessionUserAction }>; + + + // TODO@API Something like prepareSession from the interactive chat provider might be needed.Probably nobody needs it right now. + // prepareSession(); + + /** + * TODO@API explain what happens wrt to history, in-flight requests etc... + * Dispose this agent and free resources + */ + dispose(): void; + } + + export interface ChatAgentRequest { + + /** + * The prompt entered by the user. The {@link ChatAgent2.name name} of the agent or the {@link ChatAgentSlashCommand.name slash command} + * are not part of the prompt. + * + * @see {@link ChatAgentRequest.slashCommand} + */ + prompt: string; + + /** + * The {@link ChatAgentSlashCommand slash command} that was selected for this request. It is guaranteed that the passed slash + * command is an instance that was previously returned from the {@link ChatAgentSlashCommandProvider.provideSlashCommands slash command provider}. + */ + slashCommand?: ChatAgentSlashCommand; + + variables: Record; + } + + // TODO@API InteractiveProgress is a lot to inline... + export type ChatAgentHandler = (request: ChatAgentRequest, context: ChatAgentContext, progress: Progress, token: CancellationToken) => ProviderResult; + + export namespace chat { + + /** + * Create a new {@link ChatAgent2 chat agent} instance. + * + * @param name Short name by which this agent is referred to in the UI + * @param handler The reply-handler of the agent. + * @returns A new chat agent + */ + export function createChatAgent(name: string, handler: ChatAgentHandler): ChatAgent2; + } +} diff --git a/src/vscode-dts/vscode.proposed.interactive.d.ts b/src/vscode-dts/vscode.proposed.interactive.d.ts index a3c2fd927bf..30708bfda72 100644 --- a/src/vscode-dts/vscode.proposed.interactive.d.ts +++ b/src/vscode-dts/vscode.proposed.interactive.d.ts @@ -109,6 +109,8 @@ declare module 'vscode' { export interface InteractiveRequest { session: InteractiveSession; message: string | InteractiveSessionReplyFollowup; + // TODO@API move to agent + // slashCommand?: InteractiveSessionSlashCommand; } export interface InteractiveResponseErrorDetails { diff --git a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts index 2e6bfe31f99..e018235d609 100644 --- a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts +++ b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts @@ -13,6 +13,7 @@ declare module 'vscode' { export interface InteractiveSessionVoteAction { // eslint-disable-next-line local/vscode-dts-string-type-literals kind: 'vote'; + // sessionId: string; responseId: string; direction: InteractiveSessionVoteDirection; } @@ -26,6 +27,7 @@ declare module 'vscode' { export interface InteractiveSessionCopyAction { // eslint-disable-next-line local/vscode-dts-string-type-literals kind: 'copy'; + // sessionId: string; responseId: string; codeBlockIndex: number; copyType: InteractiveSessionCopyKind; @@ -37,6 +39,7 @@ declare module 'vscode' { export interface InteractiveSessionInsertAction { // eslint-disable-next-line local/vscode-dts-string-type-literals kind: 'insert'; + // sessionId: string; responseId: string; codeBlockIndex: number; totalCharacters: number; @@ -46,6 +49,7 @@ declare module 'vscode' { export interface InteractiveSessionTerminalAction { // eslint-disable-next-line local/vscode-dts-string-type-literals kind: 'runInTerminal'; + // sessionId: string; responseId: string; codeBlockIndex: number; languageId?: string; From 0719762057b11690a8d04de3dcfcf50a6d4fbbff Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 11 Oct 2023 23:58:00 -0700 Subject: [PATCH 024/290] allow `Text Editor` to show up in `focusedView` (#195181) --- .../browser/parts/titlebar/windowTitle.ts | 38 ++++++++++++++++++- .../browser/parts/views/viewsService.ts | 7 +++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/titlebar/windowTitle.ts b/src/vs/workbench/browser/parts/titlebar/windowTitle.ts index ee3683fec4c..a723be76707 100644 --- a/src/vs/workbench/browser/parts/titlebar/windowTitle.ts +++ b/src/vs/workbench/browser/parts/titlebar/windowTitle.ts @@ -25,6 +25,7 @@ import { Schemas } from 'vs/base/common/network'; import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtualWorkspace'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { IViewsService } from 'vs/workbench/common/views'; +import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; const enum WindowSettingNames { titleSeparator = 'window.titleSeparator', @@ -45,6 +46,7 @@ export class WindowTitle extends Disposable { readonly onDidChange = this.onDidChangeEmitter.event; private title: string | undefined; + private titleIncludesFocusedView: boolean = false; constructor( @IConfigurationService protected readonly configurationService: IConfigurationService, @@ -58,6 +60,8 @@ export class WindowTitle extends Disposable { @IViewsService private readonly viewsService: IViewsService ) { super(); + + this.updateTitleIncludesFocusedView(); this.registerListeners(); } @@ -77,15 +81,28 @@ export class WindowTitle extends Disposable { this._register(this.contextService.onDidChangeWorkspaceName(() => this.titleUpdater.schedule())); this._register(this.labelService.onDidChangeFormatters(() => this.titleUpdater.schedule())); this._register(this.userDataProfileService.onDidChangeCurrentProfile(() => this.titleUpdater.schedule())); - this._register(this.viewsService.onDidChangeFocusedView(() => this.titleUpdater.schedule())); + this._register(this.viewsService.onDidChangeFocusedView(() => { + if (this.titleIncludesFocusedView) { + this.titleUpdater.schedule(); + } + })); } private onConfigurationChanged(event: IConfigurationChangeEvent): void { + if (event.affectsConfiguration(WindowSettingNames.title)) { + this.updateTitleIncludesFocusedView(); + } + if (event.affectsConfiguration(WindowSettingNames.title) || event.affectsConfiguration(WindowSettingNames.titleSeparator)) { this.titleUpdater.schedule(); } } + private updateTitleIncludesFocusedView(): void { + const titleTemplate = this.configurationService.getValue(WindowSettingNames.title); + this.titleIncludesFocusedView = typeof titleTemplate === 'string' && titleTemplate.includes('${focusedView}'); + } + private onActiveEditorChange(): void { // Dispose old listeners @@ -100,6 +117,22 @@ export class WindowTitle extends Disposable { this.activeEditorListeners.add(activeEditor.onDidChangeDirty(() => this.titleUpdater.schedule())); this.activeEditorListeners.add(activeEditor.onDidChangeLabel(() => this.titleUpdater.schedule())); } + + // Apply listeners for tracking focused code editor + if (this.titleIncludesFocusedView) { + const activeTextEditorControl = this.editorService.activeTextEditorControl; + const textEditorControls: ICodeEditor[] = []; + if (isCodeEditor(activeTextEditorControl)) { + textEditorControls.push(activeTextEditorControl); + } else if (isDiffEditor(activeTextEditorControl)) { + textEditorControls.push(activeTextEditorControl.getOriginalEditor(), activeTextEditorControl.getModifiedEditor()); + } + + for (const textEditorControl of textEditorControls) { + this.activeEditorListeners.add(textEditorControl.onDidBlurEditorText(() => this.titleUpdater.schedule())); + this.activeEditorListeners.add(textEditorControl.onDidFocusEditorText(() => this.titleUpdater.schedule())); + } + } } private doUpdateTitle(): void { @@ -189,7 +222,7 @@ export class WindowTitle extends Disposable { * {appName}: e.g. VS Code * {remoteName}: e.g. SSH * {dirty}: indicator - * {focusedView}L e.g. Terminal + * {focusedView}: e.g. Terminal * {separator}: conditional separator */ getWindowTitle(): string { @@ -277,6 +310,7 @@ export class WindowTitle extends Disposable { isCustomTitleFormat(): boolean { const title = this.configurationService.inspect(WindowSettingNames.title); const titleSeparator = this.configurationService.inspect(WindowSettingNames.titleSeparator); + return title.value !== title.defaultValue || titleSeparator.value !== titleSeparator.defaultValue; } } diff --git a/src/vs/workbench/browser/parts/views/viewsService.ts b/src/vs/workbench/browser/parts/views/viewsService.ts index 22eb80ff787..0907c9e8783 100644 --- a/src/vs/workbench/browser/parts/views/viewsService.ts +++ b/src/vs/workbench/browser/parts/views/viewsService.ts @@ -32,6 +32,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { FilterViewPaneContainer } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { ICommandActionTitle, ILocalizedString } from 'vs/platform/action/common/action'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; export class ViewsService extends Disposable implements IViewsService { @@ -56,7 +57,8 @@ export class ViewsService extends Disposable implements IViewsService { @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService, @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IEditorService private readonly editorService: IEditorService ) { super(); @@ -239,7 +241,8 @@ export class ViewsService extends Disposable implements IViewsService { getFocusedViewName(): string { const viewId: string = this.contextKeyService.getContextKeyValue(FocusedViewContext.key) ?? ''; - return this.viewDescriptorService.getViewDescriptorById(viewId.toString())?.name?.value ?? ''; + const textEditorFocused = this.editorService.activeTextEditorControl?.hasTextFocus() ? localize('editor', "Text Editor") : undefined; + return this.viewDescriptorService.getViewDescriptorById(viewId.toString())?.name?.value ?? textEditorFocused ?? ''; } async openView(id: string, focus?: boolean): Promise { From df8c4d45379b31715b2b84eeb616af0ab7df71c4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Oct 2023 08:59:22 +0200 Subject: [PATCH 025/290] Confirm for protocol links opt-out is not being honored (fix #195373) (#195437) --- src/vs/code/electron-main/app.ts | 8 +++++++- .../platform/windows/electron-main/windowsMainService.ts | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index df8320f3eb0..f687d93c9c0 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -797,7 +797,13 @@ export class CodeApplication extends Disposable { } if (checkboxChecked) { - windowsMainService.sendToOpeningWindow('vscode:disablePromptForProtocolHandling', uri.authority === Schemas.file ? 'local' : 'remote'); + // Due to https://github.com/microsoft/vscode/issues/195436, we can only + // update settings from within a window. But we do not know if a window + // is about to open or can already handle the request, so we have to send + // to any current window and any newly opening window. + const request = { channel: 'vscode:disablePromptForProtocolHandling', args: uri.authority === Schemas.file ? 'local' : 'remote' }; + windowsMainService.sendToFocused(request.channel, request.args); + windowsMainService.sendToOpeningWindow(request.channel, request.args); } return false; // not blocked by user choice diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index 9ebd04ee4b7..aa19814554e 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -1129,7 +1129,13 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic addUNCHostToAllowlist(uri.authority); if (checkboxChecked) { - this.sendToOpeningWindow('vscode:configureAllowedUNCHost', uri.authority); + // Due to https://github.com/microsoft/vscode/issues/195436, we can only + // update settings from within a window. But we do not know if a window + // is about to open or can already handle the request, so we have to send + // to any current window and any newly opening window. + const request = { channel: 'vscode:configureAllowedUNCHost', args: uri.authority }; + this.sendToFocused(request.channel, request.args); + this.sendToOpeningWindow(request.channel, request.args); } return this.doResolveFilePath(path, options, true /* do not handle UNC error again */); From 4dce9d5ad442f96e805a8e1542cc8bd54998417f Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 12 Oct 2023 00:00:51 -0700 Subject: [PATCH 026/290] Fix current query showing up in the history (#195432) --- src/vs/workbench/contrib/chat/common/chatServiceImpl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 9586faeb1c3..947e471dc3d 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -504,7 +504,6 @@ export class ChatService extends Disposable implements IChatService { let slashCommandFollowups: IChatFollowup[] | void = []; if (typeof message === 'string' && agentPart) { - request = model.addRequest(parsedRequest, agentPart.agent); const history: IChatMessage[] = []; for (const request of model.getRequests()) { if (!request.response) { @@ -515,6 +514,7 @@ export class ChatService extends Disposable implements IChatService { history.push({ role: ChatMessageRole.Assistant, content: request.response.response.asString() }); } + request = model.addRequest(parsedRequest, agentPart.agent); const requestProps: IChatAgentRequest = { requestId: generateUuid(), message: message, From 7a03774b964426b3286d7cb83b40ade2a839f3c8 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 12 Oct 2023 14:53:01 +0200 Subject: [PATCH 027/290] speech - core service and extension API (#195365) * speech - scaffold a basic core service for registration * speech - scaffold a basic extension API for speech providers * cleanup * speech - improve API to work with events * simplify * better api * cleanup --- build/lib/i18n.resources.json | 4 + .../api/browser/extensionHost.contribution.ts | 1 + .../workbench/api/browser/mainThreadSpeech.ts | 81 +++++++++++++++++++ .../workbench/api/common/extHost.api.impl.ts | 14 +++- .../workbench/api/common/extHost.protocol.ts | 14 ++++ src/vs/workbench/api/common/extHostSpeech.ts | 61 ++++++++++++++ src/vs/workbench/api/common/extHostTypes.ts | 11 +++ .../speech/common/speech.contribution.ts | 9 +++ .../contrib/speech/common/speechService.ts | 74 +++++++++++++++++ .../common/extensionsApiProposals.ts | 1 + src/vs/workbench/workbench.common.main.ts | 4 + src/vscode-dts/vscode.proposed.speech.d.ts | 35 ++++++++ 12 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 src/vs/workbench/api/browser/mainThreadSpeech.ts create mode 100644 src/vs/workbench/api/common/extHostSpeech.ts create mode 100644 src/vs/workbench/contrib/speech/common/speech.contribution.ts create mode 100644 src/vs/workbench/contrib/speech/common/speechService.ts create mode 100644 src/vscode-dts/vscode.proposed.speech.d.ts diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 303ac03be1e..2d03fbd5712 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -214,6 +214,10 @@ "name": "vs/workbench/contrib/tags", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/speech", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/surveys", "project": "vscode-workbench" diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index 85063e0987a..b34ef1570cc 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -54,6 +54,7 @@ import './mainThreadQuickDiff'; import './mainThreadQuickOpen'; import './mainThreadRemoteConnectionData'; import './mainThreadSaveParticipant'; +import './mainThreadSpeech'; import './mainThreadEditSessionIdentityParticipant'; import './mainThreadSCM'; import './mainThreadSearch'; diff --git a/src/vs/workbench/api/browser/mainThreadSpeech.ts b/src/vs/workbench/api/browser/mainThreadSpeech.ts new file mode 100644 index 00000000000..c3efdd37cd2 --- /dev/null +++ b/src/vs/workbench/api/browser/mainThreadSpeech.ts @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { ILogService } from 'vs/platform/log/common/log'; +import { ExtHostContext, ExtHostSpeechShape, MainContext, MainThreadSpeechShape } from 'vs/workbench/api/common/extHost.protocol'; +import { ISpeechProviderMetadata, ISpeechService, ISpeechToTextEvent } from 'vs/workbench/contrib/speech/common/speechService'; +import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; + +type SpeechToTextSession = { + readonly onDidChange: Emitter; +}; + +@extHostNamedCustomer(MainContext.MainThreadSpeech) +export class MainThreadSpeech extends Disposable implements MainThreadSpeechShape { + + private readonly proxy: ExtHostSpeechShape; + + private readonly providerRegistrations = new Map(); + private readonly providerSessions = new Map(); + + constructor( + extHostContext: IExtHostContext, + @ISpeechService private readonly speechService: ISpeechService, + @ILogService private readonly logService: ILogService + ) { + super(); + + this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostSpeech); + } + + $registerProvider(handle: number, identifier: string, metadata: ISpeechProviderMetadata): void { + this.logService.trace('[Speech] extension registered provider', metadata.extension.value); + + const registration = this.speechService.registerSpeechProvider(identifier, { + metadata, + createSpeechToTextSession: token => { + const cts = new CancellationTokenSource(token); + const session = Math.random(); + + this.proxy.$createSpeechToTextSession(handle, session, cts.token); + + const onDidChange = new Emitter(); + this.providerSessions.set(session, { onDidChange }); + + return { + onDidChange: onDidChange.event, + dispose: () => { + cts.dispose(true); + onDidChange.dispose(); + this.providerSessions.delete(session); + } + }; + } + }); + this.providerRegistrations.set(handle, { + dispose: () => { + registration.dispose(); + } + }); + } + + $unregisterProvider(handle: number): void { + const registration = this.providerRegistrations.get(handle); + if (registration) { + registration.dispose(); + this.providerRegistrations.delete(handle); + } + } + + $emitSpeechToTextEvent(session: number, event: ISpeechToTextEvent): void { + const providerSession = this.providerSessions.get(session); + if (providerSession) { + providerSession.onDidChange.fire(event); + } + } +} diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index a894d5c01ce..1fe5ef33fa6 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -104,6 +104,7 @@ import { ExtHostIssueReporter } from 'vs/workbench/api/common/extHostIssueReport import { IExtHostManagedSockets } from 'vs/workbench/api/common/extHostManagedSockets'; import { ExtHostShare } from 'vs/workbench/api/common/extHostShare'; import { ExtHostChatProvider } from 'vs/workbench/api/common/extHostChatProvider'; +import { ExtHostSpeech } from 'vs/workbench/api/common/extHostSpeech'; import { ExtHostChatVariables } from 'vs/workbench/api/common/extHostChatVariables'; import { ExtHostRelatedInformation } from 'vs/workbench/api/common/extHostAiRelatedInformation'; import { ExtHostAiEmbeddingVector } from 'vs/workbench/api/common/extHostEmbeddingVector'; @@ -217,6 +218,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostAiEmbeddingVector = rpcProtocol.set(ExtHostContext.ExtHostAiEmbeddingVector, new ExtHostAiEmbeddingVector(rpcProtocol)); const extHostIssueReporter = rpcProtocol.set(ExtHostContext.ExtHostIssueReporter, new ExtHostIssueReporter(rpcProtocol)); const extHostStatusBar = rpcProtocol.set(ExtHostContext.ExtHostStatusBar, new ExtHostStatusBar(rpcProtocol, extHostCommands.converter)); + const extHostSpeech = rpcProtocol.set(ExtHostContext.ExtHostSpeech, new ExtHostSpeech(rpcProtocol)); // Check that no named customers are missing const expected = Object.values>(ExtHostContext); @@ -1378,6 +1380,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I } }; + // namespace: speech + const speech: typeof vscode.speech = { + registerSpeechProvider(id: string, provider: vscode.SpeechProvider) { + checkProposedApiEnabled(extension, 'speech'); + return extHostSpeech.registerProvider(extension.identifier, id, provider); + } + }; + return { version: initData.version, // namespaces @@ -1394,6 +1404,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I languages, notebooks, scm, + speech, tasks, tests, window, @@ -1593,7 +1604,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I InteractiveEditorResponseFeedbackKind: extHostTypes.InteractiveEditorResponseFeedbackKind, StackFrameFocus: extHostTypes.StackFrameFocus, ThreadFocus: extHostTypes.ThreadFocus, - RelatedInformationType: extHostTypes.RelatedInformationType + RelatedInformationType: extHostTypes.RelatedInformationType, + SpeechToTextStatus: extHostTypes.SpeechToTextStatus }; }; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 48d318c3795..0e5ef464728 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -63,6 +63,7 @@ import { ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/ import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm'; import { IWorkspaceSymbol } from 'vs/workbench/contrib/search/common/search'; +import { ISpeechProviderMetadata, ISpeechToTextEvent } from 'vs/workbench/contrib/speech/common/speechService'; import { CoverageDetails, ExtensionRunTestsRequest, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, TestResultState, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes'; import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline'; import { TypeHierarchyItem } from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy'; @@ -1133,6 +1134,17 @@ export interface MainThreadNotebookRenderersShape extends IDisposable { export interface MainThreadInteractiveShape extends IDisposable { } +export interface MainThreadSpeechShape extends IDisposable { + $registerProvider(handle: number, identifier: string, metadata: ISpeechProviderMetadata): void; + $unregisterProvider(handle: number): void; + + $emitSpeechToTextEvent(session: number, event: ISpeechToTextEvent): void; +} + +export interface ExtHostSpeechShape { + $createSpeechToTextSession(handle: number, session: number, token: CancellationToken): Promise; +} + export interface MainThreadChatProviderShape extends IDisposable { $registerProvider(handle: number, identifier: string, metadata: IChatResponseProviderMetadata): void; $unregisterProvider(handle: number): void; @@ -2713,6 +2725,7 @@ export const MainContext = { MainThreadStatusBar: createProxyIdentifier('MainThreadStatusBar'), MainThreadSecretState: createProxyIdentifier('MainThreadSecretState'), MainThreadStorage: createProxyIdentifier('MainThreadStorage'), + MainThreadSpeech: createProxyIdentifier('MainThreadSpeechProvider'), MainThreadTelemetry: createProxyIdentifier('MainThreadTelemetry'), MainThreadTerminalService: createProxyIdentifier('MainThreadTerminalService'), MainThreadWebviews: createProxyIdentifier('MainThreadWebviews'), @@ -2808,6 +2821,7 @@ export const ExtHostContext = { ExtHostChatAgents2: createProxyIdentifier('ExtHostChatAgents'), ExtHostChatVariables: createProxyIdentifier('ExtHostChatVariables'), ExtHostChatProvider: createProxyIdentifier('ExtHostChatProvider'), + ExtHostSpeech: createProxyIdentifier('ExtHostSpeech'), ExtHostAiRelatedInformation: createProxyIdentifier('ExtHostAiRelatedInformation'), ExtHostAiEmbeddingVector: createProxyIdentifier('ExtHostAiEmbeddingVector'), ExtHostTheming: createProxyIdentifier('ExtHostTheming'), diff --git a/src/vs/workbench/api/common/extHostSpeech.ts b/src/vs/workbench/api/common/extHostSpeech.ts new file mode 100644 index 00000000000..aa937496aa3 --- /dev/null +++ b/src/vs/workbench/api/common/extHostSpeech.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { ExtHostSpeechShape, IMainContext, MainContext, MainThreadSpeechShape } from 'vs/workbench/api/common/extHost.protocol'; +import type * as vscode from 'vscode'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; + +export class ExtHostSpeech implements ExtHostSpeechShape { + + private static ID_POOL = 1; + + private readonly proxy: MainThreadSpeechShape; + private readonly providers = new Map(); + + constructor( + mainContext: IMainContext + ) { + this.proxy = mainContext.getProxy(MainContext.MainThreadSpeech); + } + + async $createSpeechToTextSession(handle: number, session: number, token: CancellationToken): Promise { + const provider = this.providers.get(handle); + if (!provider) { + return; + } + + const speechToTextSession = provider.provideSpeechToTextSession(token); + if (token.isCancellationRequested) { + return; + } + + const listener = speechToTextSession.onDidChange(e => { + if (token.isCancellationRequested) { + return; + } + + this.proxy.$emitSpeechToTextEvent(session, e); + }); + + token.onCancellationRequested(() => { + listener.dispose(); + speechToTextSession.dispose(); + }); + } + + registerProvider(extension: ExtensionIdentifier, identifier: string, provider: vscode.SpeechProvider): IDisposable { + const handle = ExtHostSpeech.ID_POOL++; + + this.providers.set(handle, provider); + this.proxy.$registerProvider(handle, identifier, { extension, displayName: extension.value }); + + return toDisposable(() => { + this.proxy.$unregisterProvider(handle); + this.providers.delete(handle); + }); + } +} diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 670dffdcbb4..55cde471a70 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4140,3 +4140,14 @@ export enum RelatedInformationType { } //#endregion + +//#region Speech + +export enum SpeechToTextStatus { + Started = 1, + Recognizing = 2, + Recognized = 3, + Stopped = 4 +} + +//#endregion diff --git a/src/vs/workbench/contrib/speech/common/speech.contribution.ts b/src/vs/workbench/contrib/speech/common/speech.contribution.ts new file mode 100644 index 00000000000..6a093cd32e7 --- /dev/null +++ b/src/vs/workbench/contrib/speech/common/speech.contribution.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ISpeechService, SpeechService } from 'vs/workbench/contrib/speech/common/speechService'; + +registerSingleton(ISpeechService, SpeechService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/speech/common/speechService.ts b/src/vs/workbench/contrib/speech/common/speechService.ts new file mode 100644 index 00000000000..4e54851f69a --- /dev/null +++ b/src/vs/workbench/contrib/speech/common/speechService.ts @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancellationToken } from 'vs/base/common/cancellation'; +import { Event } from 'vs/base/common/event'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const ISpeechService = createDecorator('speechService'); + +export interface ISpeechProviderMetadata { + readonly extension: ExtensionIdentifier; + readonly displayName: string; +} + +export enum SpeechToTextStatus { + Started = 1, + Recognizing = 2, + Recognized = 3, + Stopped = 4 +} + +export interface ISpeechToTextEvent { + readonly status: SpeechToTextStatus; + readonly text?: string; +} + +export interface ISpeechProvider { + readonly metadata: ISpeechProviderMetadata; + + createSpeechToTextSession(token: CancellationToken): ISpeechToTextSession; +} + +export interface ISpeechToTextSession extends IDisposable { + readonly onDidChange: Event; +} + +export interface ISpeechService { + + readonly _serviceBrand: undefined; + + registerSpeechProvider(identifier: string, provider: ISpeechProvider): IDisposable; + + createSpeechToTextSession(identifier: string, token: CancellationToken): ISpeechToTextSession; +} + +export class SpeechService implements ISpeechService { + + readonly _serviceBrand: undefined; + + private readonly providers = new Map(); + + registerSpeechProvider(identifier: string, provider: ISpeechProvider): IDisposable { + if (this.providers.has(identifier)) { + throw new Error(`Speech provider with identifier ${identifier} is already registered.`); + } + + this.providers.set(identifier, provider); + + return toDisposable(() => this.providers.delete(identifier)); + } + + createSpeechToTextSession(identifier: string, token: CancellationToken): ISpeechToTextSession { + const provider = this.providers.get(identifier); + if (!provider) { + throw new Error(`Speech provider with identifier ${identifier} is not registered.`); + } + + return provider.createSpeechToTextSession(token); + } +} diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index ed45aadd56d..4eba13aa59c 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -82,6 +82,7 @@ export const allApiProposals = Object.freeze({ scmValidation: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmValidation.d.ts', shareProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.shareProvider.d.ts', showLocal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.showLocal.d.ts', + speech: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.speech.d.ts', tabInputTextMerge: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tabInputTextMerge.d.ts', taskPresentationGroup: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskPresentationGroup.d.ts', telemetry: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetry.d.ts', diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 81e55f19de6..9f5014b86a3 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -178,6 +178,10 @@ import 'vs/workbench/contrib/contextmenu/browser/contextmenu.contribution'; // Notebook import 'vs/workbench/contrib/notebook/browser/notebook.contribution'; +// Speech +import 'vs/workbench/contrib/speech/common/speech.contribution'; + +// Chat import 'vs/workbench/contrib/chat/browser/chat.contribution'; import 'vs/workbench/contrib/inlineChat/browser/inlineChat.contribution'; diff --git a/src/vscode-dts/vscode.proposed.speech.d.ts b/src/vscode-dts/vscode.proposed.speech.d.ts new file mode 100644 index 00000000000..81c90e39bac --- /dev/null +++ b/src/vscode-dts/vscode.proposed.speech.d.ts @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + export enum SpeechToTextStatus { + Started = 1, + Recognizing = 2, + Recognized = 3, + Stopped = 4 + } + + export interface SpeechToTextEvent { + readonly status: SpeechToTextStatus; + readonly text?: string; + } + + export interface SpeechToTextSession extends Disposable { + readonly onDidChange: Event; + } + + export interface SpeechProvider { + provideSpeechToTextSession(token: CancellationToken): SpeechToTextSession; + } + + export namespace speech { + + /** + * TODO@bpasero work in progress speech provider API + */ + export function registerSpeechProvider(id: string, provider: SpeechProvider): Disposable; + } +} From 2b9791e491a7dafbce8034fca382e80a21a4786f Mon Sep 17 00:00:00 2001 From: "ermin.zem" Date: Thu, 12 Oct 2023 21:23:34 +0800 Subject: [PATCH 028/290] feat: support iconThemes definitions for root folders (#195319) Co-authored-by: ermin.zem --- src/vs/editor/common/services/getIconClasses.ts | 7 ++++++- .../themes/browser/fileIconThemeData.ts | 17 +++++++++++++++++ .../themes/common/fileIconThemeSchema.ts | 16 ++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/common/services/getIconClasses.ts b/src/vs/editor/common/services/getIconClasses.ts index 464555c63fb..bc3da1e5e6c 100644 --- a/src/vs/editor/common/services/getIconClasses.ts +++ b/src/vs/editor/common/services/getIconClasses.ts @@ -37,8 +37,13 @@ export function getIconClasses(modelService: IModelService, languageService: ILa } } + // Root Folders + if (fileKind === FileKind.ROOT_FOLDER) { + classes.push(`${name}-root-name-folder-icon`); + } + // Folders - if (fileKind === FileKind.FOLDER) { + else if (fileKind === FileKind.FOLDER) { classes.push(`${name}-name-folder-icon`); } diff --git a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts index b65836c2377..aaf4f1735bb 100644 --- a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts @@ -172,6 +172,8 @@ interface IconsAssociation { folderExpanded?: string; rootFolder?: string; rootFolderExpanded?: string; + rootFolderNames?: { [folderName: string]: string }; + rootFolderNamesExpanded?: { [folderName: string]: string }; folderNames?: { [folderName: string]: string }; folderNamesExpanded?: { [folderName: string]: string }; fileExtensions?: { [extension: string]: string }; @@ -309,6 +311,21 @@ export class FileIconThemeLoader { } } + const rootFolderNames = associations.rootFolderNames; + if (rootFolderNames) { + for (const key in rootFolderNames) { + addSelector(`${qualifier} .${escapeCSS(key)}-root-name-folder-icon.rootfolder-icon::before`, rootFolderNames[key]); + result.hasFolderIcons = true; + } + } + const rootFolderNamesExpanded = associations.rootFolderNamesExpanded; + if (rootFolderNamesExpanded) { + for (const key in rootFolderNamesExpanded) { + addSelector(`${qualifier} ${expanded} .${escapeCSS(key)}-root-name-folder-icon.rootfolder-icon::before`, rootFolderNamesExpanded[key]); + result.hasFolderIcons = true; + } + } + const languageIds = associations.languageIds; if (languageIds) { if (!languageIds.jsonc && languageIds.json) { diff --git a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts index 1e4182151aa..e4c1b2b3c3c 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts @@ -29,6 +29,22 @@ const schema: IJSONSchema = { description: nls.localize('schema.file', 'The default file icon, shown for all files that don\'t match any extension, filename or language id.') }, + rootFolderNames: { + type: 'object', + description: nls.localize('schema.rootFolderNames', 'Associates root folder names to icons. The object key is the folder name, not including any path segments. No patterns or wildcards are allowed. Folder name matching is case insensitive.'), + additionalProperties: { + type: 'string', + description: nls.localize('schema.folderName', 'The ID of the icon definition for the association.') + } + }, + rootFolderNamesExpanded: { + type: 'object', + description: nls.localize('schema.rootFolderNamesExpanded', 'Associates root folder names to icons for expanded folders. The object key is the folder name, not including any path segments. No patterns or wildcards are allowed. Folder name matching is case insensitive.'), + additionalProperties: { + type: 'string', + description: nls.localize('schema.folderNameExpanded', 'The ID of the icon definition for the association.') + } + }, folderNames: { type: 'object', description: nls.localize('schema.folderNames', 'Associates folder names to icons. The object key is the folder name, not including any path segments. No patterns or wildcards are allowed. Folder name matching is case insensitive.'), From 4afb8f7f2bac5cdc9bf67707ded743eeef7fb02f Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:09:06 +0200 Subject: [PATCH 029/290] SourceControl - `scm/inputBox` menu proposal (#195475) Initial implementation --- src/vs/platform/actions/common/actions.ts | 1 + .../workbench/contrib/scm/browser/media/scm.css | 8 ++++++++ src/vs/workbench/contrib/scm/browser/menus.ts | 10 ++++++++++ .../contrib/scm/browser/scmViewPane.ts | 17 +++++++++++++++-- src/vs/workbench/contrib/scm/common/scm.ts | 1 + .../actions/common/menusExtensionPoint.ts | 6 ++++++ .../extensions/common/extensionsApiProposals.ts | 1 + ...oposed.contribSourceControlInputBoxMenu.d.ts | 7 +++++++ 8 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.contribSourceControlInputBoxMenu.d.ts diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 10a31c98531..165a2ed3636 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -109,6 +109,7 @@ export class MenuId { static readonly SCMResourceFolderContext = new MenuId('SCMResourceFolderContext'); static readonly SCMResourceGroupContext = new MenuId('SCMResourceGroupContext'); static readonly SCMSourceControl = new MenuId('SCMSourceControl'); + static readonly SCMInputBox = new MenuId('SCMInputBox'); static readonly SCMTitle = new MenuId('SCMTitle'); static readonly SearchContext = new MenuId('SearchContext'); static readonly SearchActionMenu = new MenuId('SearchActionContext'); diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css index f92c54db113..efd1ace9387 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css @@ -242,6 +242,14 @@ border-radius: 2px; } +.scm-view .scm-input .actions { + position: absolute; + top: 6px; + right: 20px; + border: 1px solid var(--vscode-toolbar-hoverBackground); + border-radius: 5px; +} + .scm-view .scm-editor-container .monaco-editor { border-radius: 2px; } diff --git a/src/vs/workbench/contrib/scm/browser/menus.ts b/src/vs/workbench/contrib/scm/browser/menus.ts index 9918414d4c0..d1bde83d780 100644 --- a/src/vs/workbench/contrib/scm/browser/menus.ts +++ b/src/vs/workbench/contrib/scm/browser/menus.ts @@ -161,6 +161,16 @@ export class SCMRepositoryMenus implements ISCMRepositoryMenus, IDisposable { return this._repositoryMenu; } + private _inputBoxMenu: IMenu | undefined; + get inputBoxMenu(): IMenu { + if (!this._inputBoxMenu) { + this._inputBoxMenu = this.menuService.createMenu(MenuId.SCMInputBox, this.contextKeyService); + this.disposables.add(this._inputBoxMenu); + } + + return this._inputBoxMenu; + } + private readonly disposables = new DisposableStore(); constructor( diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index 9e3fbce5719..46151c7881d 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -227,6 +227,7 @@ class SCMTreeDragAndDrop implements ITreeDragAndDrop { interface InputTemplate { readonly inputWidget: SCMInputWidget; inputWidgetHeight: number; + actionBar: ActionBar; readonly elementDisposables: DisposableStore; readonly templateDisposable: IDisposable; } @@ -246,7 +247,9 @@ class InputRenderer implements ICompressibleTreeRenderer void, + private actionViewItemProvider: IActionViewItemProvider, @IInstantiationService private instantiationService: IInstantiationService, + @ISCMViewService private scmViewService: ISCMViewService ) { } renderTemplate(container: HTMLElement): InputTemplate { @@ -261,7 +264,10 @@ class InputRenderer implements ICompressibleTreeRenderer, index: number, templateData: InputTemplate): void { @@ -314,6 +320,13 @@ class InputRenderer implements ICompressibleTreeRenderer templateData.inputWidget.layout(); templateData.elementDisposables.add(this.outerLayout.onDidChange(layoutEditor)); layoutEditor(); + + // Action bar + templateData.actionBar.clear(); + templateData.actionBar.context = input.repository.provider; + + const menus = this.scmViewService.menus.getRepositoryMenus(input.repository.provider); + templateData.elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.inputBoxMenu, templateData.actionBar)); } renderCompressedElements(): void { @@ -2348,7 +2361,7 @@ export class SCMViewPane extends ViewPane { this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.providerCountBadge'), this.disposables)(updateProviderCountVisibility)); updateProviderCountVisibility(); - this.inputRenderer = this.instantiationService.createInstance(InputRenderer, this.layoutCache, overflowWidgetsDomNode, (input, height) => this.tree.updateElementHeight(input, height)); + this.inputRenderer = this.instantiationService.createInstance(InputRenderer, this.layoutCache, overflowWidgetsDomNode, (input, height) => this.tree.updateElementHeight(input, height), getActionViewItemProvider(this.instantiationService)); const delegate = new ListDelegate(this.inputRenderer); this.actionButtonRenderer = this.instantiationService.createInstance(ActionButtonRenderer); diff --git a/src/vs/workbench/contrib/scm/common/scm.ts b/src/vs/workbench/contrib/scm/common/scm.ts index e7d39bfecbb..af7852084c7 100644 --- a/src/vs/workbench/contrib/scm/common/scm.ts +++ b/src/vs/workbench/contrib/scm/common/scm.ts @@ -172,6 +172,7 @@ export interface ISCMTitleMenu { export interface ISCMRepositoryMenus { readonly titleMenu: ISCMTitleMenu; readonly repositoryMenu: IMenu; + readonly inputBoxMenu: IMenu; getResourceGroupMenu(group: ISCMResourceGroup): IMenu; getResourceMenu(resource: ISCMResource): IMenu; getResourceFolderMenu(group: ISCMResourceGroup): IMenu; diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index bb1993e9d95..56609d8331f 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -124,6 +124,12 @@ const apiMenus: IAPIMenu[] = [ id: MenuId.SCMSourceControl, description: localize('menus.scmSourceControl', "The Source Control menu") }, + { + key: 'scm/inputBox', + id: MenuId.SCMInputBox, + description: localize('menus.scmInputBox', "The Source Control input box menu"), + proposed: 'contribSourceControlInputBoxMenu' + }, { key: 'scm/resourceState/context', id: MenuId.SCMResourceContext, diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 4eba13aa59c..3724be62923 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -30,6 +30,7 @@ export const allApiProposals = Object.freeze({ contribNotebookStaticPreloads: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts', contribRemoteHelp: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribRemoteHelp.d.ts', contribShareMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts', + contribSourceControlInputBoxMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlInputBoxMenu.d.ts', contribStatusBarItems: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribStatusBarItems.d.ts', contribViewsRemote: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsRemote.d.ts', contribViewsWelcome: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsWelcome.d.ts', diff --git a/src/vscode-dts/vscode.proposed.contribSourceControlInputBoxMenu.d.ts b/src/vscode-dts/vscode.proposed.contribSourceControlInputBoxMenu.d.ts new file mode 100644 index 00000000000..4774bf46fef --- /dev/null +++ b/src/vscode-dts/vscode.proposed.contribSourceControlInputBoxMenu.d.ts @@ -0,0 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// empty placeholder declaration for the `scm/inputBox` menu contribution point +// https://github.com/microsoft/vscode/issues/195474 From 365c6f225c5fd168b12b65eace0207e6c2c29804 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 12 Oct 2023 08:34:11 -0700 Subject: [PATCH 030/290] fix #195374 --- .../common/capabilities/commandDetectionCapability.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 39169a64fbc..40f6d319e81 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -390,6 +390,8 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._windowsPromptPollingInProcess = false; if (i === 20) { this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); + } else { + this._currentCommand.commandStartX = this._terminal.buffer.active.cursorX; } } else { // HACK: Fire command started on the following frame on Windows to allow the cursor @@ -413,6 +415,8 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe const line = this._terminal.buffer.active.getLine(this._currentCommand.commandStartMarker.line); if (line) { this._currentCommand.commandStartLineContent = line.translateToString(true); + this._logService.debug('command start line content', this._currentCommand.commandStartLineContent); + this._logService.debug('command start x', this._currentCommand.commandStartX); } } this._onCommandStarted.fire({ marker: this._currentCommand.commandStartMarker } as ITerminalCommand); From d863bb8900a0e3319a069df2f425738a85d89ab8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 12 Oct 2023 08:36:02 -0700 Subject: [PATCH 031/290] Fix tests --- src/vs/platform/quickinput/test/browser/quickinput.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/quickinput/test/browser/quickinput.test.ts b/src/vs/platform/quickinput/test/browser/quickinput.test.ts index dd3ef20eafd..8d54f3cd5af 100644 --- a/src/vs/platform/quickinput/test/browser/quickinput.test.ts +++ b/src/vs/platform/quickinput/test/browser/quickinput.test.ts @@ -85,7 +85,7 @@ suite('QuickInput', () => { // https://github.com/microsoft/vscode/issues/147543 } }, new TestThemeService(), - { activeContainer: { ownerDocument: null } } as any)); + { activeContainer: fixture } as any)); // initial layout controller.layout({ height: 20, width: 40 }, 0); From 4d9ba224d3d82b801b54984401bf1ab54973694e Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 12 Oct 2023 08:36:05 -0700 Subject: [PATCH 032/290] Update src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts --- .../terminal/common/capabilities/commandDetectionCapability.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 40f6d319e81..e9535db6def 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -415,8 +415,6 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe const line = this._terminal.buffer.active.getLine(this._currentCommand.commandStartMarker.line); if (line) { this._currentCommand.commandStartLineContent = line.translateToString(true); - this._logService.debug('command start line content', this._currentCommand.commandStartLineContent); - this._logService.debug('command start x', this._currentCommand.commandStartX); } } this._onCommandStarted.fire({ marker: this._currentCommand.commandStartMarker } as ITerminalCommand); From 8e90fd310b53cb540d02ae7620caadd527b42fe8 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 12 Oct 2023 09:02:42 -0700 Subject: [PATCH 033/290] use regex for prompt position --- .../capabilities/commandDetectionCapability.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index e9535db6def..17ea2e74c5c 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -373,6 +373,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe // On Windows track all cursor movements after the command start sequence this._commandMarkers.length = 0; + let promptMatch: RegExpMatchArray | undefined; // Conpty could have the wrong cursor position at this point. if (!this._cursorOnNextLine() || !this._cursorLineLooksLikeWindowsPrompt()) { this._windowsPromptPollingInProcess = true; @@ -380,7 +381,8 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe let i = 0; for (; i < 20; i++) { await timeout(10); - if (!this._windowsPromptPollingInProcess || this._cursorOnNextLine() && this._cursorLineLooksLikeWindowsPrompt()) { + promptMatch = this._cursorLineLooksLikeWindowsPrompt(); + if (!this._windowsPromptPollingInProcess || this._cursorOnNextLine() && promptMatch) { if (!this._windowsPromptPollingInProcess) { this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling cancelled'); } @@ -390,8 +392,9 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._windowsPromptPollingInProcess = false; if (i === 20) { this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); - } else { - this._currentCommand.commandStartX = this._terminal.buffer.active.cursorX; + } else if (promptMatch) { + // use the regex to set the position as it's possible input has occurred + this._currentCommand.commandStartX = promptMatch[0].length; } } else { // HACK: Fire command started on the following frame on Windows to allow the cursor @@ -434,13 +437,13 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe return cursorYAbsolute > lastCommandYAbsolute; } - private _cursorLineLooksLikeWindowsPrompt(): boolean { + private _cursorLineLooksLikeWindowsPrompt(): RegExpMatchArray | undefined { const line = this._terminal.buffer.active.getLine(this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY); if (!line) { - return false; + return; } // TODO: fine tune prompt regex to accomodate for unique configurtions. - return line.translateToString(true)?.match(/^(PS.+>)|([A-Z]:\\.*>)/) !== null; + return line.translateToString(true)?.match(/^(PS.+>)|([A-Z]:\\.*>)/) ?? undefined; } handleGenericCommand(options?: IHandleCommandOptions): void { From a71cd073451797dcbd20e28408f204e094fe3811 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 12 Oct 2023 09:08:25 -0700 Subject: [PATCH 034/290] length + 1 --- .../terminal/common/capabilities/commandDetectionCapability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 17ea2e74c5c..90ff205798a 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -394,7 +394,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); } else if (promptMatch) { // use the regex to set the position as it's possible input has occurred - this._currentCommand.commandStartX = promptMatch[0].length; + this._currentCommand.commandStartX = promptMatch[0].length + 1; } } else { // HACK: Fire command started on the following frame on Windows to allow the cursor From 9bb94efbe279580856897b63cc9417a3e875e405 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 12 Oct 2023 09:16:55 -0700 Subject: [PATCH 035/290] Fix missing slash command in prompt (#195484) --- src/vs/workbench/contrib/chat/common/chatParserTypes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts index 0dea56c5e22..5c9e368d58e 100644 --- a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts @@ -101,7 +101,7 @@ export class ChatRequestSlashCommandPart implements IParsedChatRequestPart { } get promptText(): string { - return ''; + return `/${this.slashCommand.command}`; } } From a72df4109d765ca81dcafb0da1ef4512f4fef495 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:25:19 -0700 Subject: [PATCH 036/290] Make explain only quick fix color brighter --- .../quickFix/browser/media/terminalQuickFix.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/media/terminalQuickFix.css b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/media/terminalQuickFix.css index 11a54028fe5..c907928d5fb 100644 --- a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/media/terminalQuickFix.css +++ b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/media/terminalQuickFix.css @@ -13,7 +13,5 @@ } .monaco-workbench .terminal .terminal-command-decoration.quick-fix.explainOnly { - /* Use success background to blend in with the terminal better as it's lower priority. We will - * probably want to add an explicit color for this eventually. */ - color: var(--vscode-terminalCommandDecoration-successBackground) !important; + color: var(--vscode-editorLightBulbAutoFix-foreground) !important; } From 443f8cc0861e6a4eadd04a65d722af2c45ac3eca Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:36:00 -0700 Subject: [PATCH 037/290] Wait for next command prompt before creating decoration marker Fixes #195496 --- .../terminalContrib/quickFix/browser/quickFixAddon.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts index 697f6db5009..d86a971c1ee 100644 --- a/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts @@ -186,6 +186,15 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, if (command.command !== '' && this._lastQuickFixId) { this._disposeQuickFix(this._lastQuickFixId, false); } + + + // Wait for the next command to start to ensure the quick fix marker is created on the next + // prompt line + const commandDetection = this._capabilities.get(TerminalCapability.CommandDetection); + if (commandDetection) { + await Event.toPromise(commandDetection.onCommandStarted); + } + const resolver = async (selector: ITerminalQuickFixOptions, lines?: string[]) => { if (lines === undefined) { return undefined; From 88fc434af43ddabbeaea93d531e707df2037ee85 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Thu, 12 Oct 2023 11:03:27 -0700 Subject: [PATCH 038/290] Mitigate smoke test failure #195491 (#195493) --- test/smoke/src/areas/preferences/preferences.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/smoke/src/areas/preferences/preferences.test.ts b/test/smoke/src/areas/preferences/preferences.test.ts index 13418dde91b..ed5726c3f20 100644 --- a/test/smoke/src/areas/preferences/preferences.test.ts +++ b/test/smoke/src/areas/preferences/preferences.test.ts @@ -64,7 +64,8 @@ export function setup(logger: Logger) { await app.code.waitForElements('.line-numbers', false, elements => !elements || elements.length === 0); }); - it('hides the toc when searching depending on the search behavior', async function () { + // Skipping test due to it being flaky. + it.skip('hides the toc when searching depending on the search behavior', async function () { const app = this.app as Application; // Hide ToC when searching From 0db5e97f1841fd7527ddcc3295ce1be181d85d6a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 12 Oct 2023 20:19:05 +0200 Subject: [PATCH 039/290] fix #195130 (#195492) --- .../parts/auxiliarybar/auxiliaryBarPart.ts | 11 ++-- .../workbench/browser/parts/compositeBar.ts | 3 +- .../browser/parts/compositeBarActions.ts | 31 +++++++---- .../browser/parts/globalCompositeBar.ts | 53 +++++++++++-------- .../browser/parts/media/paneCompositePart.css | 17 +++--- .../browser/parts/paneCompositeBar.ts | 2 + .../parts/sidebar/media/sidebarpart.css | 16 ------ .../browser/parts/sidebar/sidebarPart.ts | 3 +- .../parts/titlebar/media/titlebarpart.css | 7 ++- .../extensions/browser/extensionsViewlet.ts | 2 +- .../files/common/dirtyFilesIndicator.ts | 1 - .../workbench/contrib/scm/browser/activity.ts | 2 +- .../contrib/update/browser/update.ts | 6 +-- .../userDataSync/browser/userDataSync.ts | 6 +-- .../services/activity/common/activity.ts | 1 - .../progress/browser/progressService.ts | 2 +- 16 files changed, 82 insertions(+), 81 deletions(-) diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts index df41f2fdfc3..e6bd36f86c6 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts @@ -11,10 +11,10 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ActiveAuxiliaryContext, AuxiliaryBarFocusContext } from 'vs/workbench/common/contextkeys'; -import { PANEL_ACTIVE_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_DRAG_AND_DROP_BORDER, PANEL_INACTIVE_TITLE_FOREGROUND, SIDE_BAR_BACKGROUND, SIDE_BAR_BORDER, SIDE_BAR_FOREGROUND } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_DRAG_AND_DROP_BORDER, PANEL_INACTIVE_TITLE_FOREGROUND, SIDE_BAR_BACKGROUND, SIDE_BAR_BORDER, SIDE_BAR_FOREGROUND } from 'vs/workbench/common/theme'; import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; @@ -143,10 +143,11 @@ export class AuxiliaryBarPart extends AbstractPaneCompositePart { activeBorderBottomColor: theme.getColor(PANEL_ACTIVE_TITLE_BORDER), activeForegroundColor: theme.getColor(PANEL_ACTIVE_TITLE_FOREGROUND), inactiveForegroundColor: theme.getColor(PANEL_INACTIVE_TITLE_FOREGROUND), - badgeBackground: theme.getColor(badgeBackground), - badgeForeground: theme.getColor(badgeForeground), + badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), + badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), dragAndDropBorder: theme.getColor(PANEL_DRAG_AND_DROP_BORDER) - }) + }), + compact: true }; } diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index f885347fcd8..03766f49ad1 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -133,6 +133,7 @@ export interface ICompositeBarOptions { readonly icon: boolean; readonly orientation: ActionsOrientation; readonly colors: (theme: IColorTheme) => ICompositeBarColors; + readonly compact?: boolean; readonly compositeSize: number; readonly overflowActionSize: number; readonly dndHandler: ICompositeDragAndDrop; @@ -208,7 +209,7 @@ export class CompositeBar extends Widget implements ICompositeBar { const item = this.model.findItem(action.id); return item && this.instantiationService.createInstance( CompositeActionViewItem, - { draggable: true, colors: this.options.colors, icon: this.options.icon, hoverOptions: this.options.activityHoverOptions }, + { draggable: true, colors: this.options.colors, icon: this.options.icon, hoverOptions: this.options.activityHoverOptions, compact: this.options.compact }, action as CompositeBarAction, item.pinnedAction, item.toggleBadgeAction, diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index e407e975531..b4dfa8fdc9f 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -140,6 +140,7 @@ export interface ICompositeBarActionViewItemOptions extends IActionViewItemOptio readonly hoverOptions: IActivityHoverOptions; readonly hasPopup?: boolean; + readonly compact?: boolean; } export class CompoisteBarActionViewItem extends BaseActionViewItem { @@ -300,10 +301,25 @@ export class CompoisteBarActionViewItem extends BaseActionViewItem { if (activity && shouldRenderBadges) { - const { badge, clazz } = activity; + const { badge } = activity; + const classes: string[] = []; + + if (this.options.compact) { + classes.push('compact'); + } + + // Progress + if (badge instanceof ProgressBadge) { + show(this.badge); + classes.push('progress-badge'); + } + + else if (this.options.compact) { + show(this.badge); + } // Number - if (badge instanceof NumberBadge) { + else if (badge instanceof NumberBadge) { if (badge.number) { let number = badge.number.toString(); if (badge.number > 999) { @@ -333,16 +349,11 @@ export class CompoisteBarActionViewItem extends BaseActionViewItem { show(this.badge); } - // Progress - else if (badge instanceof ProgressBadge) { - show(this.badge); + if (classes.length) { + this.badge.classList.add(...classes); + this.badgeDisposable.value = toDisposable(() => this.badge.classList.remove(...classes)); } - if (clazz) { - const classNames = clazz.split(' '); - this.badge.classList.add(...classNames); - this.badgeDisposable.value = toDisposable(() => this.badge.classList.remove(...classNames)); - } } this.updateTitle(); diff --git a/src/vs/workbench/browser/parts/globalCompositeBar.ts b/src/vs/workbench/browser/parts/globalCompositeBar.ts index 291c36e1f59..f7391720341 100644 --- a/src/vs/workbench/browser/parts/globalCompositeBar.ts +++ b/src/vs/workbench/browser/parts/globalCompositeBar.ts @@ -12,7 +12,7 @@ import { DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { CompoisteBarActionViewItem, CompositeBarAction, IActivityHoverOptions, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions'; +import { CompoisteBarActionViewItem, CompositeBarAction, IActivityHoverOptions, ICompositeBarActionViewItemOptions, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions'; import { Codicon } from 'vs/base/common/codicons'; import { ThemeIcon } from 'vs/base/common/themables'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; @@ -72,14 +72,16 @@ export class GlobalCompositeBar extends Disposable { this.globalActivityActionBar = this._register(new ActionBar(this.element, { actionViewItemProvider: action => { if (action.id === GLOBAL_ACTIVITY_ID) { - return this.instantiationService.createInstance(GlobalActivityActionViewItem, this.contextMenuActionsProvider, this.colors, this.activityHoverOptions, anchorAlignment, anchorAxisAlignment); + return this.instantiationService.createInstance(GlobalActivityActionViewItem, this.contextMenuActionsProvider, { colors: this.colors, hoverOptions: this.activityHoverOptions }, anchorAlignment, anchorAxisAlignment); } if (action.id === ACCOUNTS_ACTIVITY_ID) { return this.instantiationService.createInstance(AccountsActivityActionViewItem, this.contextMenuActionsProvider, - this.colors, - this.activityHoverOptions, + { + colors: this.colors, + hoverOptions: this.activityHoverOptions + }, anchorAlignment, anchorAxisAlignment, (actions: IAction[]) => { @@ -156,9 +158,8 @@ abstract class AbstractGlobalActivityActionViewItem extends CompoisteBarActionVi constructor( private readonly menuId: MenuId, action: CompositeBarAction, + options: ICompositeBarActionViewItemOptions, private readonly contextMenuActionsProvider: () => IAction[], - colors: (theme: IColorTheme) => ICompositeBarColors, - hoverOptions: IActivityHoverOptions, private readonly anchorAlignment: AnchorAlignment | undefined, private readonly anchorAxisAlignment: AnchorAxisAlignment | undefined, @IThemeService themeService: IThemeService, @@ -170,7 +171,7 @@ abstract class AbstractGlobalActivityActionViewItem extends CompoisteBarActionVi @IKeybindingService keybindingService: IKeybindingService, @IActivityService private readonly activityService: IActivityService, ) { - super(action, { hoverOptions, colors, draggable: false, icon: true, hasPopup: true }, () => true, themeService, hoverService, configurationService, keybindingService); + super(action, { draggable: false, icon: true, hasPopup: true, ...options }, () => true, themeService, hoverService, configurationService, keybindingService); this.updateItemActivity(); this._register(this.activityService.onDidChangeActivity(viewContainerOrAction => { @@ -184,10 +185,10 @@ abstract class AbstractGlobalActivityActionViewItem extends CompoisteBarActionVi const activities = this.activityService.getActivity(this.compositeBarActionItem.id); let activity = activities[0]; if (activity) { - const { badge, clazz, priority } = activity; + const { badge, priority } = activity; if (badge instanceof NumberBadge && activities.length > 1) { const cumulativeNumberBadge = this.getCumulativeNumberBadge(activities, priority ?? 0); - activity = { badge: cumulativeNumberBadge, clazz }; + activity = { badge: cumulativeNumberBadge }; } } (this.action as CompositeBarAction).activity = activity; @@ -289,8 +290,7 @@ export class AccountsActivityActionViewItem extends AbstractGlobalActivityAction constructor( contextMenuActionsProvider: () => IAction[], - colors: (theme: IColorTheme) => ICompositeBarColors, - activityHoverOptions: IActivityHoverOptions, + options: ICompositeBarActionViewItemOptions, anchorAlignment: AnchorAlignment | undefined, anchorAxisAlignment: AnchorAxisAlignment | undefined, private readonly fillContextMenuActions: (actions: IAction[]) => void, @@ -315,7 +315,7 @@ export class AccountsActivityActionViewItem extends AbstractGlobalActivityAction name: localize('accounts', "Accounts"), classNames: ThemeIcon.asClassNameArray(GlobalCompositeBar.ACCOUNTS_ICON) }); - super(MenuId.AccountsContext, action, contextMenuActionsProvider, colors, activityHoverOptions, anchorAlignment, anchorAxisAlignment, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, keybindingService, activityService); + super(MenuId.AccountsContext, action, options, contextMenuActionsProvider, anchorAlignment, anchorAxisAlignment, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, keybindingService, activityService); this._register(action); this.registerListeners(); this.initialize(); @@ -531,8 +531,7 @@ export class GlobalActivityActionViewItem extends AbstractGlobalActivityActionVi constructor( contextMenuActionsProvider: () => IAction[], - colors: (theme: IColorTheme) => ICompositeBarColors, - activityHoverOptions: IActivityHoverOptions, + options: ICompositeBarActionViewItemOptions, anchorAlignment: AnchorAlignment | undefined, anchorAxisAlignment: AnchorAxisAlignment | undefined, @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, @@ -552,7 +551,7 @@ export class GlobalActivityActionViewItem extends AbstractGlobalActivityActionVi name: localize('manage', "Manage"), classNames: ThemeIcon.asClassNameArray(userDataProfileService.currentProfile.icon ? ThemeIcon.fromId(userDataProfileService.currentProfile.icon) : DEFAULT_ICON) }); - super(MenuId.GlobalActivity, action, contextMenuActionsProvider, colors, activityHoverOptions, anchorAlignment, anchorAxisAlignment, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, keybindingService, activityService); + super(MenuId.GlobalActivity, action, options, contextMenuActionsProvider, anchorAlignment, anchorAxisAlignment, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, keybindingService, activityService); this._register(action); this._register(this.userDataProfileService.onDidChangeCurrentProfile(e => { action.compositeBarActionItem = { @@ -625,10 +624,14 @@ export class SimpleAccountActivityActionViewItem extends AccountsActivityActionV @IActivityService activityService: IActivityService, @IInstantiationService instantiationService: IInstantiationService ) { - super(() => [], theme => ({ - badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), - badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), - }), hoverOptions, undefined, undefined, actions => actions, themeService, lifecycleService, hoverService, contextMenuService, menuService, contextKeyService, authenticationService, environmentService, productService, configurationService, keybindingService, secretStorageService, logService, activityService, instantiationService); + super(() => [], { + colors: theme => ({ + badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), + badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), + }), + hoverOptions, + compact: true, + }, undefined, undefined, actions => actions, themeService, lifecycleService, hoverService, contextMenuService, menuService, contextKeyService, authenticationService, environmentService, productService, configurationService, keybindingService, secretStorageService, logService, activityService, instantiationService); } } @@ -648,9 +651,13 @@ export class SimpleGlobalActivityActionViewItem extends GlobalActivityActionView @IInstantiationService instantiationService: IInstantiationService, @IActivityService activityService: IActivityService, ) { - super(() => [], theme => ({ - badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), - badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), - }), hoverOptions, undefined, undefined, userDataProfileService, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService, instantiationService, activityService); + super(() => [], { + colors: theme => ({ + badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), + badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), + }), + hoverOptions, + compact: true, + }, undefined, undefined, userDataProfileService, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService, instantiationService, activityService); } } diff --git a/src/vs/workbench/browser/parts/media/paneCompositePart.css b/src/vs/workbench/browser/parts/media/paneCompositePart.css index 23b12ec3f9c..ee9abd7b981 100644 --- a/src/vs/workbench/browser/parts/media/paneCompositePart.css +++ b/src/vs/workbench/browser/parts/media/paneCompositePart.css @@ -48,9 +48,13 @@ display: flex; } -.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon { - padding-left: 2px; - padding-right: 2px; +.monaco-workbench .pane-composite-part > .title > .composite-bar-container >.composite-bar > .monaco-action-bar .action-item.icon { + height: 24px; + padding: 0 5px; +} + +.monaco-workbench .pane-composite-part > .title > .composite-bar-container >.composite-bar .monaco-action-bar .action-label.codicon { + font-size: 18px; } .monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .action-label:not(.codicon) { @@ -154,7 +158,7 @@ position: relative; } -.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.progress-badge { +.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact { position: absolute; top: 0; bottom: 0; @@ -166,7 +170,7 @@ z-index: 2; } -.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.progress-badge .badge-content { +.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; top: 13px; right: 2px; @@ -174,13 +178,12 @@ font-weight: 600; min-width: 10px; height: 10px; - line-height: 10px; padding: 0 4px; border-radius: 16px; text-align: center; } -.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.progress-badge .badge-content::before { +.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact.progress-badge .badge-content::before { mask-size: 10px; -webkit-mask-size: 10px; top: 4px; diff --git a/src/vs/workbench/browser/parts/paneCompositeBar.ts b/src/vs/workbench/browser/parts/paneCompositeBar.ts index 350028bf4a4..13d713ca7bc 100644 --- a/src/vs/workbench/browser/parts/paneCompositeBar.ts +++ b/src/vs/workbench/browser/parts/paneCompositeBar.ts @@ -65,6 +65,7 @@ export interface IPaneCompositeBarOptions { readonly pinnedViewContainersKey: string; readonly placeholderViewContainersKey: string; readonly icon: boolean; + readonly compact?: boolean; readonly iconSize: number; readonly recomputeSizes: boolean; readonly orientation: ActionsOrientation; @@ -126,6 +127,7 @@ export class PaneCompositeBar extends Disposable { private createCompositeBar(cachedItems: ICompositeBarItem[]) { return this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, { icon: this.options.icon, + compact: this.options.compact, orientation: this.options.orientation, activityHoverOptions: this.options.activityHoverOptions, preventLoopNavigation: this.options.preventLoopNavigation, diff --git a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css index 8934987b817..4b0289f87ef 100644 --- a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css +++ b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css @@ -63,19 +63,3 @@ .monaco-workbench .sidebar.pane-composite-part > .title > .composite-bar-container { flex: 1; } - -.monaco-workbench .sidebar.pane-composite-part > .title > .composite-bar-container >.composite-bar > .monaco-action-bar .action-item.icon { - height: 24px; - padding: 0 5px; -} - -.monaco-workbench .sidebar.pane-composite-part > .title > .composite-bar-container >.composite-bar .monaco-action-bar .action-label.codicon { - font-size: 18px; -} - -.monaco-workbench .sidebar.pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .badge .badge-content { - padding-top: 2px; - font-size: 9px; - min-width: 11px; - height: 16px; -} diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 6d5099b914f..17a010dfad8 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -190,7 +190,8 @@ export class SidebarPart extends AbstractPaneCompositePart { badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), dragAndDropBorder: theme.getColor(PANEL_DRAG_AND_DROP_BORDER) - }) + }), + compact: true }; } diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 5d8d5b10cb4..5325e70151d 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -422,10 +422,9 @@ display: inline-block; box-sizing: border-box; position: relative; - } -.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.progress-badge { +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact { position: absolute; top: 0; bottom: 0; @@ -437,13 +436,13 @@ z-index: 2; } -.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.progress-badge .badge-content::before { +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content::before { mask-size: 10px; -webkit-mask-size: 10px; top: 4px; } -.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.progress-badge .badge-content { +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; top: 12px; right: 0px; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index bb92321d133..94a6279bcdb 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -851,7 +851,7 @@ export class StatusUpdater extends Disposable implements IWorkbenchContribution msg += extensionsReloadRequired.length === 1 ? localize('extensionToReload', '{0} requires reload', extensionsReloadRequired.length) : localize('extensionsToReload', '{0} require reload', extensionsReloadRequired.length); } const badge = new NumberBadge(newBadgeNumber, () => msg); - this.badgeHandle.value = this.activityService.showViewContainerActivity(VIEWLET_ID, { badge, clazz: 'extensions-badge count-badge' }); + this.badgeHandle.value = this.activityService.showViewContainerActivity(VIEWLET_ID, { badge }); } } } diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts index 6dfdf2560f2..3c8a4afffa1 100644 --- a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -60,7 +60,6 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib VIEWLET_ID, { badge: new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), - clazz: 'explorer-viewlet-label' } ); } else { diff --git a/src/vs/workbench/contrib/scm/browser/activity.ts b/src/vs/workbench/contrib/scm/browser/activity.ts index b33088511af..b4edaa7f64e 100644 --- a/src/vs/workbench/contrib/scm/browser/activity.ts +++ b/src/vs/workbench/contrib/scm/browser/activity.ts @@ -197,7 +197,7 @@ export class SCMStatusController implements IWorkbenchContribution { if (count > 0) { const badge = new NumberBadge(count, num => localize('scmPendingChangesBadge', '{0} pending changes', num)); - this.badgeDisposable.value = this.activityService.showViewActivity(VIEW_PANE_ID, { badge, clazz: 'scm-viewlet-label' }); + this.badgeDisposable.value = this.activityService.showViewActivity(VIEW_PANE_ID, { badge }); } else { this.badgeDisposable.value = undefined; } diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index bfba80a99df..b0ada2acd81 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -250,29 +250,25 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu } let badge: IBadge | undefined = undefined; - let clazz: string | undefined; let priority: number | undefined = undefined; if (state.type === StateType.AvailableForDownload || state.type === StateType.Downloaded || state.type === StateType.Ready) { badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", this.productService.nameShort)); } else if (state.type === StateType.CheckingForUpdates) { badge = new ProgressBadge(() => nls.localize('checkingForUpdates', "Checking for Updates...")); - clazz = 'progress-badge'; priority = 1; } else if (state.type === StateType.Downloading) { badge = new ProgressBadge(() => nls.localize('downloading', "Downloading...")); - clazz = 'progress-badge'; priority = 1; } else if (state.type === StateType.Updating) { badge = new ProgressBadge(() => nls.localize('updating', "Updating...")); - clazz = 'progress-badge'; priority = 1; } this.badgeDisposable.clear(); if (badge) { - this.badgeDisposable.value = this.activityService.showGlobalActivity({ badge, clazz, priority }); + this.badgeDisposable.value = this.activityService.showGlobalActivity({ badge, priority }); } this.state = state; diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 50d091fbd3d..5691e410542 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -425,19 +425,17 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo this.globalActivityBadgeDisposable.clear(); let badge: IBadge | undefined = undefined; - let clazz: string | undefined; let priority: number | undefined = undefined; if (this.userDataSyncService.conflicts.length && this.userDataSyncEnablementService.isEnabled()) { badge = new NumberBadge(this.getConflictsCount(), () => localize('has conflicts', "{0}: Conflicts Detected", SYNC_TITLE.value)); } else if (this.turningOnSync) { badge = new ProgressBadge(() => localize('turning on syncing', "Turning on Settings Sync...")); - clazz = 'progress-badge'; priority = 1; } if (badge) { - this.globalActivityBadgeDisposable.value = this.activityService.showGlobalActivity({ badge, clazz, priority }); + this.globalActivityBadgeDisposable.value = this.activityService.showGlobalActivity({ badge, priority }); } } @@ -451,7 +449,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } if (badge) { - this.accountBadgeDisposable.value = this.activityService.showAccountsActivity({ badge, clazz: undefined, priority: undefined }); + this.accountBadgeDisposable.value = this.activityService.showAccountsActivity({ badge, priority: undefined }); } } diff --git a/src/vs/workbench/services/activity/common/activity.ts b/src/vs/workbench/services/activity/common/activity.ts index 5768712f35e..62f5150097b 100644 --- a/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -11,7 +11,6 @@ import { ViewContainer } from 'vs/workbench/common/views'; export interface IActivity { readonly badge: IBadge; - readonly clazz?: string; readonly priority?: number; } diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index b9d54ac98cb..9dbf8a6e216 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -452,7 +452,7 @@ export class ProgressService extends Disposable implements IProgressService { let activityProgress: IDisposable; let delayHandle: any = setTimeout(() => { delayHandle = undefined; - const handle = this.activityService.showViewContainerActivity(viewletId, { badge: new ProgressBadge(() => ''), clazz: 'progress-badge', priority: 100 }); + const handle = this.activityService.showViewContainerActivity(viewletId, { badge: new ProgressBadge(() => ''), priority: 100 }); const startTimeVisible = Date.now(); const minTimeVisible = 300; activityProgress = { From 7da6dc1bcab1d6c5c0bf65ab828ad2e63d3343fb Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 12 Oct 2023 20:20:16 +0200 Subject: [PATCH 040/290] align with primary sidebar (#195501) --- .../browser/parts/auxiliarybar/media/auxiliaryBarPart.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css b/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css index eed4b1f0954..2c0c99d85cc 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css +++ b/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css @@ -14,6 +14,10 @@ background-color: var(--vscode-sideBar-background); } +.monaco-workbench .part.auxiliarybar > .title > .composite-bar-container { + flex: 1; +} + .monaco-workbench .part.auxiliarybar > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item:hover .action-label, .monaco-workbench .part.auxiliarybar > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item:focus .action-label { color: var(--vscode-sideBarTitle-foreground) !important; From 17eb59f1467bd9c0cbccf7ac341257b83cf4f6e7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 12 Oct 2023 20:49:32 +0200 Subject: [PATCH 041/290] make responses of `chatRequestAccess` proposal easier to consume and digest (#195479) * make responses of `chatRequestAccess` proposal easier to consume and digest * allow same modern JS in API as in the rest --- src/tsconfig.vscode-dts.json | 3 +- src/vs/base/common/async.ts | 57 +++++++++++ .../api/common/extHostChatProvider.ts | 95 +++++++++++++++++-- .../vscode.proposed.chatRequestAccess.d.ts | 72 ++++++++++++-- 4 files changed, 206 insertions(+), 21 deletions(-) diff --git a/src/tsconfig.vscode-dts.json b/src/tsconfig.vscode-dts.json index b8607658396..3df2c2292ef 100644 --- a/src/tsconfig.vscode-dts.json +++ b/src/tsconfig.vscode-dts.json @@ -13,8 +13,7 @@ "forceConsistentCasingInFileNames": true, "types": [], "lib": [ - "es5", - "ES2015.Iterable" + "ES2022" ], }, "include": [ diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 98b6aff2b4e..192c222315b 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -1887,4 +1887,61 @@ export function createCancelableAsyncIterable(callback: (token: CancellationT }); } +export class DeferredAsyncIterableObject { + + private readonly _deferred = new DeferredPromise(); + private readonly _asyncIterable: AsyncIterableObject; + + private _errorFn: (error: Error) => void; + private _emitFn: (item: T) => void; + + constructor() { + this._asyncIterable = new AsyncIterableObject(emitter => { + + if (earlyError) { + emitter.reject(earlyError); + return; + } + if (earlyItems) { + emitter.emitMany(earlyItems); + } + this._errorFn = (error: Error) => emitter.reject(error); + this._emitFn = (item: T) => emitter.emitOne(item); + return this._deferred.p; + }); + + let earlyError: Error | undefined; + let earlyItems: T[] | undefined; + + this._emitFn = (item: T) => { + if (!earlyItems) { + earlyItems = []; + } + earlyItems.push(item); + }; + this._errorFn = (error: Error) => { + if (!earlyError) { + earlyError = error; + } + }; + } + + get asyncIterable(): AsyncIterableObject { + return this._asyncIterable; + } + + complete(): void { + this._deferred.complete(); + } + + error(error: Error): void { + this._errorFn(error); + this._deferred.complete(); + } + + emit(item: T): void { + this._emitFn(item); + } +} + //#endregion diff --git a/src/vs/workbench/api/common/extHostChatProvider.ts b/src/vs/workbench/api/common/extHostChatProvider.ts index e7679f4bfd4..fa819c6bec3 100644 --- a/src/vs/workbench/api/common/extHostChatProvider.ts +++ b/src/vs/workbench/api/common/extHostChatProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken } from 'vs/base/common/cancellation'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostChatProviderShape, IMainContext, MainContext, MainThreadChatProviderShape } from 'vs/workbench/api/common/extHost.protocol'; @@ -12,12 +12,82 @@ import type * as vscode from 'vscode'; import { Progress } from 'vs/platform/progress/common/progress'; import { IChatMessage, IChatResponseFragment } from 'vs/workbench/contrib/chat/common/chatProvider'; import { ExtensionIdentifier, ExtensionIdentifierMap } from 'vs/platform/extensions/common/extensions'; +import { DeferredAsyncIterableObject } from 'vs/base/common/async'; +import { Emitter } from 'vs/base/common/event'; type ProviderData = { readonly extension: ExtensionIdentifier; readonly provider: vscode.ChatResponseProvider; }; +class ChatResponseStream { + + readonly apiObj: vscode.ChatResponseStream; + readonly stream = new DeferredAsyncIterableObject(); + + constructor(option: number, stream?: DeferredAsyncIterableObject) { + this.stream = stream ?? new DeferredAsyncIterableObject(); + const that = this; + this.apiObj = { + option: option, + response: that.stream.asyncIterable + }; + } +} + +class ChatRequest { + + readonly apiObject: vscode.ChatRequest; + + private readonly _onDidStart = new Emitter(); + private readonly _responseStreams = new Map(); + private readonly _defaultStream = new DeferredAsyncIterableObject(); + private _isDone: boolean = false; + + constructor( + promise: Promise, + cts: CancellationTokenSource + ) { + const that = this; + this.apiObject = { + result: promise, + response: that._defaultStream.asyncIterable, + onDidStartResponseStream: that._onDidStart.event, + cancel() { cts.cancel(); }, + }; + + promise.finally(() => { + this._isDone = true; + if (this._responseStreams.size > 0) { + for (const [, value] of this._responseStreams) { + value.stream.complete(); + } + } else { + this._defaultStream.complete(); + } + }); + } + + handleFragment(fragment: IChatResponseFragment): void { + if (this._isDone) { + return; + } + let res = this._responseStreams.get(fragment.index); + if (!res) { + if (this._responseStreams.size === 0) { + // the first response claims the default response + res = new ChatResponseStream(fragment.index, this._defaultStream); + } else { + res = new ChatResponseStream(fragment.index); + } + this._responseStreams.set(fragment.index, res); + this._onDidStart.fire(res.apiObj); + } + res.stream.emit(fragment.part); + } + +} + export class ExtHostChatProvider implements ExtHostChatProviderShape { private static _idPool = 1; @@ -62,7 +132,7 @@ export class ExtHostChatProvider implements ExtHostChatProviderShape { //#region --- making request - private readonly _pendingRequest = new Map>(); + private readonly _pendingRequest = new Map(); private readonly _chatAccessAllowList = new ExtensionIdentifierMap>(); @@ -84,24 +154,31 @@ export class ExtHostChatProvider implements ExtHostChatProviderShape { get isRevoked() { return !that._chatAccessAllowList.has(from); }, - async makeRequest(messages, options, progress, token) { + makeRequest(messages, options, token) { if (!that._chatAccessAllowList.has(from)) { throw new Error('Access to chat has been revoked'); } + const cts = new CancellationTokenSource(token); const requestId = (Math.random() * 1e6) | 0; - that._pendingRequest.set(requestId, progress); - try { - await that._proxy.$fetchResponse(from, identifier, requestId, messages.map(typeConvert.ChatMessage.from), options, token); - } finally { + const requestPromise = that._proxy.$fetchResponse(from, identifier, requestId, messages.map(typeConvert.ChatMessage.from), options ?? {}, cts.token); + const res = new ChatRequest(requestPromise, cts); + that._pendingRequest.set(requestId, { res }); + + requestPromise.finally(() => { that._pendingRequest.delete(requestId); - } + }); + + return res.apiObject; }, }; } async $handleResponseFragment(requestId: number, chunk: IChatResponseFragment): Promise { - this._pendingRequest.get(requestId)?.report(chunk); + const data = this._pendingRequest.get(requestId);//.report(chunk); + if (data) { + data.res.handleFragment(chunk); + } } } diff --git a/src/vscode-dts/vscode.proposed.chatRequestAccess.d.ts b/src/vscode-dts/vscode.proposed.chatRequestAccess.d.ts index bf6ac4ff236..230366ae909 100644 --- a/src/vscode-dts/vscode.proposed.chatRequestAccess.d.ts +++ b/src/vscode-dts/vscode.proposed.chatRequestAccess.d.ts @@ -5,32 +5,84 @@ declare module 'vscode' { - export interface ChatResponseFragment { - index: number; - part: string; + export interface ChatResponseStream { + + /** + * The response stream. + */ + readonly response: AsyncIterable; + + /** + * The variant of multiple responses. This is used to disambiguate between multiple + * response streams when having asked for multiple response options + */ + readonly option: number; + } + + export interface ChatRequest { + + /** + * The overall result of the request which represents failure or success + * but _not_ the actual response or responses + */ + result: Thenable; + + /** + * The _default response_ stream. This is the stream of the first response option + * receiving data. + * + * Usually there is only one response option and this stream is more convienient to use + * than the {@link onDidStartResponseStream `onDidStartResponseStream`} event. + */ + response: AsyncIterable; + + /** + * An event that fires whenever a new response option is available. The response + * itself is a stream of the actual response. + * + * *Note* that the first time this event fires, the {@link ChatResponseStream.response response stream} + * is the same as the {@link response `default response stream`}. + * + * *Note* that unless requested there is only one response option, so this event will only fire + * once. + */ + onDidStartResponseStream: Event; + + /** + * Cancel this request. + */ + // TODO@API remove this? We pass a token to makeRequest call already + cancel(): void; } /** * Represents access to using a chat provider (LLM). Access is granted and temporary, usually only valid - * for the duration of an user interaction. + * for the duration of an user interaction or specific time frame. */ export interface ChatAccess { /** - * Whether the access to chat has been revoked. This happens when the user interaction that allowed for - * chat access is finished. + * Whether the access to chat has been revoked. This happens when the condition that allowed for + * chat access doesn't hold anymore, e.g a user interaction has ended. */ isRevoked: boolean; /** - * TODO: return an AsyncIterable instead of asking to pass Progress<...>? + * Make a chat request. + * + * The actual response will be reported back via the `progress` callback. The promise returned by this function + * returns a overall result which represents failure or success of the request. + * + * Chat can be asked for multiple response options. In that case the `progress` callback will be called multiple + * time with different `ChatResponseStream` objects. Each object represents a different response option and the actual + * response will be reported back via their `stream` property. + * + * *Note:* This will throw an error if access has been revoked. * * @param messages * @param options - * @param progress - * @param token */ - makeRequest(messages: ChatMessage[], options: { [name: string]: any }, progress: Progress, token: CancellationToken): Thenable; + makeRequest(messages: ChatMessage[], options: { [name: string]: any }, token: CancellationToken): ChatRequest; } export namespace chat { From 7afb6c27ba9d2a4e48f12a845adb998251a99376 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 11:52:37 -0700 Subject: [PATCH 042/290] use prompt group --- .../commandDetectionCapability.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 90ff205798a..b48bca49439 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -373,16 +373,16 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe // On Windows track all cursor movements after the command start sequence this._commandMarkers.length = 0; - let promptMatch: RegExpMatchArray | undefined; + let prompt: string | undefined = this._getWindowsPrompt(); // Conpty could have the wrong cursor position at this point. - if (!this._cursorOnNextLine() || !this._cursorLineLooksLikeWindowsPrompt()) { + if (!this._cursorOnNextLine() || !prompt) { this._windowsPromptPollingInProcess = true; // Poll for 200ms until the cursor position is correct. let i = 0; for (; i < 20; i++) { await timeout(10); - promptMatch = this._cursorLineLooksLikeWindowsPrompt(); - if (!this._windowsPromptPollingInProcess || this._cursorOnNextLine() && promptMatch) { + prompt = this._getWindowsPrompt(); + if (!this._windowsPromptPollingInProcess || this._cursorOnNextLine() && prompt) { if (!this._windowsPromptPollingInProcess) { this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling cancelled'); } @@ -391,10 +391,10 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe } this._windowsPromptPollingInProcess = false; if (i === 20) { - this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); - } else if (promptMatch) { + this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._getWindowsPrompt()); + } else if (prompt) { // use the regex to set the position as it's possible input has occurred - this._currentCommand.commandStartX = promptMatch[0].length + 1; + this._currentCommand.commandStartX = prompt.length + 1; } } else { // HACK: Fire command started on the following frame on Windows to allow the cursor @@ -437,13 +437,14 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe return cursorYAbsolute > lastCommandYAbsolute; } - private _cursorLineLooksLikeWindowsPrompt(): RegExpMatchArray | undefined { + private _getWindowsPrompt(): string | undefined { const line = this._terminal.buffer.active.getLine(this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY); if (!line) { return; } // TODO: fine tune prompt regex to accomodate for unique configurtions. - return line.translateToString(true)?.match(/^(PS.+>)|([A-Z]:\\.*>)/) ?? undefined; + + return line.translateToString(true)?.match(/^(?(?:PS.+>)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; } handleGenericCommand(options?: IHandleCommandOptions): void { From 2cde938231213432c2a4eeefce788db12670e3b3 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 11:53:17 -0700 Subject: [PATCH 043/290] use prompt group --- .../terminal/common/capabilities/commandDetectionCapability.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index b48bca49439..fd8ff6d4d65 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -443,7 +443,6 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe return; } // TODO: fine tune prompt regex to accomodate for unique configurtions. - return line.translateToString(true)?.match(/^(?(?:PS.+>)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; } From f46251f0210aef8edb1f4e7a1023b6242319e37b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 12 Oct 2023 12:51:59 -0700 Subject: [PATCH 044/290] Implement provideFollowups for chat agents (#195438) * Sketch provideFollowups for chat agents * Implement provideFollowups for chatAgents2 API --- .../api/browser/mainThreadChatAgents2.ts | 32 ++++++++++++------- .../workbench/api/common/extHost.protocol.ts | 5 +-- .../api/common/extHostChatAgents2.ts | 27 ++++++++++------ .../contrib/chat/common/chatAgents.ts | 13 +++++--- .../contrib/chat/common/chatService.ts | 1 + .../contrib/chat/common/chatServiceImpl.ts | 26 +++++++++------ 6 files changed, 68 insertions(+), 36 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index 1e389f6ff7b..c6102cbeecc 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -3,15 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DisposableMap, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; import { IProgress } from 'vs/platform/progress/common/progress'; import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IExtensionChatAgentMetadata, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; -import { IChatProgress } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatFollowup, IChatProgress, IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; - type AgentData = { dispose: () => void; name: string; @@ -20,27 +19,29 @@ type AgentData = { }; @extHostNamedCustomer(MainContext.MainThreadChatAgents2) -export class MainThreadChatAgents implements MainThreadChatAgentsShape2, IDisposable { +export class MainThreadChatAgents2 extends Disposable implements MainThreadChatAgentsShape2 { - private readonly _agents = new DisposableMap; + private readonly _agents = this._register(new DisposableMap()); private readonly _pendingProgress = new Map>(); private readonly _proxy: ExtHostChatAgentsShape2; constructor( extHostContext: IExtHostContext, - @IChatAgentService private readonly _chatAgentService: IChatAgentService + @IChatAgentService private readonly _chatAgentService: IChatAgentService, + @IChatService private readonly _chatService: IChatService, ) { + super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents2); + + this._register(this._chatService.onDidDisposeSession(e => { + this._proxy.$releaseSession(e.sessionId); + })); } $unregisterAgent(handle: number): void { this._agents.deleteAndDispose(handle); } - dispose(): void { - this._agents.clearAndDisposeAll(); - } - $registerAgent(handle: number, name: string, metadata: IExtensionChatAgentMetadata): void { const d = this._chatAgentService.registerAgent({ id: name, @@ -49,14 +50,21 @@ export class MainThreadChatAgents implements MainThreadChatAgentsShape2, IDispos const requestId = Math.random(); // Make this a guid this._pendingProgress.set(requestId, progress); try { - return await this._proxy.$invokeAgent(handle, requestId, request, { history }, token) ?? {}; + return await this._proxy.$invokeAgent(handle, request.sessionId, requestId, request, { history }, token) ?? {}; } finally { this._pendingProgress.delete(requestId); } }, + provideFollowups: async (sessionId, token): Promise => { + if (!this._agents.get(handle)?.hasSlashCommands) { + return []; + } + + return this._proxy.$provideFollowups(handle, sessionId, token); + }, provideSlashCommands: async (token) => { if (!this._agents.get(handle)?.hasSlashCommands) { - return []; // safe an IPC call + return []; // save an IPC call } return this._proxy.$provideSlashCommands(handle, token); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 0e5ef464728..86c7f4ade21 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1181,9 +1181,10 @@ export interface ExtHostChatAgentsShape { } export interface ExtHostChatAgentsShape2 { - $invokeAgent(handle: number, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise; + $invokeAgent(handle: number, sessionId: string, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise; $provideSlashCommands(handle: number, token: CancellationToken): Promise; - $provideFollowups(handle: number, requestId: number, token: CancellationToken): Promise; + $provideFollowups(handle: number, sessionId: string, token: CancellationToken): Promise; + $releaseSession(sessionId: string): void; } export interface MainThreadChatVariablesShape extends IDisposable { diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 365d4d0d91d..f600a080047 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -26,6 +26,8 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { private readonly _agents = new Map(); private readonly _proxy: MainThreadChatAgentsShape2; + private readonly _previousResultMap: Map = new Map(); + constructor( mainContext: IMainContext, private readonly _extHostChatProvider: ExtHostChatProvider, @@ -43,7 +45,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return agent.apiAgent; } - async $invokeAgent(handle: number, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise { + async $invokeAgent(handle: number, sessionId: string, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise { const agent = this._agents.get(handle); if (!agent) { throw new Error(`[CHAT](${handle}) CANNOT invoke agent because the agent is not registered`); @@ -81,10 +83,10 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return await raceCancellation(Promise.resolve(task).then((result) => { if (result) { - // An option would be to call provideFollowups here and send the result back to the renderer, rather than store the result - // and wait for the renderer to ask for followups - // agent.provideFollowups(result, token); + this._previousResultMap.set(sessionId, result); return { errorDetails: result.errorDetails }; // TODO timings here + } else { + this._previousResultMap.delete(sessionId); } return undefined; @@ -104,6 +106,10 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { } } + $releaseSession(sessionId: string): void { + this._previousResultMap.delete(sessionId); + } + async $provideSlashCommands(handle: number, token: CancellationToken): Promise { const agent = this._agents.get(handle); if (!agent) { @@ -113,15 +119,18 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return agent.provideSlashCommand(token); } - async $provideFollowups(handle: number, requestId: number, token: CancellationToken): Promise { + $provideFollowups(handle: number, sessionId: string, token: CancellationToken): Promise { const agent = this._agents.get(handle); if (!agent) { - // this is OK, the agent might have disposed while the request was in flight - return []; + return Promise.resolve([]); } - // TODO look up result object based on requestId - return agent.provideFollowups(null!, token); + const result = this._previousResultMap.get(sessionId); + if (!result) { + return Promise.resolve([]); + } + + return agent.provideFollowups(result, token); } } diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index e6a33f88f88..525137f000e 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -19,7 +19,7 @@ export interface IChatAgent { id: string; metadata: IChatAgentMetadata; invoke(request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise; - // provideFollowups?: IChatAgentFollowupProvider; + provideFollowups?(sessionId: string, token: CancellationToken): Promise; provideSlashCommands(token: CancellationToken): Promise; } @@ -42,6 +42,7 @@ export interface IChatAgentMetadata { } export interface IChatAgentRequest { + sessionId: string; requestId: string; command?: string; message: string; @@ -65,7 +66,7 @@ export interface IChatAgentService { readonly onDidChangeAgents: Event; registerAgent(agent: IChatAgent): IDisposable; invokeAgent(id: string, request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise; - getFollowups(id: string, requestId: string): IChatFollowup[]; + getFollowups(id: string, sessionId: string, token: CancellationToken): Promise; getAgents(): Array; getAgent(id: string): IChatAgent | undefined; hasAgent(id: string): boolean; @@ -133,12 +134,16 @@ export class ChatAgentService extends Disposable implements IChatAgentService { return await data.agent.invoke(request, progress, history, token); } - getFollowups(id: string, requestId: string): IChatFollowup[] { + async getFollowups(id: string, sessionId: string, token: CancellationToken): Promise { const data = this._agents.get(id); if (!data) { throw new Error(`No agent with id ${id}`); } - return []; + if (!data.agent.provideFollowups) { + return []; + } + + return data.agent.provideFollowups(sessionId, token); } } diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 3d280772e1e..dacd94fd844 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -280,6 +280,7 @@ export interface IChatService { onDidPerformUserAction: Event; notifyUserAction(event: IChatUserActionEvent): void; + onDidDisposeSession: Event<{ sessionId: string }>; transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void; } diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 947e471dc3d..af03c838a71 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -147,6 +147,9 @@ export class ChatService extends Disposable implements IChatService { private readonly _onDidSubmitSlashCommand = this._register(new Emitter<{ slashCommand: string; sessionId: string }>()); public readonly onDidSubmitSlashCommand = this._onDidSubmitSlashCommand.event; + private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string }>()); + public readonly onDidDisposeSession = this._onDidDisposeSession.event; + constructor( @IStorageService private readonly storageService: IStorageService, @ILogService private readonly logService: ILogService, @@ -374,6 +377,7 @@ export class ChatService extends Disposable implements IChatService { model.setInitializationError(err); model.dispose(); this._sessionModels.delete(model.sessionId); + this._onDidDisposeSession.fire({ sessionId: model.sessionId }); } } @@ -501,7 +505,7 @@ export class ChatService extends Disposable implements IChatService { } let rawResponse: IChatResponse | null | undefined; - let slashCommandFollowups: IChatFollowup[] | void = []; + let agentOrCommandFollowups: Promise | undefined = undefined; if (typeof message === 'string' && agentPart) { const history: IChatMessage[] = []; @@ -516,6 +520,7 @@ export class ChatService extends Disposable implements IChatService { request = model.addRequest(parsedRequest, agentPart.agent); const requestProps: IChatAgentRequest = { + sessionId, requestId: generateUuid(), message: message, variables: {}, @@ -530,8 +535,9 @@ export class ChatService extends Disposable implements IChatService { const agentResult = await this.chatAgentService.invokeAgent(agentPart.agent.id, requestProps, new Progress(p => { progressCallback(p); }), history, token); - slashCommandFollowups = agentResult?.followUp; rawResponse = { session: model.session!, errorDetails: agentResult.errorDetails, timings: agentResult.timings }; + agentOrCommandFollowups = agentResult?.followUp ? Promise.resolve(agentResult.followUp) : + this.chatAgentService.getFollowups(agentPart.agent.id, sessionId, CancellationToken.None); } else if (commandPart && typeof message === 'string' && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) { request = model.addRequest(parsedRequest); // contributed slash commands @@ -549,7 +555,7 @@ export class ChatService extends Disposable implements IChatService { const data = isCompleteInteractiveProgressTreeData(content) ? content : { content }; progressCallback(data); }), history, token); - slashCommandFollowups = commandResult?.followUp; + agentOrCommandFollowups = Promise.resolve(commandResult?.followUp); rawResponse = { session: model.session! }; } else { @@ -592,15 +598,16 @@ export class ChatService extends Disposable implements IChatService { this.trace('sendRequest', `Provider returned response for session ${model.sessionId}`); // TODO refactor this or rethink the API https://github.com/microsoft/vscode-copilot/issues/593 - if (provider.provideFollowups) { + if (agentOrCommandFollowups) { + agentOrCommandFollowups.then(followups => { + model.setFollowups(request, followups); + model.completeResponse(request); + }); + } else if (provider.provideFollowups) { Promise.resolve(provider.provideFollowups(model.session!, CancellationToken.None)).then(providerFollowups => { - const allFollowups = providerFollowups?.concat(slashCommandFollowups ?? []); - model.setFollowups(request, allFollowups ?? undefined); + model.setFollowups(request, providerFollowups ?? undefined); model.completeResponse(request); }); - } else if (slashCommandFollowups?.length) { - model.setFollowups(request, slashCommandFollowups); - model.completeResponse(request); } else { model.completeResponse(request); } @@ -725,6 +732,7 @@ export class ChatService extends Disposable implements IChatService { model.dispose(); this._sessionModels.delete(sessionId); this._pendingRequests.get(sessionId)?.cancel(); + this._onDidDisposeSession.fire({ sessionId }); } registerProvider(provider: IChatProvider): IDisposable { From 5776adf61e3e84cafc2c2084be048487dd3998cd Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 13:20:15 -0700 Subject: [PATCH 045/290] tests are breaking --- .../browser/accessibilityService.ts | 8 +--- .../screenReaderNotificationService.ts | 43 ++++++++++++++++++ .../accessibility/common/accessibility.ts | 1 - .../test/common/testAccessibilityService.ts | 1 + .../audioCues/browser/audioCueService.ts | 8 ++++ .../audioCues/browser/media/clear.mp3 | Bin 0 -> 34816 bytes .../browser/audioCues.contribution.ts | 10 ++-- .../chat/browser/actions/chatClearActions.ts | 4 +- .../workbench/contrib/debug/browser/repl.ts | 6 +-- .../output/browser/output.contribution.ts | 6 +-- .../terminal/browser/xterm/xtermTerminal.ts | 6 +-- .../test/browser/bufferContentTracker.test.ts | 5 +- src/vs/workbench/workbench.web.main.ts | 2 + 13 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 src/vs/platform/accessibility/browser/screenReaderNotificationService.ts create mode 100644 src/vs/platform/audioCues/browser/media/clear.mp3 diff --git a/src/vs/platform/accessibility/browser/accessibilityService.ts b/src/vs/platform/accessibility/browser/accessibilityService.ts index a183dd490c2..409619555ec 100644 --- a/src/vs/platform/accessibility/browser/accessibilityService.ts +++ b/src/vs/platform/accessibility/browser/accessibilityService.ts @@ -7,7 +7,6 @@ import { addDisposableListener } from 'vs/base/browser/dom'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { localize } from 'vs/nls'; import { AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED, IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -27,7 +26,7 @@ export class AccessibilityService extends Disposable implements IAccessibilitySe constructor( @IContextKeyService private readonly _contextKeyService: IContextKeyService, @ILayoutService private readonly _layoutService: ILayoutService, - @IConfigurationService protected readonly _configurationService: IConfigurationService, + @IConfigurationService protected readonly _configurationService: IConfigurationService ) { super(); this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService); @@ -116,9 +115,4 @@ export class AccessibilityService extends Disposable implements IAccessibilitySe alert(message: string): void { alert(message); } - alertCleared(): void { - if (this.isScreenReaderOptimized()) { - alert(localize('cleared', "Cleared")); - } - } } diff --git a/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts b/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts new file mode 100644 index 00000000000..313298b498d --- /dev/null +++ b/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IScreenReaderNotificationService = createDecorator('screenReaderNotificationService'); + +export interface IScreenReaderNotificationService { + notifyCleared(): void; +} + +export class ScreenReaderNotificationService extends Disposable implements IScreenReaderNotificationService { + declare readonly _serviceBrand: undefined; + + constructor(@IAudioCueService private readonly _audioCueService: IAudioCueService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IAccessibilityService private readonly _accessibilityService: IAccessibilityService) { + super(); + } + + notifyCleared(): void { + const audioCueValue = this._configurationService.getValue('audioCues.clear'); + if (audioCueValue === 'on' || audioCueValue === 'auto' && this._accessibilityService.isScreenReaderOptimized()) { + this._audioCueService.playAudioCue(AudioCue.clear); + } else { + alert(localize('cleared', "Cleared")); + } + } +} + +export class TestScreenReaderNotificationService implements IScreenReaderNotificationService { + + declare readonly _serviceBrand: undefined; + + notifyCleared(): void { } +} diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index 84d2f65d24c..f7325c2caa9 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -21,7 +21,6 @@ export interface IAccessibilityService { getAccessibilitySupport(): AccessibilitySupport; setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void; alert(message: string): void; - alertCleared(): void; } export const enum AccessibilitySupport { diff --git a/src/vs/platform/accessibility/test/common/testAccessibilityService.ts b/src/vs/platform/accessibility/test/common/testAccessibilityService.ts index e6a7531f496..b046c6b46da 100644 --- a/src/vs/platform/accessibility/test/common/testAccessibilityService.ts +++ b/src/vs/platform/accessibility/test/common/testAccessibilityService.ts @@ -12,6 +12,7 @@ export class TestAccessibilityService implements IAccessibilityService { onDidChangeScreenReaderOptimized = Event.None; onDidChangeReducedMotion = Event.None; + onDidRequestPlayClearAudioCue = Event.None; isScreenReaderOptimized(): boolean { return false; } isMotionReduced(): boolean { return false; } diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index bbf03de5613..c2b8358898a 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -50,6 +50,7 @@ export class AudioCueService extends Disposable implements IAudioCueService { public async playAudioCue(cue: AudioCue, options: IAudioCueOptions = {}): Promise { if (this.isEnabled(cue)) { + console.log('playing cue', cue.name); this.sendAudioCueTelemetry(cue, options.source); await this.playSound(cue.sound.getSound(), options.allowManyInParallel); } @@ -254,6 +255,7 @@ export class Sound { public static readonly chatResponseReceived2 = Sound.register({ fileName: 'chatResponseReceived2.mp3' }); public static readonly chatResponseReceived3 = Sound.register({ fileName: 'chatResponseReceived3.mp3' }); public static readonly chatResponseReceived4 = Sound.register({ fileName: 'chatResponseReceived4.mp3' }); + public static readonly clear = Sound.register({ fileName: 'clear.mp3' }); private constructor(public readonly fileName: string) { } } @@ -419,6 +421,12 @@ export class AudioCue { settingsKey: 'audioCues.chatResponsePending' }); + public static readonly clear = AudioCue.register({ + name: localize('audioCues.clear', 'Clear'), + sound: Sound.clear, + settingsKey: 'audioCues.clear' + }); + private constructor( public readonly sound: SoundSource, public readonly name: string, diff --git a/src/vs/platform/audioCues/browser/media/clear.mp3 b/src/vs/platform/audioCues/browser/media/clear.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d26fc4ac3c19d352493ada6636998e16557404ab GIT binary patch literal 34816 zcmeI&cTf}E|1a=OA+&%Yp#)F}MWl(L8j27)NN<8t3`n&gAXQo@DhenlB?w4Skg9-6 z6$nk~2%@M6B1J%?C@3IEEO3gTaDIY|C%gIL<$u(9H{SmMq!8);@mJYcEuD1u|fPnNqj zYx%H6u;w;^3_@0Z=ooann8e!7V~w4 zO|jORx4vE|HJBag*&;zW3;$F~<9of! z|NNP))jDS(p^ZubRJv;#|7OFt*CAg5zE9@`CjY<~3kobqaiVVMC6Dt%F&WuR3$#J0 z)-p0j4;ynp_|*C7x|)G<=8=B20J*RlS}OY1LQJICBI`a>;fy-KuySr(q9Jr#(3=gV z9ZJZeeaCsb{NV3zSp|qD<^USc2(zHe4wDhL653DV!(*Tp01<_!2RNlV_EgTS6n2ca zo4CIvaATX8k{5<8Zb-Yx#9E=XSgXI)#%rxDxprcboPR_vOUczAo#G;jdH9bCr>{i# zo)luPjMR#`%w~Z&mTaQOTImooDH;9rvCwm9VoSf|YpLE)mq$nuv&ru3ALV17sZ2P- zL@ve{8nJN)Ny{HYvy|pBEZvcen=D0?P2U#AT;Q!7%JBQ%;`&zNj8kjgskqp9j_Ve``8MWtd6?A&Xo^c-bH&1&N zoy-h~Su(^ynvhL;`;enIO}pB;BeKIt3@`+Qgvgt}orVRre1! z$3{1=o~%_1v45S5FL!i6O#8-9C+wA0k9@+%9}VLWVQhJNrC*6>0F9ZQ<@O(qdysNE zWtRI~QIdm|kL#I~wwSka^r@QH6`np!57L&Ngt8kpxwuRPOKZM^_g}|1T2(0dhz#i* zfzPSKdC@|oi@Fw>Tq1U#rDOON-2%*^kPa$ygUH zT=h=8Vwj8AyNBUQDsgH|FE5pZFKB#yV6XX_BtStRu_U$3jd9AR21S7x$FY^vXexQt zKy@o~&tvXK!R3?3Z;sqF9P6I<@|&rD^L<%I^UKQQ@q78{+-qD@F0vu_KhpLGFRuo7 z^h~Q9>OJz@t*(R;d3S;%f2C6DQ95&a^1>&D>EoMSA(_q&!9ngpX`Ul<56rE5H_W6* zWjATlEyLj>=TnAW*So$ssk&NKuo(WKa-k}0F}0$t-#tl#MB+imijx8*olFNp!gM?$ zppMnTSa@ac@UghATv1Rd{ydYh7kQ4r36VC zpTCGHYJaHyaF*`L^4;7dFDLuHefJ^VH;ZbSM6Sef@Z;8ps$?GUh#$z|;b)O~U+n2q z&_*X4C3(j@wEIIeQ$R@ zmzQZPS@r%4g&CN;gDeDK#j7z|2s(#Kuft?vV+?cZIUu@01g_?JdFn*>(JAvfJIHi4QBXqp~&+vI>(A1!NqfJy#ktS`N;6 zs=wa2@xF0$t*`tl-OGVdSbh7}#)eYv+Y`eso{BWurM+r>Bev?IV+>dzk~@N!hFw2Y zeuZp-<%sYg6A=JCz702FDzzH-fzk%a_p_LBxAjjjK28rAH92|r-ppEA7X8+G)(zs? z$O|5u&4%I8`7PyD4r&y)i0)VE#OhB~vbcta{_oB%UqimEl6^k&RH1NaQ#tMucioTO zL#6d+XU?8^cW<@vd@Y#_6M#f8h*IFpkhB#OYzV@PT)mqD0TSSlBP=#NSe(Gs*eZwY zo)6}{celP9FPs>+o1+}gP*pgB66v*ZN&RBIj_lkcFJ$B9b0dT!I-|Ss=oZV!==rao z8O1d&Lg~oS&1ivm&9)*M}N34soB{1xYr{hikyIA z*2w-u(o(z2>3ffq#4m))P=bjuXaVGN$lSHI{pxgui6>;cYIkLu)&4j<&6^@xoTla* z!MLmb(5@d{?X@51LYlRHMvh2^TS~UVdU%{-JO~LvCmhW7+(7SQKhrdQ zB{yO=Zp=xv?ugs>`OQXZ0Rt8SQ6%drV1-!=+cWejKJ<*_7(oWI5!tlpL!>-xH9Ytv z=eXEH$>w5RgNcmt#zkvZnSzhHLdJzbC4uWcEopPFEVR@P_-(nk(2RXt6N6-XU3MqK zzZVPC?|ZU470tKWaB8ZA$HvM}Zr}c3&c&gHEvH7pF+cvo#*Ob~)&ZC19=mB&lO!Re zXCeU1BSH+um!SOlVzmPn3VAKc$Us%W(+$BgamEHug7Y!vf;=8S~@W(-y&Ga!}7fq-4=D0ekF;|oT;WzVm6V)fE1w@DhtZada~P*NZO4M z#3Na&F@Xi~xzDQ6$7)|G8omrPsS(He3ELMb+nkKSqLdU{WeIi<< zvczkz2TsQP!O}AM1^V3hQpF7eFBQ9^?U{tzy&hz8w)-=pi{1rdm#@9KE@W(NMHHIj z=$dYHFpY)F@O!|;jlv>7H17-BN4Nw40stJ42N1vse{?Tqi`@#JNB00q+Kp!fWP#{U zwIl5;Dph@jv_8QeeZ!2cV9}T-DDR(D1LZ;XYAs$IJxt?>L7P42C z-}4O}qn+rKz27+~M#VzMP*?_lhr*6y$0|h#^EkALVr7X|6jU}R7D0xl^L+7J>9w+V z6r)vsp;6GM@(pemTfMmV$wvCU;J(2D6O;$J!1zGkn5B`tdoYgvv3t@+uG^j2tq*(b zY@O$H<#h{h2R^>fEhou)ym~>>J8SWcj>wiJRRVZMb%#h&=Yj0z3|8{6v5aYRAS`3W zB;K8U(7KbQ-`mjHsSV@RT>LsV|3W|%O!o7)kv;*78MBk`42)M=hC=t=@2ayAqpH4K z9A~r}`TT^jYm{+hna^wMkY;F}m$gZ;rP+{!z*L~a)~wG)iDuPJT9=5YTZqSjwXoHZ z(2?oEMp}5tscbxw9E+!mz~T2czs75$y73PO((xscK6pYC2G0*rRY#0e&gl`lE+8He z-$+p8`5Y>LytGmEnAaTE*Lm1jy(j+1RRwFaIDJKSIKP_Ll}cQ^TBGJV&BWG<_Zx)g ztNLnAurymQp?jZ7K1?_+XI z$W`BD5j%cj*Lu{NJ6)#J)9Yr5odfR5`hY0pD49g39udiYH1hEoNNp{fcVr4Yk&J{E zl11U(WAPO1VMzCGd!pD6cgdr}71c>K9SHu9d4*kP%13PY-DN~m+IwzXCsekVNv$X} z+7}%T&W#_77kR!Ev~1)%-;gdcWV2AeckN^1M$z?R|Fb6Fzh?0ds=Zr0`7W=9*7N0I zul4GWhDJGK8ZEbOF>HP-lFUn?C%R&JbD}7smppd|JKn;|kc_Y}Kqdn4qK7*`0K+<0 z`D^*IIuE%&E!@6#z=K~m^*~KuI}TDj@TfGX(DUTEj*~L% z`EpZks0h z_Q$H%YbDirGUB@|M&2>R9)|| zfmvzyxkm}kU(89e5qcyks1He*>61Ik$l1d!#*1__;tk0Wh$9`3C}V+8slq@EJH?=6 zpjcGrZsW_SIj-9EE~gt@jR8_UU5nilkti}98@lD>VE@=TSs16gAQ7g)5Rm_Aw!fd< zJ?#s^!O~lIe+QqHkp>{{qy4(z&9gD|ugLX@Ys1!MNU7R-+2KNlXq#d*$0`|0$0iur zumr>i+f5j74O!l}rBd9)RkL`%OF$DoU@AUCmbTz9LdqHBxPWW zqy!|8jslOBpk)cnA`l!9nGJB6<0CY(A;o4z&g!n>&rDy;rxwGITwCs8905kd3Tt2A z^{N=Oek;8lxa3zo0eQivFO1MG)a#eH5k8lzkF+@TsN3YoJnu)9sW(rKPKFoClegCy z1xU|dIt6pzUdU=hET(Q(krWg!Bh4MS=q3fF)E9l8Zk;eTiZ)NR4NIpsDd0XTW79IOd@n z5s5~e4txqpXJyfpt}Q)xM=a9iP7lxlM>G*nKv@!`0T_;K`Uuxm)SiZOz5G=;2w#_U+ss<`-+yZ%Nn4jwU&Qp3nrFFaj}kUC?V)IsehhRoPC^%;RS>0H92-IG#c%>wjA1dsPKk86Kz>59@~GzdE~5-UMLMFd@C|<8*`9l5(DGorH+Or z0&nTyV@@bhWIDOWd9sgjCIg0{iy%k&UT%#D+-3LLwmm1Xur9YsuR)77{hhgFsmF7x z=i&7jt%U5l;L1|r*R#*&wyrG{-Rq)R5B)ghPovGzXj`NAhiF^(w~vHoz5Rz5WQ4Kz zTjI@lVS5I!GQ7MekmbxWwMH10gh_l7!wm>Z5l@1ggO2US1CS^>R06&WDa4py$_iDO zi7C;FA!lD0bd%vd$iBy;_rbSzTZe)oz=|y*sI6K(u?l8qddIRfmgIqj>vm07#a9?8#p;QFobw#o7jgCh6ATKiL+@5-laJ)LFRhVRqvgvi-+xxu9^#~hzcL$bpwU*M+GRL-(g>Aq zlZ=$>q&EGnTOYy>P%?d{(uVIN126`egkcwbih^u*KpZ;k3GKwmAS`wA2IG zg9;E%R5^0>gg`edoRF&nhe|Psiev1qpL8#F$9q2u2Oqy1TpCEqQmwdq8 zM_@S#9m1g=?a-mWpJ4iu`=F#6#+1}?rnlWv<)EB){L8*( zCs!C{0%JK4)QNrt&vU-sjnIAN8_F14DizG7(#}RiMZ0xq$b5$1q#Ra_p6Muu`yF6t z@60#L6E0LjXDO=Ibj%}@Wt_g1+G^(M8=kOrc+^lFn(8GkhPTny)+V`&V>HU;IN8ih zZFrayb8N0NMq65nAlkINj)+`vw&Y|}FSp@k#%NR!I58)j%DfarE;w0oVw}dy6vQ|u zYFKmLXhpea9MpbxMSAUX!_B&~r0Pw99@y$*4to&CLhRjHUeC?yS8bD(*&@r94m zr7^Q#s{&LX+WXbc#3cBN_y#f*B&*T*@XB~MX*o2V6@S{P6?BSuAa2~LKoaqhS7s=1 zuViF^qYd^nN4}{GMn)y!F;EV1=Y{q7_UR2?6;+K#?*dYm0uWGj zXVfU`AsiqTG2Ha@&h}l&KfNha6LGjZYX;0J)P5Z4&Kli?=yK;KF=qNEhbA%DKV9el za{WIemrn-tU`nb z?-<=e{?kGJC+q(eIWb68ln?-=BPuLypM!}c#3&LD04(I;CNlYdQvN^Wy8@Nmm2f*Y zum6zc{J&ksugIYw2P4J+01AjKscat*0X_;N0{}gcP6e5_J&+fzh}#>m{W}DHMUD}u zB4=;^o{i&NV&5){f{p^@p9!?3qPB9`=VB~%m0mnNm07h3xJXPT?8EOumBjj9R>!=|1JPV?spMzyu$)u z+DQR0ayzLD*8YP47`Z>7fKxju07h;nb-~(y5C9|h e2NZB>Ck4RB?W8VP`ws%(6PkZO0jG9Q;C}&N=YUTD literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 81db01babb9..f143d82676f 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -131,8 +131,12 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'description': localize('audioCues.chatResponseReceived', "Plays a sound on loop while the response has been received."), ...audioCueFeatureBase, default: 'off' - } - } + }, + 'audioCues.clear': { + 'description': localize('audioCues.clear', "Plays a sound when a feature is cleared (for example, the terminal, debug console, or output channel)."), + ...audioCueFeatureBase, + default: 'off' + }, + }, }); - registerAction2(ShowAudioCueHelp); diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts index 753e8b54ffc..fae300e585a 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts @@ -18,7 +18,7 @@ import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput'; import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane'; import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; export const ACTION_ID_CLEAR_CHAT = `workbench.action.chat.clear`; @@ -118,5 +118,5 @@ export function getClearAction(viewId: string, providerId: string) { } function announceChatCleared(accessor: ServicesAccessor): void { - accessor.get(IAccessibilityService).alertCleared(); + accessor.get(IScreenReaderNotificationService).notifyCleared(); } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 3966e663acc..ddaba69cd63 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -69,7 +69,7 @@ import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; import { ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { registerNavigableContainer } from 'vs/workbench/browser/actions/widgetNavigationCommands'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; const $ = dom.$; @@ -976,9 +976,9 @@ registerAction2(class extends ViewAction { } runInView(_accessor: ServicesAccessor, view: Repl): void { - const accessibilityService = _accessor.get(IAccessibilityService); + const screenReaderNotificationService = _accessor.get(IScreenReaderNotificationService); view.clearRepl(); - accessibilityService.alertCleared(); + screenReaderNotificationService.notifyCleared(); } }); diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index d31903060bc..263242b1696 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -28,7 +28,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; // Register Service registerSingleton(IOutputService, OutputService, InstantiationType.Delayed); @@ -221,11 +221,11 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { } async run(accessor: ServicesAccessor): Promise { const outputService = accessor.get(IOutputService); - const accesibilityService = accessor.get(IAccessibilityService); + const screenReaderNotificationService = accessor.get(IScreenReaderNotificationService); const activeChannel = outputService.getActiveChannel(); if (activeChannel) { activeChannel.clear(); - accesibilityService.alertCleared(); + screenReaderNotificationService.notifyCleared(); } } })); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 81cdc6320db..6c232cc5343 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -43,7 +43,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { debounce } from 'vs/base/common/decorators'; import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; const enum RenderConstants { /** @@ -204,7 +204,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach @ITelemetryService private readonly _telemetryService: ITelemetryService, @IClipboardService private readonly _clipboardService: IClipboardService, @IContextKeyService contextKeyService: IContextKeyService, - @IAccessibilityService private readonly _accessibilityService: IAccessibilityService + @IScreenReaderNotificationService private readonly _screenReaderNotificationService: IScreenReaderNotificationService ) { super(); const font = this._configHelper.getFont(undefined, true); @@ -590,7 +590,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach // the prompt being written this._capabilities.get(TerminalCapability.CommandDetection)?.handlePromptStart(); this._capabilities.get(TerminalCapability.CommandDetection)?.handleCommandStart(); - this._accessibilityService.alertCleared(); + this._screenReaderNotificationService.notifyCleared(); } hasSelection(): boolean { diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index 4a4ba9498e1..ef94a0c761e 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -7,8 +7,7 @@ import * as assert from 'assert'; import { importAMDNodeModule } from 'vs/amdX'; import { isWindows } from 'vs/base/common/platform'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { TestAccessibilityService } from 'vs/platform/accessibility/test/common/testAccessibilityService'; +import { IScreenReaderNotificationService, TestScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -67,7 +66,7 @@ suite('Buffer Content Tracker', () => { instantiationService.stub(IContextMenuService, store.add(instantiationService.createInstance(ContextMenuService))); instantiationService.stub(ILifecycleService, store.add(new TestLifecycleService())); instantiationService.stub(IContextKeyService, store.add(new MockContextKeyService())); - instantiationService.stub(IAccessibilityService, new TestAccessibilityService()); + instantiationService.stub(IScreenReaderNotificationService, new TestScreenReaderNotificationService()); configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper)); capabilities = store.add(new TerminalCapabilityStore()); if (!isWindows) { diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index c61a78d6fc1..a01f5755cc0 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -93,6 +93,7 @@ import { WebLanguagePacksService } from 'vs/platform/languagePacks/browser/langu registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, InstantiationType.Delayed); registerSingleton(IAccessibilityService, AccessibilityService, InstantiationType.Delayed); +registerSingleton(IScreenReaderNotificationService, ScreenReaderNotificationService, InstantiationType.Delayed); registerSingleton(IContextMenuService, ContextMenuService, InstantiationType.Delayed); registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService, InstantiationType.Delayed); registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, InstantiationType.Delayed); @@ -181,6 +182,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { IScreenReaderNotificationService, ScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; export { From 8de0cf79d2a9ab39f38cdafc91af8d29ca3d49d5 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 12 Oct 2023 13:24:36 -0700 Subject: [PATCH 046/290] Update distro (#195516) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e5e939d40dc..6ec7ad15b97 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.84.0", - "distro": "23fd0c979db23b5d166dea2195bfb3aa5fe1f390", + "distro": "ca54f82b1adb64bbf5601501cc4edef8043f045c", "author": { "name": "Microsoft Corporation" }, From 9d32835bd7b2facd133f63287c10910b294a26d8 Mon Sep 17 00:00:00 2001 From: Isidor Nikolic Date: Thu, 12 Oct 2023 20:47:40 +0000 Subject: [PATCH 047/290] add sqm id for windows (#195377) * add sqm id for windows * Update src/vs/platform/windows/electron-main/windowsMainService.ts * Update src/vs/platform/sharedProcess/node/sharedProcess.ts * react on review comments * The reg entry is called MachineId not MachineGuid * fix compile error * no need for \\ prefix in reg path * Wait for 1s max (as to not block the startup) to read the SQM value --------- Co-authored-by: Benjamin Pasero --- src/vs/base/node/id.ts | 19 +++++++++++++++++ src/vs/base/test/node/id.test.ts | 9 +++++++- src/vs/code/electron-main/app.ts | 21 +++++++++++-------- src/vs/code/node/cliProcessMain.ts | 5 +++-- .../node/sharedProcess/sharedProcessMain.ts | 2 +- .../electron-main/sharedProcess.ts | 2 ++ .../sharedProcess/node/sharedProcess.ts | 2 ++ .../telemetry/common/commonProperties.ts | 3 +++ src/vs/platform/telemetry/common/telemetry.ts | 1 + .../telemetry/electron-main/telemetryUtils.ts | 12 ++++++++--- .../platform/telemetry/node/telemetryUtils.ts | 15 ++++++++++--- src/vs/platform/window/common/window.ts | 1 + .../electron-main/windowsMainService.ts | 2 ++ src/vs/server/node/serverServices.ts | 9 ++++---- .../electron-sandbox/environmentService.ts | 4 ++++ .../common/workbenchCommonProperties.ts | 3 ++- .../electron-sandbox/telemetryService.ts | 2 +- .../test/node/commonProperties.test.ts | 6 +++--- .../workingCopyBackupService.test.ts | 1 + 19 files changed, 91 insertions(+), 28 deletions(-) diff --git a/src/vs/base/node/id.ts b/src/vs/base/node/id.ts index a5ea6a2bb0d..5bbbbd75f9a 100644 --- a/src/vs/base/node/id.ts +++ b/src/vs/base/node/id.ts @@ -7,6 +7,7 @@ import { networkInterfaces } from 'os'; import { TernarySearchTree } from 'vs/base/common/ternarySearchTree'; import * as uuid from 'vs/base/common/uuid'; import { getMac } from 'vs/base/node/macAddress'; +import { isWindows } from 'vs/base/common/platform'; // http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/ // VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69 @@ -99,3 +100,21 @@ async function getMacMachineId(errorLogger: (error: any) => void): Promise void): Promise { + if (isWindows) { + const Registry = await import('@vscode/windows-registry'); + try { + // Wait for 1s max (as to not block the startup) to read the SQM value + return await Promise.race([ + Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', SQM_KEY, 'MachineId') || '', + new Promise(resolve => setTimeout(() => resolve(''), 1000)) + ]); + } catch (err) { + errorLogger(err); + return ''; + } + } + return ''; +} diff --git a/src/vs/base/test/node/id.test.ts b/src/vs/base/test/node/id.test.ts index ed4b0d0cb2f..bdec456edde 100644 --- a/src/vs/base/test/node/id.test.ts +++ b/src/vs/base/test/node/id.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { getMachineId } from 'vs/base/node/id'; +import { getMachineId, getSqmMachineId } from 'vs/base/node/id'; import { getMac } from 'vs/base/node/macAddress'; import { flakySuite } from 'vs/base/test/node/testUtils'; @@ -17,6 +17,13 @@ flakySuite('ID', () => { assert.strictEqual(errors.length, 0); }); + test('getSqmId', async function () { + const errors = []; + const id = await getSqmMachineId(err => errors.push(err)); + assert.ok(typeof id === 'string'); + assert.strictEqual(errors.length, 0); + }); + test('getMac', async () => { const macAddress = getMac(); assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index f687d93c9c0..fb758311a1a 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -105,7 +105,7 @@ import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/e import { UserDataProfilesHandler } from 'vs/platform/userDataProfile/electron-main/userDataProfilesHandler'; import { ProfileStorageChangesListenerChannel } from 'vs/platform/userDataProfile/electron-main/userDataProfileStorageIpc'; import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; -import { resolveMachineId } from 'vs/platform/telemetry/electron-main/telemetryUtils'; +import { resolveMachineId, resolveSqmId } from 'vs/platform/telemetry/electron-main/telemetryUtils'; import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/node/extensionsProfileScannerService'; import { LoggerChannel } from 'vs/platform/log/electron-main/logIpc'; import { ILoggerMainService } from 'vs/platform/log/electron-main/loggerService'; @@ -596,14 +596,17 @@ export class CodeApplication extends Disposable { // Resolve unique machine ID this.logService.trace('Resolving machine identifier...'); - const machineId = await resolveMachineId(this.stateService, this.logService); + const [machineId, sqmId] = await Promise.all([ + resolveMachineId(this.stateService, this.logService), + resolveSqmId(this.stateService, this.logService) + ]); this.logService.trace(`Resolved machine identifier: ${machineId}`); // Shared process - const { sharedProcessReady, sharedProcessClient } = this.setupSharedProcess(machineId); + const { sharedProcessReady, sharedProcessClient } = this.setupSharedProcess(machineId, sqmId); // Services - const appInstantiationService = await this.initServices(machineId, sharedProcessReady); + const appInstantiationService = await this.initServices(machineId, sqmId, sharedProcessReady); // Auth Handler this._register(appInstantiationService.createInstance(ProxyAuthHandler)); @@ -956,8 +959,8 @@ export class CodeApplication extends Disposable { return false; } - private setupSharedProcess(machineId: string): { sharedProcessReady: Promise; sharedProcessClient: Promise } { - const sharedProcess = this._register(this.mainInstantiationService.createInstance(SharedProcess, machineId)); + private setupSharedProcess(machineId: string, sqmId: string): { sharedProcessReady: Promise; sharedProcessClient: Promise } { + const sharedProcess = this._register(this.mainInstantiationService.createInstance(SharedProcess, machineId, sqmId)); const sharedProcessClient = (async () => { this.logService.trace('Main->SharedProcess#connect'); @@ -978,7 +981,7 @@ export class CodeApplication extends Disposable { return { sharedProcessReady, sharedProcessClient }; } - private async initServices(machineId: string, sharedProcessReady: Promise): Promise { + private async initServices(machineId: string, sqmId: string, sharedProcessReady: Promise): Promise { const services = new ServiceCollection(); // Update @@ -1001,7 +1004,7 @@ export class CodeApplication extends Disposable { } // Windows - services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, this.userEnv], false)); + services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, sqmId, this.userEnv], false)); services.set(IAuxiliaryWindowsMainService, new SyncDescriptor(AuxiliaryWindowsMainService, undefined, false)); // Dialogs @@ -1081,7 +1084,7 @@ export class CodeApplication extends Disposable { const isInternal = isInternalTelemetry(this.productService, this.configurationService); const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender'))); const appender = new TelemetryAppenderClient(channel); - const commonProperties = resolveCommonProperties(release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal); + const commonProperties = resolveCommonProperties(release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, sqmId, isInternal); const piiPaths = getPiiPathsFromEnvironment(this.environmentMainService); const config: ITelemetryServiceConfig = { appenders: [appender], commonProperties, piiPaths, sendErrorTelemetry: true }; diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 85daa51a6e1..b2861976c11 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -57,7 +57,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { UserDataProfilesReadonlyService } from 'vs/platform/userDataProfile/node/userDataProfile'; -import { resolveMachineId } from 'vs/platform/telemetry/node/telemetryUtils'; +import { resolveMachineId, resolveSqmId } from 'vs/platform/telemetry/node/telemetryUtils'; import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/node/extensionsProfileScannerService'; import { LogService } from 'vs/platform/log/common/logService'; import { LoggerService } from 'vs/platform/log/node/loggerService'; @@ -184,6 +184,7 @@ class CliMain extends Disposable { logService.error(error); } } + const sqmId = await resolveSqmId(stateService, logService); // Initialize user data profiles after initializing the state userDataProfilesService.init(); @@ -219,7 +220,7 @@ class CliMain extends Disposable { const config: ITelemetryServiceConfig = { appenders, sendErrorTelemetry: false, - commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, machineId, isInternal), + commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, machineId, sqmId, isInternal), piiPaths: getPiiPathsFromEnvironment(environmentService) }; diff --git a/src/vs/code/node/sharedProcess/sharedProcessMain.ts b/src/vs/code/node/sharedProcess/sharedProcessMain.ts index 6a26fb9ad17..557f8b6a6fe 100644 --- a/src/vs/code/node/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/node/sharedProcess/sharedProcessMain.ts @@ -303,7 +303,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { telemetryService = new TelemetryService({ appenders, - commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, internalTelemetry), + commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, this.configuration.sqmId, internalTelemetry), sendErrorTelemetry: true, piiPaths: getPiiPathsFromEnvironment(environmentService), }, configurationService, productService); diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 70059e1d7fc..7372f366459 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -29,6 +29,7 @@ export class SharedProcess extends Disposable { constructor( private readonly machineId: string, + private readonly sqmId: string, @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @@ -172,6 +173,7 @@ export class SharedProcess extends Disposable { private createSharedProcessConfiguration(): ISharedProcessConfiguration { return { machineId: this.machineId, + sqmId: this.sqmId, codeCachePath: this.environmentMainService.codeCachePath, profiles: { home: this.userDataProfilesService.profilesHome, diff --git a/src/vs/platform/sharedProcess/node/sharedProcess.ts b/src/vs/platform/sharedProcess/node/sharedProcess.ts index efdde2ec7c5..f93082d7a2d 100644 --- a/src/vs/platform/sharedProcess/node/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/node/sharedProcess.ts @@ -13,6 +13,8 @@ import { UriComponents, UriDto } from 'vs/base/common/uri'; export interface ISharedProcessConfiguration { readonly machineId: string; + readonly sqmId: string; + readonly codeCachePath: string | undefined; readonly args: NativeParsedArgs; diff --git a/src/vs/platform/telemetry/common/commonProperties.ts b/src/vs/platform/telemetry/common/commonProperties.ts index 7ee1e0b7705..587bf334463 100644 --- a/src/vs/platform/telemetry/common/commonProperties.ts +++ b/src/vs/platform/telemetry/common/commonProperties.ts @@ -23,6 +23,7 @@ export function resolveCommonProperties( commit: string | undefined, version: string | undefined, machineId: string | undefined, + sqmId: string | undefined, isInternalTelemetry: boolean, product?: string ): ICommonProperties { @@ -30,6 +31,8 @@ export function resolveCommonProperties( // __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } result['common.machineId'] = machineId; + // __GDPR__COMMON__ "common.sqmId" : { "endPoint": "SQMMachineId", "classification": "EndUserPseudonymizedInformation", "purpose": "BusinessInsight" } + result['common.sqmId'] = sqmId; // __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['sessionID'] = generateUuid() + Date.now(); // __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } diff --git a/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts index f19c01188ee..3c48ecfaf0d 100644 --- a/src/vs/platform/telemetry/common/telemetry.ts +++ b/src/vs/platform/telemetry/common/telemetry.ts @@ -71,6 +71,7 @@ export const currentSessionDateStorageKey = 'telemetry.currentSessionDate'; export const firstSessionDateStorageKey = 'telemetry.firstSessionDate'; export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; export const machineIdKey = 'telemetry.machineId'; +export const sqmIdKey = 'telemetry.sqmId'; // Configuration Keys export const TELEMETRY_SECTION_ID = 'telemetry'; diff --git a/src/vs/platform/telemetry/electron-main/telemetryUtils.ts b/src/vs/platform/telemetry/electron-main/telemetryUtils.ts index db3bb1bcd8b..6dc9a9fa9d6 100644 --- a/src/vs/platform/telemetry/electron-main/telemetryUtils.ts +++ b/src/vs/platform/telemetry/electron-main/telemetryUtils.ts @@ -5,12 +5,18 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IStateService } from 'vs/platform/state/node/state'; -import { machineIdKey } from 'vs/platform/telemetry/common/telemetry'; -import { resolveMachineId as resolveNodeMachineId } from 'vs/platform/telemetry/node/telemetryUtils'; +import { machineIdKey, sqmIdKey } from 'vs/platform/telemetry/common/telemetry'; +import { resolveMachineId as resolveNodeMachineId, resolveSqmId as resolveNodeSqmId } from 'vs/platform/telemetry/node/telemetryUtils'; -export async function resolveMachineId(stateService: IStateService, logService: ILogService) { +export async function resolveMachineId(stateService: IStateService, logService: ILogService): Promise { // Call the node layers implementation to avoid code duplication const machineId = await resolveNodeMachineId(stateService, logService); stateService.setItem(machineIdKey, machineId); return machineId; } + +export async function resolveSqmId(stateService: IStateService, logService: ILogService): Promise { + const sqmId = await resolveNodeSqmId(stateService, logService); + stateService.setItem(sqmIdKey, sqmId); + return sqmId; +} diff --git a/src/vs/platform/telemetry/node/telemetryUtils.ts b/src/vs/platform/telemetry/node/telemetryUtils.ts index 4e970ce6afa..cb5a03fd687 100644 --- a/src/vs/platform/telemetry/node/telemetryUtils.ts +++ b/src/vs/platform/telemetry/node/telemetryUtils.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { isMacintosh } from 'vs/base/common/platform'; -import { getMachineId } from 'vs/base/node/id'; +import { getMachineId, getSqmMachineId } from 'vs/base/node/id'; import { ILogService } from 'vs/platform/log/common/log'; import { IStateReadService } from 'vs/platform/state/node/state'; -import { machineIdKey } from 'vs/platform/telemetry/common/telemetry'; +import { machineIdKey, sqmIdKey } from 'vs/platform/telemetry/common/telemetry'; -export async function resolveMachineId(stateService: IStateReadService, logService: ILogService) { +export async function resolveMachineId(stateService: IStateReadService, logService: ILogService): Promise { // We cache the machineId for faster lookups // and resolve it only once initially if not cached or we need to replace the macOS iBridge device let machineId = stateService.getItem(machineIdKey); @@ -20,3 +20,12 @@ export async function resolveMachineId(stateService: IStateReadService, logServi return machineId; } + +export async function resolveSqmId(stateService: IStateReadService, logService: ILogService): Promise { + let sqmId = stateService.getItem(sqmIdKey); + if (typeof sqmId !== 'string') { + sqmId = await getSqmMachineId(logService.error.bind(logService)); + } + + return sqmId; +} diff --git a/src/vs/platform/window/common/window.ts b/src/vs/platform/window/common/window.ts index 6cec55dc373..5762b3c380b 100644 --- a/src/vs/platform/window/common/window.ts +++ b/src/vs/platform/window/common/window.ts @@ -280,6 +280,7 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native mainPid: number; machineId: string; + sqmId: string; execPath: string; backupPath?: string; diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index aa19814554e..8a3e4b35ae1 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -199,6 +199,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic constructor( private readonly machineId: string, + private readonly sqmId: string, private readonly initialUserEnv: IProcessEnvironment, @ILogService private readonly logService: ILogService, @ILoggerMainService private readonly loggerService: ILoggerMainService, @@ -1381,6 +1382,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic ...options.cli, machineId: this.machineId, + sqmId: this.sqmId, windowId: -1, // Will be filled in by the window once loaded later diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 9db61e83f34..019b7d3768a 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -9,7 +9,7 @@ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import * as path from 'vs/base/common/path'; import { IURITransformer } from 'vs/base/common/uriIpc'; -import { getMachineId } from 'vs/base/node/id'; +import { getMachineId, getSqmMachineId } from 'vs/base/node/id'; import { Promises } from 'vs/base/node/pfs'; import { ClientConnectionEvent, IMessagePassingProtocol, IPCServer, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import { ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net'; @@ -132,10 +132,11 @@ export async function setupServerServices(connectionToken: ServerConnectionToken socketServer.registerChannel('userDataProfiles', new RemoteUserDataProfilesServiceChannel(userDataProfilesService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority))); // Initialize - const [, , machineId] = await Promise.all([ + const [, , machineId, sqmId] = await Promise.all([ configurationService.initialize(), userDataProfilesService.init(), - getMachineId(logService.error.bind(logService)) + getMachineId(logService.error.bind(logService)), + getSqmMachineId(logService.error.bind(logService)) ]); const extensionHostStatusService = new ExtensionHostStatusService(); @@ -155,7 +156,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken const config: ITelemetryServiceConfig = { appenders: [oneDsAppender], - commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, isInternal, 'remoteAgent'), + commonProperties: resolveCommonProperties(release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, sqmId, isInternal, 'remoteAgent'), piiPaths: getPiiPathsFromEnvironment(environmentService) }; const initialTelemetryLevelArg = environmentService.args['telemetry-level']; diff --git a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts index 26fedfa0219..ff7ca909d1c 100644 --- a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts @@ -38,6 +38,7 @@ export interface INativeWorkbenchEnvironmentService extends IBrowserWorkbenchEnv readonly mainPid: number; readonly os: IOSConfiguration; readonly machineId: string; + readonly sqmId: string; // --- Paths readonly execPath: string; @@ -59,6 +60,9 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment @memoize get machineId() { return this.configuration.machineId; } + @memoize + get sqmId() { return this.configuration.sqmId; } + @memoize get remoteAuthority() { return this.configuration.remoteAuthority; } diff --git a/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts b/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts index 9f2cc7a3196..18d92118512 100644 --- a/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts +++ b/src/vs/workbench/services/telemetry/common/workbenchCommonProperties.ts @@ -16,11 +16,12 @@ export function resolveWorkbenchCommonProperties( commit: string | undefined, version: string | undefined, machineId: string, + sqmId: string, isInternalTelemetry: boolean, process: INodeProcess, remoteAuthority?: string ): ICommonProperties { - const result = resolveCommonProperties(release, hostname, process.arch, commit, version, machineId, isInternalTelemetry); + const result = resolveCommonProperties(release, hostname, process.arch, commit, version, machineId, sqmId, isInternalTelemetry); const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.APPLICATION)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.APPLICATION)!; diff --git a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts index d5da21a8d28..84207e13089 100644 --- a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts @@ -44,7 +44,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { const channel = sharedProcessService.getChannel('telemetryAppender'); const config: ITelemetryServiceConfig = { appenders: [new TelemetryAppenderClient(channel)], - commonProperties: resolveWorkbenchCommonProperties(storageService, environmentService.os.release, environmentService.os.hostname, productService.commit, productService.version, environmentService.machineId, isInternal, process, environmentService.remoteAuthority), + commonProperties: resolveWorkbenchCommonProperties(storageService, environmentService.os.release, environmentService.os.hostname, productService.commit, productService.version, environmentService.machineId, environmentService.sqmId, isInternal, process, environmentService.remoteAuthority), piiPaths: getPiiPathsFromEnvironment(environmentService), sendErrorTelemetry: true }; diff --git a/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts b/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts index 8600bd13f15..48159a6c21c 100644 --- a/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts +++ b/src/vs/workbench/services/telemetry/test/node/commonProperties.test.ts @@ -22,7 +22,7 @@ suite('Telemetry - common properties', function () { ensureNoDisposablesAreLeakedInTestSuite(); test('default', function () { - const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', false, process); + const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', 'someSqmId', false, process); assert.ok('commitHash' in props); assert.ok('sessionID' in props); assert.ok('timestamp' in props); @@ -46,14 +46,14 @@ suite('Telemetry - common properties', function () { testStorageService.store('telemetry.lastSessionDate', new Date().toUTCString(), StorageScope.APPLICATION, StorageTarget.MACHINE); - const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', false, process); + const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', 'someSqmId', false, process); assert.ok('common.lastSessionDate' in props); // conditional, see below assert.ok('common.isNewSession' in props); assert.strictEqual(props['common.isNewSession'], '0'); }); test('values chance on ask', async function () { - const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', false, process); + const props = resolveWorkbenchCommonProperties(testStorageService, release(), hostname(), commit, version, 'someMachineId', 'someSqmId', false, process); let value1 = props['common.sequence']; let value2 = props['common.sequence']; assert.ok(value1 !== value2, 'seq'); diff --git a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupService.test.ts b/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupService.test.ts index fe5d207307e..4cbfe873cae 100644 --- a/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/electron-sandbox/workingCopyBackupService.test.ts @@ -55,6 +55,7 @@ const NULL_PROFILE = { const TestNativeWindowConfiguration: INativeWindowConfiguration = { windowId: 0, machineId: 'testMachineId', + sqmId: 'testSqmId', logLevel: LogLevel.Error, loggers: { global: [], window: [] }, mainPid: 0, From 42565ebe6a291d2cb80f279901bd03f3a05e74d3 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 13:57:44 -0700 Subject: [PATCH 048/290] store is disposed --- .../commandDetectionCapability.ts | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 1fb5f28abaf..6de046c8ae0 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -6,7 +6,7 @@ import { Barrier, timeout } from 'vs/base/common/async'; import { debounce } from 'vs/base/common/decorators'; import { Emitter } from 'vs/base/common/event'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { ICommandDetectionCapability, TerminalCapability, ITerminalCommand, IHandleCommandOptions, ICommandInvalidationRequest, CommandInvalidationReason, ISerializedTerminalCommand, ISerializedCommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ITerminalOutputMatch, ITerminalOutputMatcher } from 'vs/platform/terminal/common/terminal'; @@ -377,22 +377,20 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe if (!this._cursorOnNextLine() || !this._cursorLineLooksLikeWindowsPrompt()) { this._windowsPromptPollingInProcess = true; // Poll for 200ms until the cursor position is correct. - this._register(toDisposable(async () => { - let i = 0; - for (; i < 20; i++) { - await timeout(10); - if (!this._windowsPromptPollingInProcess || this._cursorOnNextLine() && this._cursorLineLooksLikeWindowsPrompt()) { - if (!this._windowsPromptPollingInProcess) { - this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling cancelled'); - } - break; + let i = 0; + for (; i < 20; i++) { + await timeout(10); + if (this._store.isDisposed || !this._windowsPromptPollingInProcess || this._cursorOnNextLine() && this._cursorLineLooksLikeWindowsPrompt()) { + if (!this._windowsPromptPollingInProcess) { + this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling cancelled'); } + break; } - this._windowsPromptPollingInProcess = false; - if (i === 20) { - this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); - } - })); + } + this._windowsPromptPollingInProcess = false; + if (i === 20) { + this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._cursorLineLooksLikeWindowsPrompt()); + } } else { // HACK: Fire command started on the following frame on Windows to allow the cursor // position to update as conpty often prints the sequence on a different line to the From 428dd5d9bb7be4aa030ade329815c1b152ecd21f Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 14:03:02 -0700 Subject: [PATCH 049/290] add space --- .../common/capabilities/commandDetectionCapability.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index fd8ff6d4d65..0b3073cad3e 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -394,7 +394,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows reached max attempts, ', this._cursorOnNextLine(), this._getWindowsPrompt()); } else if (prompt) { // use the regex to set the position as it's possible input has occurred - this._currentCommand.commandStartX = prompt.length + 1; + this._currentCommand.commandStartX = prompt.length; } } else { // HACK: Fire command started on the following frame on Windows to allow the cursor @@ -443,7 +443,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe return; } // TODO: fine tune prompt regex to accomodate for unique configurtions. - return line.translateToString(true)?.match(/^(?(?:PS.+>)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; + return line.translateToString(true)?.match(/^(?(?:PS.+>\s)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; } handleGenericCommand(options?: IHandleCommandOptions): void { From 855f4226520adca3dba23b63048ad13513a65402 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 12 Oct 2023 14:05:00 -0700 Subject: [PATCH 050/290] Update src/vs/platform/audioCues/browser/audioCueService.ts --- src/vs/platform/audioCues/browser/audioCueService.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index c2b8358898a..e71162ab665 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -50,7 +50,6 @@ export class AudioCueService extends Disposable implements IAudioCueService { public async playAudioCue(cue: AudioCue, options: IAudioCueOptions = {}): Promise { if (this.isEnabled(cue)) { - console.log('playing cue', cue.name); this.sendAudioCueTelemetry(cue, options.source); await this.playSound(cue.sound.getSound(), options.allowManyInParallel); } From 819b0404e00d1f3a2afb0ca7a25a5b0aa3d0738a Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 14:08:59 -0700 Subject: [PATCH 051/290] fix issue --- .../browser/screenReaderNotificationService.ts | 9 +-------- src/vs/platform/accessibility/common/accessibility.ts | 7 +++++++ .../contrib/terminal/browser/xterm/xtermTerminal.ts | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts b/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts index 313298b498d..c27442afde9 100644 --- a/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts +++ b/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts @@ -5,16 +5,9 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibilityService, IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -export const IScreenReaderNotificationService = createDecorator('screenReaderNotificationService'); - -export interface IScreenReaderNotificationService { - notifyCleared(): void; -} export class ScreenReaderNotificationService extends Disposable implements IScreenReaderNotificationService { declare readonly _serviceBrand: undefined; diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index f7325c2caa9..849b900feb9 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -46,3 +46,10 @@ export function isAccessibilityInformation(obj: any): obj is IAccessibilityInfor && typeof obj.label === 'string' && (typeof obj.role === 'undefined' || typeof obj.role === 'string'); } + +export interface IScreenReaderNotificationService { + readonly _serviceBrand: undefined; + notifyCleared(): void; +} + +export const IScreenReaderNotificationService = createDecorator('screenReaderNotificationService'); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 6c232cc5343..61668047a6b 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -43,7 +43,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { debounce } from 'vs/base/common/decorators'; import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; const enum RenderConstants { /** From e8578d572421c12a8a0009aed56bc40dd335b93c Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 14:12:32 -0700 Subject: [PATCH 052/290] fix issue --- .../contrib/chat/browser/actions/chatClearActions.ts | 2 +- src/vs/workbench/contrib/debug/browser/repl.ts | 2 +- .../workbench/contrib/output/browser/output.contribution.ts | 2 +- .../accessibility/test/browser/bufferContentTracker.test.ts | 3 ++- src/vs/workbench/workbench.web.main.ts | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts index fae300e585a..fc4e0578068 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts @@ -7,6 +7,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { Action2, IAction2Options, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -18,7 +19,6 @@ import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput'; import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane'; import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; export const ACTION_ID_CLEAR_CHAT = `workbench.action.chat.clear`; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index ddaba69cd63..9884467de8e 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -69,7 +69,7 @@ import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; import { ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { registerNavigableContainer } from 'vs/workbench/browser/actions/widgetNavigationCommands'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; const $ = dom.$; diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 263242b1696..19a3e04b12c 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -28,7 +28,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; // Register Service registerSingleton(IOutputService, OutputService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index ef94a0c761e..a9b51ea1cca 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -7,7 +7,8 @@ import * as assert from 'assert'; import { importAMDNodeModule } from 'vs/amdX'; import { isWindows } from 'vs/base/common/platform'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; -import { IScreenReaderNotificationService, TestScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { TestScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index a01f5755cc0..1ad722276db 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -66,7 +66,7 @@ import 'vs/platform/extensionResourceLoader/browser/extensionResourceLoaderServi import 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibilityService, IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -182,7 +182,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { IScreenReaderNotificationService, ScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { ScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; export { From 8b549edd41ec8225e237adb02c2e55d07006d0c8 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 14:16:00 -0700 Subject: [PATCH 053/290] rename --- .../browser/screenReaderNotificationService.ts | 6 +++--- src/vs/platform/accessibility/common/accessibility.ts | 9 +++++++-- .../contrib/chat/browser/actions/chatClearActions.ts | 4 ++-- src/vs/workbench/contrib/debug/browser/repl.ts | 4 ++-- .../contrib/output/browser/output.contribution.ts | 4 ++-- .../contrib/terminal/browser/xterm/xtermTerminal.ts | 4 ++-- .../test/browser/bufferContentTracker.test.ts | 4 ++-- src/vs/workbench/workbench.web.main.ts | 6 +++--- 8 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts b/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts index c27442afde9..077122a3286 100644 --- a/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts +++ b/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts @@ -5,11 +5,11 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; -import { IAccessibilityService, IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -export class ScreenReaderNotificationService extends Disposable implements IScreenReaderNotificationService { +export class AccessibleNotificationService extends Disposable implements IAccessibleNotificationService { declare readonly _serviceBrand: undefined; constructor(@IAudioCueService private readonly _audioCueService: IAudioCueService, @@ -28,7 +28,7 @@ export class ScreenReaderNotificationService extends Disposable implements IScre } } -export class TestScreenReaderNotificationService implements IScreenReaderNotificationService { +export class TestScreenReaderNotificationService implements IAccessibleNotificationService { declare readonly _serviceBrand: undefined; diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index 849b900feb9..71192169845 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -47,9 +47,14 @@ export function isAccessibilityInformation(obj: any): obj is IAccessibilityInfor && (typeof obj.role === 'undefined' || typeof obj.role === 'string'); } -export interface IScreenReaderNotificationService { +/** + * Manages whether an audio cue or an aria alert will be used + * in response to actions taken around the workbench. + * Targets screen reader and braille users. + */ +export interface IAccessibleNotificationService { readonly _serviceBrand: undefined; notifyCleared(): void; } -export const IScreenReaderNotificationService = createDecorator('screenReaderNotificationService'); +export const IAccessibleNotificationService = createDecorator('accessibleNotificationService'); diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts index fc4e0578068..21cd019327c 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts @@ -7,7 +7,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { Action2, IAction2Options, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -118,5 +118,5 @@ export function getClearAction(viewId: string, providerId: string) { } function announceChatCleared(accessor: ServicesAccessor): void { - accessor.get(IScreenReaderNotificationService).notifyCleared(); + accessor.get(IAccessibleNotificationService).notifyCleared(); } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 9884467de8e..b3db21db9db 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -69,7 +69,7 @@ import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; import { ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { registerNavigableContainer } from 'vs/workbench/browser/actions/widgetNavigationCommands'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; const $ = dom.$; @@ -976,7 +976,7 @@ registerAction2(class extends ViewAction { } runInView(_accessor: ServicesAccessor, view: Repl): void { - const screenReaderNotificationService = _accessor.get(IScreenReaderNotificationService); + const screenReaderNotificationService = _accessor.get(IAccessibleNotificationService); view.clearRepl(); screenReaderNotificationService.notifyCleared(); } diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 19a3e04b12c..ff40639eff8 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -28,7 +28,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; // Register Service registerSingleton(IOutputService, OutputService, InstantiationType.Delayed); @@ -221,7 +221,7 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { } async run(accessor: ServicesAccessor): Promise { const outputService = accessor.get(IOutputService); - const screenReaderNotificationService = accessor.get(IScreenReaderNotificationService); + const screenReaderNotificationService = accessor.get(IAccessibleNotificationService); const activeChannel = outputService.getActiveChannel(); if (activeChannel) { activeChannel.clear(); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 61668047a6b..1c27f88f237 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -43,7 +43,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { debounce } from 'vs/base/common/decorators'; import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; const enum RenderConstants { /** @@ -204,7 +204,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach @ITelemetryService private readonly _telemetryService: ITelemetryService, @IClipboardService private readonly _clipboardService: IClipboardService, @IContextKeyService contextKeyService: IContextKeyService, - @IScreenReaderNotificationService private readonly _screenReaderNotificationService: IScreenReaderNotificationService + @IAccessibleNotificationService private readonly _screenReaderNotificationService: IAccessibleNotificationService ) { super(); const font = this._configHelper.getFont(undefined, true); diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index a9b51ea1cca..abc6747fa2b 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -8,7 +8,7 @@ import { importAMDNodeModule } from 'vs/amdX'; import { isWindows } from 'vs/base/common/platform'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { TestScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; -import { IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -67,7 +67,7 @@ suite('Buffer Content Tracker', () => { instantiationService.stub(IContextMenuService, store.add(instantiationService.createInstance(ContextMenuService))); instantiationService.stub(ILifecycleService, store.add(new TestLifecycleService())); instantiationService.stub(IContextKeyService, store.add(new MockContextKeyService())); - instantiationService.stub(IScreenReaderNotificationService, new TestScreenReaderNotificationService()); + instantiationService.stub(IAccessibleNotificationService, new TestScreenReaderNotificationService()); configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper)); capabilities = store.add(new TerminalCapabilityStore()); if (!isWindows) { diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 1ad722276db..df00a5ac33f 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -66,7 +66,7 @@ import 'vs/platform/extensionResourceLoader/browser/extensionResourceLoaderServi import 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IAccessibilityService, IScreenReaderNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -93,7 +93,7 @@ import { WebLanguagePacksService } from 'vs/platform/languagePacks/browser/langu registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, InstantiationType.Delayed); registerSingleton(IAccessibilityService, AccessibilityService, InstantiationType.Delayed); -registerSingleton(IScreenReaderNotificationService, ScreenReaderNotificationService, InstantiationType.Delayed); +registerSingleton(IAccessibleNotificationService, AccessibleNotificationService, InstantiationType.Delayed); registerSingleton(IContextMenuService, ContextMenuService, InstantiationType.Delayed); registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService, InstantiationType.Delayed); registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, InstantiationType.Delayed); @@ -182,7 +182,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { ScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { AccessibleNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; export { From d6e0b464c666bbf9204f9fd5711a2e52f1502771 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 12 Oct 2023 14:16:33 -0700 Subject: [PATCH 054/290] Update src/vs/platform/accessibility/test/common/testAccessibilityService.ts --- .../accessibility/test/common/testAccessibilityService.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/platform/accessibility/test/common/testAccessibilityService.ts b/src/vs/platform/accessibility/test/common/testAccessibilityService.ts index b046c6b46da..e6a7531f496 100644 --- a/src/vs/platform/accessibility/test/common/testAccessibilityService.ts +++ b/src/vs/platform/accessibility/test/common/testAccessibilityService.ts @@ -12,7 +12,6 @@ export class TestAccessibilityService implements IAccessibilityService { onDidChangeScreenReaderOptimized = Event.None; onDidChangeReducedMotion = Event.None; - onDidRequestPlayClearAudioCue = Event.None; isScreenReaderOptimized(): boolean { return false; } isMotionReduced(): boolean { return false; } From 30d5f3c72d16c49101114a06efec0a545eb790db Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 14:21:44 -0700 Subject: [PATCH 055/290] fix more issues --- ...otificationService.ts => accessibleNotificationService.ts} | 2 +- .../accessibility/test/common/testAccessibilityService.ts | 1 - .../accessibility/test/browser/bufferContentTracker.test.ts | 4 ++-- src/vs/workbench/workbench.web.main.ts | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) rename src/vs/platform/accessibility/browser/{screenReaderNotificationService.ts => accessibleNotificationService.ts} (94%) diff --git a/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts similarity index 94% rename from src/vs/platform/accessibility/browser/screenReaderNotificationService.ts rename to src/vs/platform/accessibility/browser/accessibleNotificationService.ts index 077122a3286..fb6311b7fbb 100644 --- a/src/vs/platform/accessibility/browser/screenReaderNotificationService.ts +++ b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts @@ -28,7 +28,7 @@ export class AccessibleNotificationService extends Disposable implements IAccess } } -export class TestScreenReaderNotificationService implements IAccessibleNotificationService { +export class TestAccessibleNotificationService implements IAccessibleNotificationService { declare readonly _serviceBrand: undefined; diff --git a/src/vs/platform/accessibility/test/common/testAccessibilityService.ts b/src/vs/platform/accessibility/test/common/testAccessibilityService.ts index e6a7531f496..0789812b905 100644 --- a/src/vs/platform/accessibility/test/common/testAccessibilityService.ts +++ b/src/vs/platform/accessibility/test/common/testAccessibilityService.ts @@ -19,5 +19,4 @@ export class TestAccessibilityService implements IAccessibilityService { setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void { } getAccessibilitySupport(): AccessibilitySupport { return AccessibilitySupport.Unknown; } alert(message: string): void { } - alertCleared(): void { } } diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index abc6747fa2b..417eb6d9028 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { importAMDNodeModule } from 'vs/amdX'; import { isWindows } from 'vs/base/common/platform'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; -import { TestScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -67,7 +67,7 @@ suite('Buffer Content Tracker', () => { instantiationService.stub(IContextMenuService, store.add(instantiationService.createInstance(ContextMenuService))); instantiationService.stub(ILifecycleService, store.add(new TestLifecycleService())); instantiationService.stub(IContextKeyService, store.add(new MockContextKeyService())); - instantiationService.stub(IAccessibleNotificationService, new TestScreenReaderNotificationService()); + instantiationService.stub(IAccessibleNotificationService, new TestAccessibleNotificationService()); configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper)); capabilities = store.add(new TerminalCapabilityStore()); if (!isWindows) { diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index df00a5ac33f..dbc49cb9dd7 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -182,7 +182,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { AccessibleNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService'; +import { AccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; export { From 3372e4ebb2f2177b511b84bbb9677aa51798d779 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 12 Oct 2023 14:22:17 -0700 Subject: [PATCH 056/290] Force include slash command in class agent API request (#195515) --- src/vs/workbench/api/browser/mainThreadChatAgents.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents.ts b/src/vs/workbench/api/browser/mainThreadChatAgents.ts index 82e0f735c6d..a5d719829f5 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents.ts @@ -43,7 +43,8 @@ export class MainThreadChatAgents implements MainThreadChatAgentsShape { const requestId = Math.random(); this._pendingProgress.set(requestId, progress); try { - const result = await this._proxy.$invokeAgent(handle, requestId, request.message, { history }, token); + const message = request.command ? `/${request.command} ${request.message}` : request.message; + const result = await this._proxy.$invokeAgent(handle, requestId, message, { history }, token); return { followUp: result?.followUp ?? [], }; From f10ee99ffea9eee40ea1c4e283261710bdc08f7d Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 14:24:28 -0700 Subject: [PATCH 057/290] use setting enum --- .../accessibility/browser/accessibleNotificationService.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts index fb6311b7fbb..836cf2e09ad 100644 --- a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts +++ b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts @@ -12,14 +12,15 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur export class AccessibleNotificationService extends Disposable implements IAccessibleNotificationService { declare readonly _serviceBrand: undefined; - constructor(@IAudioCueService private readonly _audioCueService: IAudioCueService, + constructor( + @IAudioCueService private readonly _audioCueService: IAudioCueService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService) { super(); } notifyCleared(): void { - const audioCueValue = this._configurationService.getValue('audioCues.clear'); + const audioCueValue = this._configurationService.getValue(AudioCue.clear.settingsKey); if (audioCueValue === 'on' || audioCueValue === 'auto' && this._accessibilityService.isScreenReaderOptimized()) { this._audioCueService.playAudioCue(AudioCue.clear); } else { From 275445afc32d12594ef9497338b6915a34e73889 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 12 Oct 2023 14:35:43 -0700 Subject: [PATCH 058/290] Update src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts --- .../contrib/audioCues/browser/audioCues.contribution.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index f143d82676f..22a4a7e390b 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -139,4 +139,5 @@ Registry.as(ConfigurationExtensions.Configuration).regis }, }, }); + registerAction2(ShowAudioCueHelp); From 04dc228d4f95f0af22072685c47ee5f34e97b79c Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Oct 2023 14:36:57 -0700 Subject: [PATCH 059/290] more renames --- src/vs/workbench/contrib/debug/browser/repl.ts | 4 ++-- .../workbench/contrib/output/browser/output.contribution.ts | 4 ++-- .../workbench/contrib/terminal/browser/xterm/xtermTerminal.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index b3db21db9db..5db4b41197d 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -976,9 +976,9 @@ registerAction2(class extends ViewAction { } runInView(_accessor: ServicesAccessor, view: Repl): void { - const screenReaderNotificationService = _accessor.get(IAccessibleNotificationService); + const accessibleNotificationService = _accessor.get(IAccessibleNotificationService); view.clearRepl(); - screenReaderNotificationService.notifyCleared(); + accessibleNotificationService.notifyCleared(); } }); diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index ff40639eff8..c03fe479393 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -221,11 +221,11 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { } async run(accessor: ServicesAccessor): Promise { const outputService = accessor.get(IOutputService); - const screenReaderNotificationService = accessor.get(IAccessibleNotificationService); + const accessibleNotificationService = accessor.get(IAccessibleNotificationService); const activeChannel = outputService.getActiveChannel(); if (activeChannel) { activeChannel.clear(); - screenReaderNotificationService.notifyCleared(); + accessibleNotificationService.notifyCleared(); } } })); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 1c27f88f237..1bb7bf8f194 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -204,7 +204,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach @ITelemetryService private readonly _telemetryService: ITelemetryService, @IClipboardService private readonly _clipboardService: IClipboardService, @IContextKeyService contextKeyService: IContextKeyService, - @IAccessibleNotificationService private readonly _screenReaderNotificationService: IAccessibleNotificationService + @IAccessibleNotificationService private readonly _accessibleNotificationService: IAccessibleNotificationService ) { super(); const font = this._configHelper.getFont(undefined, true); @@ -590,7 +590,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach // the prompt being written this._capabilities.get(TerminalCapability.CommandDetection)?.handlePromptStart(); this._capabilities.get(TerminalCapability.CommandDetection)?.handleCommandStart(); - this._screenReaderNotificationService.notifyCleared(); + this._accessibleNotificationService.notifyCleared(); } hasSelection(): boolean { From 5b0ed15c518ec4d89913a4c617d73bb7134cc5f4 Mon Sep 17 00:00:00 2001 From: Sandeep Sen Date: Thu, 12 Oct 2023 15:40:58 -0700 Subject: [PATCH 060/290] Adding mgmt libraries for Go + changing matcher logic for Go (#191036) * Adding management libraires for Go and upading matcher to startswith * Corrected tag concat logic for Go --- .../electron-sandbox/workspaceTagsService.ts | 242 +++++++++++++++++- 1 file changed, 236 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts index 91e03015dc5..8274fb572f6 100644 --- a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts +++ b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts @@ -293,21 +293,24 @@ const GoModulesToLookFor = [ 'github.com/Azure/azure-sdk-for-go/sdk/storage/azblob', 'github.com/Azure/azure-sdk-for-go/sdk/storage/azfile', 'github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue', + 'github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake', 'github.com/Azure/azure-sdk-for-go/sdk/tracing/azotel', 'github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azadmin', 'github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates', 'github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys', 'github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets', 'github.com/Azure/azure-sdk-for-go/sdk/monitor/azquery', + 'github.com/Azure/azure-sdk-for-go/sdk/monitor/azingest', 'github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs', 'github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus', 'github.com/Azure/azure-sdk-for-go/sdk/data/azappconfig', 'github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos', 'github.com/Azure/azure-sdk-for-go/sdk/data/aztables', 'github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry', - 'github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai', + 'github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai', 'github.com/Azure/azure-sdk-for-go/sdk/azidentity', - 'github.com/Azure/azure-sdk-for-go/sdk/azcore' + 'github.com/Azure/azure-sdk-for-go/sdk/azcore', + 'github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/' ]; @@ -681,21 +684,246 @@ export class WorkspaceTagsService implements IWorkspaceTagsService { "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/storage/azfile" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/tracing/azotel" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azadmin" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/monitor/azquery" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/monitor/azingest" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/data/azappconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/data/aztables" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/cognitiveservices/azopenai" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/azidentity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/azcore" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/azcore" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iotfirmwaredefense/armiotfirmwaredefense" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/aad/armaad" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/addons/armaddons" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/advisor/armadvisor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/agrifood/armagrifood" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/alertsmanagement/armalertsmanagement" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/analysisservices/armanalysisservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/apimanagement/armapimanagement" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appcomplianceautomation/armappcomplianceautomation" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appconfiguration/armappconfiguration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appplatform/armappplatform" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appservice/armappservice" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/azurearcdata/armazurearcdata" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/attestation/armattestation" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/automanage/armautomanage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/automation/armautomation" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/azuredata/armazuredata" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/azurestackhci/armazurestackhci" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/avs/armavs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/recoveryservices/armrecoveryservicesbackup" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/baremetalinfrastructure/armbaremetalinfrastructure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/batch/armbatch" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/billing/armbilling" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/billingbenefits/armbillingbenefits" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/blockchain/armblockchain" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/blueprint/armblueprint" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/botservice/armbotservice" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/changeanalysis/armchangeanalysis" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armchanges" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/chaos/armchaos" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/search/armsearch" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cognitiveservices/armcognitiveservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/commerce/armcommerce" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/communication/armcommunication" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/confidentialledger/armconfidentialledger" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/confluent/armconfluent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/connectedvmware/armconnectedvmware" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/consumption/armconsumption" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appcontainers/armappcontainers" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerinstance/armcontainerinstance" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservicefleet/armcontainerservicefleet" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cdn/armcdn" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmosforpostgresql/armcosmosforpostgresql" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/costmanagement/armcostmanagement" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/customproviders/armcustomproviders" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/customerinsights/armcustomerinsights" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/customerlockbox/armcustomerlockbox" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/databox/armdatabox" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/databoxedge/armdataboxedge" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/datacatalog/armdatacatalog" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/datafactory/armdatafactory" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/datalake-analytics/armdatalakeanalytics" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/datalake-store/armdatalakestore" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/datamigration/armdatamigration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dataprotection/armdataprotection" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/datashare/armdatashare" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/databricks/armdatabricks" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/datadog/armdatadog" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/delegatednetwork/armdelegatednetwork" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/deploymentmanager/armdeploymentmanager" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armdeploymentscripts" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/desktopvirtualization/armdesktopvirtualization" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/devcenter/armdevcenter" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/devhub/armdevhub" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/deviceprovisioningservices/armdeviceprovisioningservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/deviceupdate/armdeviceupdate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/devops/armdevops" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/devtestlabs/armdevtestlabs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/digitaltwins/armdigitaltwins" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dnsresolver/armdnsresolver" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/domainservices/armdomainservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dynatrace/armdynatrace" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/edgeorder/armedgeorder" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/edgeorderpartner/armedgeorderpartner" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/education/armeducation" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elastic/armelastic" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsan/armelasticsan" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/elasticsans/armelasticsans" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/engagementfabric/armengagementfabric" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventgrid/armeventgrid" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/extendedlocation/armextendedlocation" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armfeatures" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/fluidrelay/armfluidrelay" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/frontdoor/armfrontdoor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/graphservices/armgraphservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/guestconfiguration/armguestconfiguration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hanaonazure/armhanaonazure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hardwaresecuritymodules/armhardwaresecuritymodules" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hdinsight/armhdinsight" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/healthbot/armhealthbot" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/healthcareapis/armhealthcareapis" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hybridcompute/armhybridcompute" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hybridconnectivity/armhybridconnectivity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hybridcontainerservice/armhybridcontainerservice" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hybriddatamanager/armhybriddatamanager" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hybridkubernetes/armhybridkubernetes" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/hybridnetwork/armhybridnetwork" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iotcentral/armiotcentral" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iothub/armiothub" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iotsecurity/armiotsecurity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/kubernetesconfiguration/armkubernetesconfiguration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/kusto/armkusto" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/labservices/armlabservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armlinks" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/loadtesting/armloadtesting" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armlocks" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/operationalinsights/armoperationalinsights" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/logic/armlogic" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/logz/armlogz" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/m365securityandcompliance/armm365securityandcompliance" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/machinelearning/armmachinelearning" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/machinelearningservices/armmachinelearningservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/maintenance/armmaintenance" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armmanagedapplications" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/solutions/armmanagedapplications" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dashboard/armdashboard" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managednetwork/armmanagednetwork" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managednetworkfabric/armmanagednetworkfabric" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managedservices/armmanagedservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementpartner/armmanagementpartner" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/maps/armmaps" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mariadb/armmariadb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/marketplace/armmarketplace" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/marketplaceordering/armmarketplaceordering" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mediaservices/armmediaservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/migrate/armmigrate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mixedreality/armmixedreality" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mobilenetwork/armmobilenetwork" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mysql/armmysql" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/mysql/armmysqlflexibleservers" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/netapp/armnetapp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/networkcloud/armnetworkcloud" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/networkfunction/armnetworkfunction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/newrelic/armnewrelicobservability" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/nginx/armnginx" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/notificationhubs/armnotificationhubs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/oep/armoep" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/operationsmanagement/armoperationsmanagement" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/orbital/armorbital" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/paloaltonetworksngfw/armpanngfw" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/peering/armpeering" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armpolicy" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/policyinsights/armpolicyinsights" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/portal/armportal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/postgresql/armpostgresql" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/postgresql/armpostgresqlflexibleservers" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/postgresqlhsc/armpostgresqlhsc" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/powerbiprivatelinks/armpowerbiprivatelinks" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/powerbidedicated/armpowerbidedicated" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/powerbiembedded/armpowerbiembedded" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/powerplatform/armpowerplatform" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/providerhub/armproviderhub" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/purview/armpurview" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/quantum/armquantum" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/liftrqumulo/armqumulo" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/quota/armquota" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/recoveryservices/armrecoveryservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/redhatopenshift/armredhatopenshift" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/redis/armredis" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/redisenterprise/armredisenterprise" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/relay/armrelay" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/reservations/armreservations" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourceconnector/armresourceconnector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcehealth/armresourcehealth" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcemover/armresourcemover" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/saas/armsaas" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/scheduler/armscheduler" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/scvmm/armscvmm" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/security/armsecurity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/securitydevops/armsecuritydevops" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/securityinsight/armsecurityinsight" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/securityinsights/armsecurityinsights" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/selfhelp/armselfhelp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/serialconsole/armserialconsole" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/servicebus/armservicebus" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/servicefabric/armservicefabric" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/servicefabricmesh/armservicefabricmesh" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/servicelinker/armservicelinker" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/servicenetworking/armservicenetworking" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/signalr/armsignalr" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/recoveryservices/armrecoveryservicessiterecovery" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sphere/armsphere" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sqlvirtualmachine/armsqlvirtualmachine" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storagecache/armstoragecache" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storageimportexport/armstorageimportexport" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storagemover/armstoragemover" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storagepool/armstoragepool" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storagesync/armstoragesync" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storsimple1200series/armstorsimple1200series" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storsimple8000series/armstorsimple8000series" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/streamanalytics/armstreamanalytics" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/support/armsupport" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/synapse/armsynapse" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armtemplatespecs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/testbase/armtestbase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/timeseriesinsights/armtimeseriesinsights" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/trafficmanager/armtrafficmanager" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/web/armweb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/webpubsub/armwebpubsub" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/windowsesu/armwindowsesu" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/windowsiot/armwindowsiot" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/workloadmonitor/armworkloadmonitor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.go.mod.github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/workloads/armworkloads" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } } */ private async resolveWorkspaceTags(): Promise { @@ -918,8 +1146,10 @@ export class WorkspaceTagsService implements IWorkspaceTagsService { } if (firstRequireBlockFound && line !== '') { const packageName: string = line.split(' ')[0].trim(); - if (GoModulesToLookFor.indexOf(packageName) > -1) { - tags['workspace.go.mod.' + packageName] = true; + for (const module of GoModulesToLookFor) { + if (packageName.startsWith(module)) { + tags['workspace.go.mod.' + packageName] = true; + } } } } From e13be231e79ecfd58d3c0e2f0c3f270a219c765e Mon Sep 17 00:00:00 2001 From: David Dossett Date: Thu, 12 Oct 2023 17:07:58 -0700 Subject: [PATCH 061/290] Tweak references footer styling (#195524) * Tweak references footer styling * Add back deleted line --- .../contrib/chat/browser/media/chat.css | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index e7319f0a593..c4e73897ca1 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -484,18 +484,45 @@ display: none; } +.interactive-session .chat-used-context-list { + border: 1px solid var(--vscode-chat-requestBorder); + border-radius: 3px; + padding: 4px; +} + +.interactive-session .chat-used-context-list .monaco-list .monaco-list-row { + border-radius: 2px; +} + .interactive-session .chat-used-context-label { - font-size: 0.9em; + font-size: 12px; + color: var(--vscode-foreground); + opacity: 0.8; +} + +.interactive-session .chat-used-context-label:hover { + opacity: unset; } .interactive-session .chat-used-context-label .monaco-button { /* unset Button styles */ display: inline-flex; - width: initial; + width: 100%; border: none; padding: 0; text-align: initial; - padding-left: 4px; justify-content: initial; - margin-bottom: 3px; + margin-bottom: 6px; +} + +.interactive-session .chat-used-context-label .monaco-text-button { + outline-offset: unset !important; +} + +.interactive-session .chat-used-context-label .monaco-button:focus-within { + outline: none; +} + +.interactive-session .chat-used-context .chat-used-context-label .monaco-button .codicon { + margin: 0 2px 0 0; } From 6c02f61149c7ce6cadca49c6376b68a99d46135b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 12 Oct 2023 21:27:30 -0700 Subject: [PATCH 062/290] Fix variables in chatAgents2 API requests, add tests (#195529) * Fix variables in chatAgents2 API requests * Enable file references and the 'used references' section by default in Insiders * Add integration tests for chat * Fix equality * fix test --- extensions/vscode-api-tests/package.json | 9 +++ .../src/singlefolder-tests/chat.test.ts | 80 +++++++++++++++++++ .../singlefolder-tests/interactive.test.ts | 62 ++++++++++++++ .../api/common/extHostChatAgents2.ts | 8 +- .../api/common/extHostTypeConverters.ts | 9 +++ .../contrib/chat/browser/chatListRenderer.ts | 6 +- .../browser/contrib/chatInputEditorContrib.ts | 4 +- 7 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts create mode 100644 extensions/vscode-api-tests/src/singlefolder-tests/interactive.test.ts diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 94f8e3ac5db..b38c91ce1ce 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -6,6 +6,8 @@ "license": "MIT", "enabledApiProposals": [ "authSession", + "chatAgents2", + "chatVariables", "contribViewsRemote", "contribStatusBarItems", "createFileSystemWatcher", @@ -20,6 +22,7 @@ "fileSearchProvider", "findTextInFiles", "fsChunks", + "interactive", "mappedEditsProvider", "notebookCellExecutionState", "notebookDeprecated", @@ -165,6 +168,12 @@ ] } ], + "interactiveSession": [ + { + "id": "provider", + "label": "Provider" + } + ], "notebooks": [ { "type": "notebookCoreTest", diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts new file mode 100644 index 00000000000..561f040dedb --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * 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 'mocha'; +import { CancellationToken, chat, ChatAgentRequest, ChatVariableLevel, CompletionItemKind, Disposable, interactive, InteractiveProgress, InteractiveRequest, InteractiveResponseForProgress, InteractiveSession, InteractiveSessionState, Progress, ProviderResult } from 'vscode'; +import { assertNoRpc, closeAllEditors, DeferredPromise, disposeAll } from '../utils'; + +suite('chat', () => { + let disposables: Disposable[] = []; + setup(() => { + disposables = []; + }); + + teardown(async function () { + assertNoRpc(); + await closeAllEditors(); + disposeAll(disposables); + }); + + function getDeferredForRequest(): DeferredPromise { + disposables.push(interactive.registerInteractiveSessionProvider('provider', { + prepareSession: (_initialState: InteractiveSessionState | undefined, _token: CancellationToken): ProviderResult => { + return { + requester: { name: 'test' }, + responder: { name: 'test' }, + }; + }, + + provideResponseWithProgress: (_request: InteractiveRequest, _progress: Progress, _token: CancellationToken): ProviderResult => { + return null; + }, + + provideSlashCommands: (_session, _token) => { + return [{ command: 'hello', title: 'Hello', kind: CompletionItemKind.Text }]; + }, + + removeRequest: (_session: InteractiveSession, _requestId: string): void => { + throw new Error('Function not implemented.'); + } + })); + + const deferred = new DeferredPromise(); + const agent = chat.createChatAgent('agent', (request, _context, _progress, _token) => { + deferred.complete(request); + return null; + }); + agent.slashCommandProvider = { + provideSlashCommands: (_token) => { + return [{ name: 'hello', description: 'Hello' }]; + } + }; + disposables.push(agent); + return deferred; + } + + test('agent and slash command', async () => { + const deferred = getDeferredForRequest(); + interactive.sendInteractiveRequestToProvider('provider', { message: '@agent /hello friend' }); + const lastResult = await deferred.p; + assert.deepStrictEqual(lastResult.slashCommand, { name: 'hello', description: 'Hello' }); + assert.strictEqual(lastResult.prompt, 'friend'); + }); + + test('agent and variable', async () => { + disposables.push(chat.registerVariable('myVar', 'My variable', { + resolve(_name, _context, _token) { + return [{ level: ChatVariableLevel.Full, value: 'myValue' }]; + } + })); + + const deferred = getDeferredForRequest(); + interactive.sendInteractiveRequestToProvider('provider', { message: '@agent hi #myVar' }); + const lastResult = await deferred.p; + assert.strictEqual(lastResult.prompt, 'hi [#myVar](values:myVar)'); + assert.strictEqual(lastResult.variables['myVar'][0].value, 'myValue'); + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/interactive.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/interactive.test.ts new file mode 100644 index 00000000000..b6b5623a7fb --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/interactive.test.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * 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 'mocha'; +import { CancellationToken, CompletionItemKind, Disposable, interactive, InteractiveProgress, InteractiveRequest, InteractiveResponseForProgress, InteractiveSession, InteractiveSessionState, Progress, ProviderResult } from 'vscode'; +import { assertNoRpc, closeAllEditors, DeferredPromise, disposeAll } from '../utils'; + +suite('InteractiveSessionProvider', () => { + let disposables: Disposable[] = []; + setup(async () => { + disposables = []; + }); + + teardown(async function () { + assertNoRpc(); + await closeAllEditors(); + disposeAll(disposables); + }); + + function getDeferredForRequest(): DeferredPromise { + const deferred = new DeferredPromise(); + disposables.push(interactive.registerInteractiveSessionProvider('provider', { + prepareSession: (_initialState: InteractiveSessionState | undefined, _token: CancellationToken): ProviderResult => { + return { + requester: { name: 'test' }, + responder: { name: 'test' }, + }; + }, + + provideResponseWithProgress: (request: InteractiveRequest, _progress: Progress, _token: CancellationToken): ProviderResult => { + deferred.complete(request); + return null; + }, + + provideSlashCommands: (_session, _token) => { + return [{ command: 'hello', title: 'Hello', kind: CompletionItemKind.Text }]; + }, + + removeRequest: (_session: InteractiveSession, _requestId: string): void => { + throw new Error('Function not implemented.'); + } + })); + return deferred; + } + + test('plain text query', async () => { + const deferred = getDeferredForRequest(); + interactive.sendInteractiveRequestToProvider('provider', { message: 'hello' }); + const lastResult = await deferred.p; + assert.strictEqual(lastResult.message, 'hello'); + }); + + test('slash command', async () => { + const deferred = getDeferredForRequest(); + interactive.sendInteractiveRequestToProvider('provider', { message: '/hello' }); + const lastResult = await deferred.p; + assert.strictEqual(lastResult.message, '/hello'); + }); +}); diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index f600a080047..3ec9a443b9c 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -67,11 +67,13 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { ? await agent.validateSlashCommand(request.command) : undefined; - try { - const task = agent.invoke( - { prompt: request.message, variables: {}, slashCommand }, + { + prompt: request.message, + variables: typeConvert.ChatVariable.objectTo(request.variables), + slashCommand + }, { history: context.history.map(typeConvert.ChatMessage.to) }, new Progress(p => { throwIfDone(); diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index be64d84533e..df2f59b8a84 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2236,6 +2236,15 @@ export namespace ChatMessageRole { } export namespace ChatVariable { + export function objectTo(variableObject: Record): Record { + const result: Record = {}; + for (const key of Object.keys(variableObject)) { + result[key] = variableObject[key].map(ChatVariable.to); + } + + return result; + } + export function to(variable: IChatRequestVariableValue): vscode.ChatVariableValue { return { level: ChatVariableLevel.to(variable.level), diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index d37fa7c8286..84b9278cbc7 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -55,6 +55,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { WorkbenchCompressibleAsyncDataTree, WorkbenchList } from 'vs/platform/list/browser/listService'; import { ILogService } from 'vs/platform/log/common/log'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IProductService } from 'vs/platform/product/common/productService'; import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; @@ -145,6 +146,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { if (e.affectsConfiguration('chat.experimental.usedReferences')) { - this._usedReferencesEnabled = configService.getValue('chat.experimental.usedReferences'); + this._usedReferencesEnabled = configService.getValue('chat.experimental.usedReferences') ?? productService.quality !== 'stable'; } })); } diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index 2880bd122a3..3c015b89c42 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -17,6 +17,7 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IProductService } from 'vs/platform/product/common/productService'; import { Registry } from 'vs/platform/registry/common/platform'; import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -435,6 +436,7 @@ class BuiltinDynamicCompletions extends Disposable { @ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService, @IChatWidgetService private readonly chatWidgetService: IChatWidgetService, @IConfigurationService private readonly configurationService: IConfigurationService, + @IProductService private readonly productService: IProductService, ) { super(); @@ -442,7 +444,7 @@ class BuiltinDynamicCompletions extends Disposable { _debugDisplayName: 'chatDynamicCompletions', triggerCharacters: ['$'], provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { - const fileVariablesEnabled = this.configurationService.getValue('chat.experimental.fileVariables'); + const fileVariablesEnabled = this.configurationService.getValue('chat.experimental.fileVariables') ?? this.productService.quality !== 'stable'; if (!fileVariablesEnabled) { return; } From 4678919d52909efc7c4ab958a2e5c8f45d50ffc3 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 12 Oct 2023 21:48:53 -0700 Subject: [PATCH 063/290] Return the session if the user constented (#195527) Fixes https://github.com/microsoft/vscode/issues/195286 If the auth provider doesn't support multiple accounts and we have a valid session and the user consented, then use that session. --- src/vs/workbench/api/browser/mainThreadAuthentication.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index 0a7452bbe27..ec4ae3964cb 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -243,8 +243,10 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu } let session; - if (sessions?.length && !options.forceNewSession && supportsMultipleAccounts) { - session = await this.authenticationService.selectSession(providerId, extensionId, extensionName, scopes, sessions); + if (sessions?.length && !options.forceNewSession) { + session = supportsMultipleAccounts + ? await this.authenticationService.selectSession(providerId, extensionId, extensionName, scopes, sessions) + : sessions[0]; } else { let sessionToRecreate: AuthenticationSession | undefined; if (typeof options.forceNewSession === 'object' && options.forceNewSession.sessionToRecreate) { From 7729a82c179ccf0884a02e2caa08b78e6504645f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 13 Oct 2023 08:06:28 +0200 Subject: [PATCH 064/290] files - have "Open File" command on macOS too (#195537) --- src/vs/workbench/browser/actions/workspaceActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index cbb08e8ff09..3f2e2799fa5 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -36,8 +36,8 @@ export class OpenFileAction extends Action2 { title: { value: localize('openFile', "Open File..."), original: 'Open File...' }, category: Categories.File, f1: true, - precondition: IsMacNativeContext.toNegated(), keybinding: { + when: IsMacNativeContext.toNegated(), weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.CtrlCmd | KeyCode.KeyO } From 269bece617ce3e6ba280fbf5f1283ee5f7d21bf0 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:57:20 +0200 Subject: [PATCH 065/290] SCM inputBox menu css fixes (#195546) --- src/vs/workbench/contrib/scm/browser/media/scm.css | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css index efd1ace9387..6ccd5dbf96d 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css @@ -199,12 +199,16 @@ flex-grow: 100; } +.scm-view .monaco-list .monaco-list-row .scm-input > .actions, .scm-view .monaco-list .monaco-list-row .resource-group > .actions, .scm-view .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions { display: none; max-width: fit-content; } +.scm-view .monaco-list .monaco-list-row:hover .scm-input > .actions, +.scm-view .monaco-list .monaco-list-row.selected .scm-input > .actions, +.scm-view .monaco-list .monaco-list-row.focused .scm-input > .actions, .scm-view .monaco-list .monaco-list-row:hover .resource-group > .actions, .scm-view .monaco-list .monaco-list-row.selected .resource-group > .actions, .scm-view .monaco-list .monaco-list-row.focused .resource-group > .actions, @@ -227,6 +231,7 @@ } .scm-view.show-actions .scm-provider > .actions, +.scm-view.show-actions > .monaco-list .monaco-list-row .scm-input > .actions, .scm-view.show-actions > .monaco-list .monaco-list-row .resource-group > .actions, .scm-view.show-actions > .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions { display: block; @@ -244,10 +249,14 @@ .scm-view .scm-input .actions { position: absolute; - top: 6px; + top: 7px; right: 20px; - border: 1px solid var(--vscode-toolbar-hoverBackground); +} + +.scm-view .scm-input .actions .action-label { border-radius: 5px; + outline: 1px dashed var(--vscode-toolbar-hoverOutline); + outline-offset: -1px; } .scm-view .scm-editor-container .monaco-editor { From 6abc130a84a09176a6660a4dcad9da5edca5c644 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 13 Oct 2023 11:08:34 +0200 Subject: [PATCH 066/290] no need for promise.race since one call is sync --- src/vs/base/node/id.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vs/base/node/id.ts b/src/vs/base/node/id.ts index 5bbbbd75f9a..42a7f771358 100644 --- a/src/vs/base/node/id.ts +++ b/src/vs/base/node/id.ts @@ -106,11 +106,7 @@ export async function getSqmMachineId(errorLogger: (error: any) => void): Promis if (isWindows) { const Registry = await import('@vscode/windows-registry'); try { - // Wait for 1s max (as to not block the startup) to read the SQM value - return await Promise.race([ - Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', SQM_KEY, 'MachineId') || '', - new Promise(resolve => setTimeout(() => resolve(''), 1000)) - ]); + return Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', SQM_KEY, 'MachineId') || ''; } catch (err) { errorLogger(err); return ''; From e63c6c1bd0d167b281d17608f541053f70523675 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 13 Oct 2023 12:08:35 +0200 Subject: [PATCH 067/290] Re-enable continue-on for comments (#195551) --- src/vs/workbench/contrib/comments/browser/commentService.ts | 6 ------ .../contrib/comments/common/commentsConfiguration.ts | 1 - 2 files changed, 7 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentService.ts b/src/vs/workbench/contrib/comments/browser/commentService.ts index 2fc9d57909d..63b91ec40ad 100644 --- a/src/vs/workbench/contrib/comments/browser/commentService.ts +++ b/src/vs/workbench/contrib/comments/browser/commentService.ts @@ -176,9 +176,6 @@ export class CommentService extends Disposable implements ICommentService { const storageEvent = Event.debounce(this.storageService.onDidChangeValue(StorageScope.WORKSPACE, CONTINUE_ON_COMMENTS, storageListener), (last, event) => last?.external ? last : event, 500); storageListener.add(storageEvent(v => { - if (!this.configurationService.getValue(COMMENTS_SECTION)?.experimentalContinueOn) { - return; - } if (!v.external) { return; } @@ -200,9 +197,6 @@ export class CommentService extends Disposable implements ICommentService { } })); this._register(storageService.onWillSaveState(() => { - if (!this.configurationService.getValue(COMMENTS_SECTION)?.experimentalContinueOn) { - return; - } const map: Map = new Map(); for (const provider of this._continueOnCommentProviders) { const pendingComments = provider.provideContinueOnComments(); diff --git a/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts b/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts index 6894e066602..44004fe47d7 100644 --- a/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts +++ b/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts @@ -9,7 +9,6 @@ export interface ICommentsConfiguration { visible: boolean; maxHeight: boolean; collapseOnResolve: boolean; - experimentalContinueOn: boolean; } export const COMMENTS_SECTION = 'comments'; From 717f3e3f6c08bd7856fdffd0fe2076e3d4553ac9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2023 12:46:43 +0200 Subject: [PATCH 068/290] Joh/tart-lamprey (#195554) * some API todos * add `ChatAgent2#onDidReceiveFeedback` for helpful/unhelpful feedback kinds * add another proposal for chat additions * small tweaks --- .../workbench/api/browser/mainThreadChat.ts | 4 +- .../api/browser/mainThreadChatAgents2.ts | 14 ++++ .../workbench/api/common/extHost.api.impl.ts | 3 +- .../workbench/api/common/extHost.protocol.ts | 4 +- .../api/common/extHostChatAgents2.ts | 78 +++++++++++++++++-- src/vs/workbench/api/common/extHostTypes.ts | 5 ++ .../browser/actions/chatCodeblockActions.ts | 10 +++ .../chat/browser/actions/chatTitleActions.ts | 8 +- .../contrib/chat/browser/chatListRenderer.ts | 4 +- .../contrib/chat/common/chatModel.ts | 1 + .../contrib/chat/common/chatService.ts | 2 + .../contrib/chat/common/chatServiceImpl.ts | 6 +- .../contrib/chat/common/chatViewModel.ts | 6 ++ .../common/extensionsApiProposals.ts | 1 + .../vscode.proposed.chatAgents2.d.ts | 23 +++++- .../vscode.proposed.chatAgents2Additions.d.ts | 18 +++++ 16 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts diff --git a/src/vs/workbench/api/browser/mainThreadChat.ts b/src/vs/workbench/api/browser/mainThreadChat.ts index 630ea5116d2..a68c2d1c83d 100644 --- a/src/vs/workbench/api/browser/mainThreadChat.ts +++ b/src/vs/workbench/api/browser/mainThreadChat.ts @@ -38,7 +38,9 @@ export class MainThreadChat extends Disposable implements MainThreadChatShape { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChat); this._register(this._chatService.onDidPerformUserAction(e => { - this._proxy.$onDidPerformUserAction(e); + if (!e.agentId) { + this._proxy.$onDidPerformUserAction(e); + } })); } diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index c6102cbeecc..438583607e9 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -36,6 +36,20 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA this._register(this._chatService.onDidDisposeSession(e => { this._proxy.$releaseSession(e.sessionId); })); + this._register(this._chatService.onDidPerformUserAction(e => { + if (e.agentId) { + for (const [handle, agent] of this._agents) { + if (agent.name === e.agentId) { + if (e.action.kind === 'vote') { + this._proxy.$acceptFeedback(handle, e.sessionId, e.action.direction); + } else { + this._proxy.$acceptAction(handle, e.sessionId, e); + } + break; + } + } + } + })); } $unregisterAgent(handle: number): void { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 1fe5ef33fa6..cd983bdc650 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1372,7 +1372,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, createChatAgent(name: string, handler: vscode.ChatAgentHandler) { checkProposedApiEnabled(extension, 'chatAgents2'); - return extHostChatAgents2.createChatAgent(extension.identifier, name, handler); + return extHostChatAgents2.createChatAgent(extension, name, handler); }, registerAgent(name: string, agent: vscode.ChatAgent, metadata: vscode.ChatAgentMetadata) { checkProposedApiEnabled(extension, 'chatAgents'); @@ -1412,6 +1412,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // types Breakpoint: extHostTypes.Breakpoint, TerminalOutputAnchor: extHostTypes.TerminalOutputAnchor, + ChatAgentResultFeedbackKind: extHostTypes.ChatAgentResultFeedbackKind, ChatMessage: extHostTypes.ChatMessage, ChatMessageRole: extHostTypes.ChatMessageRole, ChatVariableLevel: extHostTypes.ChatVariableLevel, diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 86c7f4ade21..bf0b7392ca4 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -52,7 +52,7 @@ import { IRevealOptions, ITreeItem, IViewBadge } from 'vs/workbench/common/views import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { IChatAgentCommand, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents'; import { IChatMessage, IChatResponseFragment, IChatResponseProviderMetadata } from 'vs/workbench/contrib/chat/common/chatProvider'; -import { IChatDynamicRequest, IChatFollowup, IChatReplyFollowup, IChatResponseErrorDetails, IChatUserActionEvent, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatDynamicRequest, IChatFollowup, IChatReplyFollowup, IChatResponseErrorDetails, IChatUserActionEvent, ISlashCommand, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatSlashFragment } from 'vs/workbench/contrib/chat/common/chatSlashCommands'; import { IChatRequestVariableValue, IChatVariableData } from 'vs/workbench/contrib/chat/common/chatVariables'; import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug'; @@ -1184,6 +1184,8 @@ export interface ExtHostChatAgentsShape2 { $invokeAgent(handle: number, sessionId: string, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise; $provideSlashCommands(handle: number, token: CancellationToken): Promise; $provideFollowups(handle: number, sessionId: string, token: CancellationToken): Promise; + $acceptFeedback(handle: number, sessionId: string, vote: InteractiveSessionVoteDirection): void; + $acceptAction(handle: number, sessionId: string, action: IChatUserActionEvent): void; $releaseSession(sessionId: string): void; } diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 3ec9a443b9c..bd48108cd4a 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -6,17 +6,20 @@ import { DeferredPromise, raceCancellation } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { Emitter } from 'vs/base/common/event'; import { assertType } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { Progress } from 'vs/platform/progress/common/progress'; import { ExtHostChatAgentsShape2, IMainContext, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostChatProvider } from 'vs/workbench/api/common/extHostChatProvider'; import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; +import { ChatAgentResultFeedbackKind } from 'vs/workbench/api/common/extHostTypes'; import { IChatAgentCommand, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents'; import { IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; -import { IChatFollowup } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatFollowup, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; +import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import type * as vscode from 'vscode'; export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { @@ -36,7 +39,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { this._proxy = mainContext.getProxy(MainContext.MainThreadChatAgents2); } - createChatAgent(extension: ExtensionIdentifier, name: string, handler: vscode.ChatAgentHandler): vscode.ChatAgent2 { + createChatAgent(extension: IExtensionDescription, name: string, handler: vscode.ChatAgentHandler): vscode.ChatAgent2 { const handle = ExtHostChatAgents2._idPool++; const agent = new ExtHostChatAgent(extension, name, this._proxy, handle, handler); this._agents.set(handle, agent); @@ -61,7 +64,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { const commandExecution = new DeferredPromise(); token.onCancellationRequested(() => commandExecution.complete()); setTimeout(() => commandExecution.complete(), 3 * 1000); - this._extHostChatProvider.allowListExtensionWhile(agent.extension, commandExecution.p); + this._extHostChatProvider.allowListExtensionWhile(agent.extension.identifier, commandExecution.p); const slashCommand = request.command ? await agent.validateSlashCommand(request.command) @@ -134,6 +137,44 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return agent.provideFollowups(result, token); } + + $acceptFeedback(handle: number, sessionId: string, vote: InteractiveSessionVoteDirection): void { + const agent = this._agents.get(handle); + if (!agent) { + return; + } + const result = this._previousResultMap.get(sessionId); + if (!result) { + return; + } + + let kind: ChatAgentResultFeedbackKind; + switch (vote) { + case InteractiveSessionVoteDirection.Down: + kind = ChatAgentResultFeedbackKind.Unhelpful; + break; + case InteractiveSessionVoteDirection.Up: + kind = ChatAgentResultFeedbackKind.Helpful; + break; + } + agent.acceptFeedback(Object.freeze({ result, kind })); + } + + $acceptAction(handle: number, sessionId: string, action: IChatUserActionEvent): void { + const agent = this._agents.get(handle); + if (!agent) { + return; + } + const result = this._previousResultMap.get(sessionId); + if (!result) { + return; + } + if (action.action.kind === 'vote') { + // handled by $acceptFeedback + return; + } + agent.acceptAction(Object.freeze({ action: action.action, result })); + } } class ExtHostChatAgent { @@ -144,15 +185,24 @@ class ExtHostChatAgent { private _description: string | undefined; private _fullName: string | undefined; private _iconPath: URI | undefined; + private _onDidReceiveFeedback = new Emitter(); + private _onDidPerformAction = new Emitter(); constructor( - public readonly extension: ExtensionIdentifier, + public readonly extension: IExtensionDescription, private readonly _id: string, private readonly _proxy: MainThreadChatAgentsShape2, private readonly _handle: number, private readonly _callback: vscode.ChatAgentHandler, ) { } + acceptFeedback(feedback: vscode.ChatAgentResult2Feedback) { + this._onDidReceiveFeedback.fire(feedback); + } + + acceptAction(event: vscode.ChatAgentUserActionEvent) { + this._onDidPerformAction.fire(event); + } async validateSlashCommand(command: string) { if (!this._lastSlashCommands) { @@ -191,9 +241,12 @@ class ExtHostChatAgent { } get apiAgent(): vscode.ChatAgent2 { - + let disposed = false; let updateScheduled = false; const updateMetadataSoon = () => { + if (disposed) { + return; + } if (updateScheduled) { return; } @@ -223,7 +276,7 @@ class ExtHostChatAgent { updateMetadataSoon(); }, get fullName() { - return that._fullName ?? that.extension.value; + return that._fullName ?? that.extension.displayName ?? that.extension.name; }, set fullName(v) { that._fullName = v; @@ -251,7 +304,18 @@ class ExtHostChatAgent { that._followupProvider = v; updateMetadataSoon(); }, + get onDidReceiveFeedback() { + return that._onDidReceiveFeedback.event; + }, + onDidPerformAction: !isProposedApiEnabled(this.extension, 'chatAgents2Additions') + ? undefined! + : this._onDidPerformAction.event + , dispose() { + disposed = true; + that._slashCommandProvider = undefined; + that._followupProvider = undefined; + that._onDidReceiveFeedback.dispose(); that._proxy.$unregisterAgent(that._handle); }, } satisfies vscode.ChatAgent2; diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 55cde471a70..f92f0b4fc77 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4128,6 +4128,11 @@ export class ChatMessage implements vscode.ChatMessage { } } +export enum ChatAgentResultFeedbackKind { + Unhelpful = 0, + Helpful = 1, +} + //#endregion //#region ai diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index faa2d520396..e96cba918ef 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -105,6 +105,8 @@ export function registerChatCodeBlockActions() { const chatService = accessor.get(IChatService); chatService.notifyUserAction({ providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, action: { kind: 'copy', responseId: context.element.providerResponseId, @@ -146,6 +148,8 @@ export function registerChatCodeBlockActions() { const chatService = accessor.get(IChatService); chatService.notifyUserAction({ providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, action: { kind: 'copy', codeBlockIndex: context.codeBlockIndex, @@ -320,6 +324,8 @@ export function registerChatCodeBlockActions() { const chatService = accessor.get(IChatService); chatService.notifyUserAction({ providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, action: { kind: 'insert', responseId: context.element.providerResponseId, @@ -363,6 +369,8 @@ export function registerChatCodeBlockActions() { chatService.notifyUserAction({ providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, action: { kind: 'insert', responseId: context.element.providerResponseId, @@ -439,6 +447,8 @@ export function registerChatCodeBlockActions() { chatService.notifyUserAction({ providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, action: { kind: 'runInTerminal', responseId: context.element.providerResponseId, diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts index 6d7a399b006..b2c5828ece2 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts @@ -54,10 +54,12 @@ export function registerChatTitleActions() { const chatService = accessor.get(IChatService); chatService.notifyUserAction({ providerId: item.providerId, + agentId: item.agent?.id, + sessionId: item.sessionId, action: { kind: 'vote', direction: InteractiveSessionVoteDirection.Up, - responseId: item.providerResponseId + responseId: item.providerResponseId, } }); item.setVote(InteractiveSessionVoteDirection.Up); @@ -94,10 +96,12 @@ export function registerChatTitleActions() { const chatService = accessor.get(IChatService); chatService.notifyUserAction({ providerId: item.providerId, + agentId: item.agent?.id, + sessionId: item.sessionId, action: { kind: 'vote', direction: InteractiveSessionVoteDirection.Down, - responseId: item.providerResponseId + responseId: item.providerResponseId, } }); item.setVote(InteractiveSessionVoteDirection.Down); diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 84b9278cbc7..f4cd90ee8e4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -365,9 +365,11 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { this.chatService.notifyUserAction({ providerId: element.providerId, + agentId: element.agent?.id, + sessionId: element.sessionId, action: { kind: 'command', - command: followup + command: followup, } }); return this.commandService.executeCommand(followup.commandId, ...(followup.args ?? [])); diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index bdcb7101521..2d4dce54ed5 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -58,6 +58,7 @@ export interface IChatResponseModel { readonly username: string; readonly avatarIconUri?: URI; readonly session: IChatModel; + readonly agent?: IChatAgent; readonly response: IResponse; readonly isComplete: boolean; readonly isCanceled: boolean; diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index dacd94fd844..f71d8b7ae24 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -215,6 +215,8 @@ export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertActi export interface IChatUserActionEvent { action: ChatUserAction; providerId: string; + agentId: string | undefined; + sessionId: string; } export interface IChatDynamicRequest { diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index af03c838a71..eb3b8680044 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -535,7 +535,11 @@ export class ChatService extends Disposable implements IChatService { const agentResult = await this.chatAgentService.invokeAgent(agentPart.agent.id, requestProps, new Progress(p => { progressCallback(p); }), history, token); - rawResponse = { session: model.session!, errorDetails: agentResult.errorDetails, timings: agentResult.timings }; + rawResponse = { + session: model.session!, + errorDetails: agentResult.errorDetails, + timings: agentResult.timings + }; agentOrCommandFollowups = agentResult?.followUp ? Promise.resolve(agentResult.followUp) : this.chatAgentService.getFollowups(agentPart.agent.id, sessionId, CancellationToken.None); } else if (commandPart && typeof message === 'string' && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) { diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index 09aa29178b2..a80685c88fa 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -10,6 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; +import { IChatAgent } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatModelInitState, IChatModel, IChatRequestModel, IChatResponseModel, IChatWelcomeMessageContent, IResponse, Response } from 'vs/workbench/contrib/chat/common/chatModel'; import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChatReplyFollowup, IChatResponseCommandFollowup, IChatResponseErrorDetails, IChatResponseProgressFileTreeData, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; @@ -83,6 +84,7 @@ export interface IChatResponseViewModel { readonly providerResponseId: string | undefined; readonly username: string; readonly avatarIconUri?: URI; + readonly agent?: IChatAgent; readonly response: IResponse; readonly isComplete: boolean; readonly isCanceled: boolean; @@ -259,6 +261,10 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi return this._model.avatarIconUri; } + get agent() { + return this._model.agent; + } + get response(): IResponse { if (this._isPlaceholder) { return new Response(new MarkdownString(localize('thinking', "Thinking") + '\u2026')); diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 3724be62923..3ebf8b558b3 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -13,6 +13,7 @@ export const allApiProposals = Object.freeze({ chat: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chat.d.ts', chatAgents: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents.d.ts', chatAgents2: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents2.d.ts', + chatAgents2Additions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts', chatProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatProvider.d.ts', chatRequestAccess: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatRequestAccess.d.ts', chatVariables: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatVariables.d.ts', diff --git a/src/vscode-dts/vscode.proposed.chatAgents2.d.ts b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts index 830cb37a67c..879832237ec 100644 --- a/src/vscode-dts/vscode.proposed.chatAgents2.d.ts +++ b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts @@ -22,6 +22,16 @@ declare module 'vscode' { errorDetails?: ChatAgentErrorDetails; } + export enum ChatAgentResultFeedbackKind { + Unhelpful = 0, + Helpful = 1, + } + + export interface ChatAgentResult2Feedback { + readonly result: ChatAgentResult2; + readonly kind: ChatAgentResultFeedbackKind; + } + export interface ChatAgentSlashCommand { /** @@ -51,6 +61,8 @@ declare module 'vscode' { provideSlashCommands(token: CancellationToken): ProviderResult; } + // TODO@API is this just a vscode.Command? + // TODO@API what's the when-property for? how about not returning it in the first place? export interface ChatAgentCommandFollowup { commandId: string; args?: any[]; @@ -96,9 +108,14 @@ declare module 'vscode' { followupProvider?: FollowupProvider; - // TODO@API We need this- can't handle telemetry on the vscode side yet - // onDidPerformAction: Event<{ action: InteractiveSessionUserAction }>; - + /** + * An event that fires whenever feedback for a result is received, e.g. when a user up- or down-votes + * a result. + * + * The passed {@link ChatAgentResult2Feedback.result result} is guaranteed to be the same instance that was + * previously returned from this chat agent. + */ + onDidReceiveFeedback: Event; // TODO@API Something like prepareSession from the interactive chat provider might be needed.Probably nobody needs it right now. // prepareSession(); diff --git a/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts b/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts new file mode 100644 index 00000000000..3e132347354 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + export interface ChatAgentUserActionEvent { + readonly result: ChatAgentResult2; + readonly action: InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction; + } + + export interface ChatAgent2 { + + // TODO@API We need this- can't handle telemetry on the vscode side yet + onDidPerformAction: Event; + } +} From 269432689967846f79eccdcc44a8b5352c669613 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 13 Oct 2023 13:19:37 +0200 Subject: [PATCH 069/290] Comment does not preserve collapsed state (#195553) Fixes #195459 --- .../workbench/contrib/comments/browser/commentsController.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentsController.ts b/src/vs/workbench/contrib/comments/browser/commentsController.ts index 0ddb7dcd3d8..2eb6c4c38bb 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsController.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsController.ts @@ -1190,10 +1190,6 @@ export class CommentController implements IEditorContribution { pendingEdits = providerEditsCacheStore[thread.threadId!]; } - if (pendingComment || pendingEdits) { - thread.collapsibleState = languages.CommentThreadCollapsibleState.Expanded; - } - this.displayCommentThread(info.owner, thread, pendingComment, pendingEdits); }); for (const thread of info.pendingCommentThreads ?? []) { From ab1c7b42ef23be92fd3b205e750c0a5d47a44b08 Mon Sep 17 00:00:00 2001 From: vuittont60 <81072379+vuittont60@users.noreply.github.com> Date: Fri, 13 Oct 2023 20:28:15 +0800 Subject: [PATCH 070/290] fix typos --- extensions/emmet/src/test/tagActions.test.ts | 6 +++--- .../services/views/test/browser/viewContainerModel.test.ts | 6 +++--- src/vscode-dts/vscode.d.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/extensions/emmet/src/test/tagActions.test.ts b/extensions/emmet/src/test/tagActions.test.ts index c8680dd66f0..058e8985825 100644 --- a/extensions/emmet/src/test/tagActions.test.ts +++ b/extensions/emmet/src/test/tagActions.test.ts @@ -130,7 +130,7 @@ suite('Tests for Emmet actions on html tags', () => { // #endregion // #region remove tag - test('remove tag with mutliple cursors', () => { + test('remove tag with multiple cursors', () => { const expectedContents = `
    @@ -227,7 +227,7 @@ suite('Tests for Emmet actions on html tags', () => { // #endregion // #region split/join tag - test('split/join tag with mutliple cursors', () => { + test('split/join tag with multiple cursors', () => { const expectedContents = `
      @@ -328,7 +328,7 @@ suite('Tests for Emmet actions on html tags', () => { // #endregion // #region match tag - test('match tag with mutliple cursors', () => { + test('match tag with multiple cursors', () => { return withRandomFileEditor(contents, 'html', (editor, _) => { editor.selections = [ new Selection(1, 0, 1, 0), // just before tag starts, i.e before < diff --git a/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts b/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts index 3384bb67aa3..2a34154580b 100644 --- a/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts +++ b/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts @@ -605,7 +605,7 @@ suite('ViewContainerModel', () => { assert.strictEqual(testObject.visibleViewDescriptors.length, 0); })); - test('remove event is triggered properly if mutliple views are hidden at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { + test('remove event is triggered properly if multiple views are hidden at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: nls.localize2('test', 'test'), ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -663,7 +663,7 @@ suite('ViewContainerModel', () => { assert.strictEqual(target.elements[0].id, viewDescriptor1.id); })); - test('add event is triggered properly if mutliple views are hidden at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { + test('add event is triggered properly if multiple views are hidden at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: nls.localize2('test', 'test'), ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -731,7 +731,7 @@ suite('ViewContainerModel', () => { assert.strictEqual(target.elements[2].id, viewDescriptor3.id); })); - test('add and remove events are triggered properly if mutliple views are hidden and added at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { + test('add and remove events are triggered properly if multiple views are hidden and added at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: nls.localize2('test', 'test'), ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index f96413d1ae4..6303453c71a 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -1552,7 +1552,7 @@ declare module 'vscode' { */ with(change: { /** - * The new scheme, defauls to this Uri's scheme. + * The new scheme, defaults to this Uri's scheme. */ scheme?: string; /** From 5852e9ff3e8d6d5b5963981629abc461e0f03dfa Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 13 Oct 2023 17:02:43 +0200 Subject: [PATCH 071/290] tweak slash pill inside progress message (#195567) --- src/vs/workbench/contrib/inlineChat/browser/inlineChat.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css index 0fdfe7d2956..12d60096fcb 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css @@ -146,7 +146,7 @@ .monaco-editor .inline-chat .status .label .slash-command-pill CODE { border-radius: 3px; - padding: 1px; + padding: 0 1px; background-color: var(--vscode-chat-slashCommandBackground); color: var(--vscode-chat-slashCommandForeground); } From 8b3bc888da7d59f90684ae8c5a3415268a51f310 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Oct 2023 08:53:10 -0700 Subject: [PATCH 072/290] Remove unwanted logs --- src/vs/workbench/api/browser/mainThreadTerminalService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index a01feeb439a..9ac623649ac 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -231,7 +231,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $startSendingCommandEvents(): void { - this._logService.info('$startSendingCommandEvents'); if (this._sendCommandEventListener.value) { return; } @@ -250,7 +249,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $stopSendingCommandEvents(): void { - this._logService.info('$stopSendingCommandEvents'); this._sendCommandEventListener.clear(); } From e20515c62e9c502348faff4ef6d5c048d9357e2e Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Fri, 13 Oct 2023 09:01:12 -0700 Subject: [PATCH 073/290] Bump dependencies for debug sub-dependency (#195513) --- build/package.json | 2 +- build/yarn.lock | 36 +- package.json | 18 +- remote/package.json | 8 +- remote/yarn.lock | 108 +---- src/vs/platform/request/node/proxy.ts | 6 +- test/automation/yarn.lock | 6 +- test/leaks/yarn.lock | 6 +- test/smoke/yarn.lock | 6 +- yarn.lock | 617 +++++++++----------------- 10 files changed, 275 insertions(+), 538 deletions(-) diff --git a/build/package.json b/build/package.json index f3f365ac739..ca6b448b393 100644 --- a/build/package.json +++ b/build/package.json @@ -11,7 +11,7 @@ "@types/byline": "^4.2.32", "@types/cssnano": "^4.0.0", "@types/debounce": "^1.0.0", - "@types/debug": "4.1.5", + "@types/debug": "^4.1.5", "@types/fancy-log": "^1.3.0", "@types/fs-extra": "^9.0.12", "@types/glob": "^7.1.1", diff --git a/build/yarn.lock b/build/yarn.lock index 856b1c43957..f3dd7803415 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -400,10 +400,12 @@ resolved "https://registry.yarnpkg.com/@types/debounce/-/debounce-1.0.0.tgz#417560200331e1bb84d72da85391102c2fcd61b7" integrity sha1-QXVgIAMx4buE1y2oU5EQLC/NYbc= -"@types/debug@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" - integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== +"@types/debug@^4.1.5": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.9.tgz#906996938bc672aaf2fb8c0d3733ae1dda05b005" + integrity sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow== + dependencies: + "@types/ms" "*" "@types/events@*": version "1.2.0" @@ -533,6 +535,11 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== +"@types/ms@*": + version "0.7.32" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.32.tgz#f6cd08939ae3ad886fcc92ef7f0109dacddf61ab" + integrity sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g== + "@types/node-fetch@^2.5.0": version "2.5.8" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb" @@ -1116,10 +1123,10 @@ css-what@^6.1.0: resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== -debug@4, debug@^4.1.0, debug@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -1130,13 +1137,6 @@ debug@^2.6.8: dependencies: ms "2.0.0" -debug@^4.1.1, debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" @@ -1657,9 +1657,9 @@ http-proxy-agent@^4.0.1: debug "4" https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: agent-base "6" debug "4" diff --git a/package.json b/package.json index 6ec7ad15b97..306121e894e 100644 --- a/package.json +++ b/package.json @@ -70,8 +70,8 @@ "@parcel/watcher": "2.1.0", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/policy-watcher": "^1.1.4", - "@vscode/proxy-agent": "^0.17.4", - "@vscode/ripgrep": "^1.15.5", + "@vscode/proxy-agent": "^0.17.5", + "@vscode/ripgrep": "^1.15.6", "@vscode/spdlog": "^0.13.11", "@vscode/sqlite3": "5.1.6-vscode", "@vscode/sudo-prompt": "9.3.1", @@ -80,8 +80,8 @@ "@vscode/windows-process-tree": "^0.5.0", "@vscode/windows-registry": "^1.1.0", "graceful-fs": "4.2.11", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", "jschardet": "3.0.0", "kerberos": "^2.0.1", "minimist": "^1.2.6", @@ -111,7 +111,7 @@ "@swc/core": "1.3.62", "@types/cookie": "^0.3.3", "@types/cssnano": "^4.0.0", - "@types/debug": "4.1.5", + "@types/debug": "^4.1.5", "@types/graceful-fs": "4.1.2", "@types/gulp-postcss": "^8.0.0", "@types/gulp-svgmin": "^1.2.1", @@ -135,8 +135,8 @@ "@typescript-eslint/parser": "^5.57.0", "@vscode/gulp-electron": "^1.36.0", "@vscode/l10n-dev": "0.0.21", - "@vscode/telemetry-extractor": "^1.9.9", - "@vscode/test-web": "^0.0.41", + "@vscode/telemetry-extractor": "^1.9.10", + "@vscode/test-web": "^0.0.42", "@vscode/vscode-perf": "^0.0.14", "ansi-colors": "^3.2.3", "asar": "^3.0.3", @@ -187,8 +187,8 @@ "minimatch": "^3.0.4", "minimist": "^1.2.6", "mkdirp": "^1.0.4", - "mocha": "^9.2.2", - "mocha-junit-reporter": "^2.0.0", + "mocha": "^10.2.0", + "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", "npm-run-all": "^4.1.5", "opn": "^6.0.0", diff --git a/remote/package.json b/remote/package.json index f908503826a..b0cce32e568 100644 --- a/remote/package.json +++ b/remote/package.json @@ -7,16 +7,16 @@ "@microsoft/1ds-post-js": "^3.2.13", "@parcel/watcher": "2.1.0", "@vscode/iconv-lite-umd": "0.7.0", - "@vscode/proxy-agent": "^0.17.4", - "@vscode/ripgrep": "^1.15.5", + "@vscode/proxy-agent": "^0.17.5", + "@vscode/ripgrep": "^1.15.6", "@vscode/spdlog": "^0.13.11", "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.5.0", "@vscode/windows-registry": "^1.1.0", "cookie": "^0.4.0", "graceful-fs": "4.2.11", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", "jschardet": "3.0.0", "kerberos": "^2.0.1", "minimist": "^1.2.6", diff --git a/remote/yarn.lock b/remote/yarn.lock index 22094731621..0e4bdb1df9d 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -58,26 +58,26 @@ resolved "https://registry.yarnpkg.com/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz#d2f1e0664ee6036408f9743fee264ea0699b0e48" integrity sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg== -"@vscode/proxy-agent@^0.17.4": - version "0.17.4" - resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.17.4.tgz#e3ffb63357353a428436f15a69de3453a5061f0c" - integrity sha512-tX8eidofoJlZFRWzdiiW3wyu26hgIRk8HvM/RoP1wVSu3U/As36EgGIZYG6pPnqiythRqTcsddniVNA5M39g4w== +"@vscode/proxy-agent@^0.17.5": + version "0.17.5" + resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.17.5.tgz#a59f6087a39795425b2601c9ee95bcb0338154e6" + integrity sha512-plKfR1i9ce09aro1/yvK3Ckiu84Cj5ViuLqJ/7VRT6E9w5xP2YUPcgrCy+u7FGorKZmJb+wQ1L6f/cdJ7axulw== dependencies: "@tootallnate/once" "^3.0.0" agent-base "^7.0.1" debug "^4.3.4" http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.1" + https-proxy-agent "^7.0.2" socks-proxy-agent "^8.0.1" optionalDependencies: "@vscode/windows-ca-certs" "^0.3.1" -"@vscode/ripgrep@^1.15.5": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@vscode/ripgrep/-/ripgrep-1.15.5.tgz#26025884bbc3a8b40dfc29f5bda4b87b47bd7356" - integrity sha512-PVvKNEmtnlek3i4MJMaB910dz46CKQqcIY2gKR3PSlfz/ZPlSYuSuyQMS7iK20KL4hGUdSbWt964B5S5EIojqw== +"@vscode/ripgrep@^1.15.6": + version "1.15.6" + resolved "https://registry.yarnpkg.com/@vscode/ripgrep/-/ripgrep-1.15.6.tgz#17bdffc1fd0c4a034dc3e1e8203b8d07add96c0d" + integrity sha512-mCtfHqZ/g+75qDDeIPB9ST1xyJDaJornaSujuRKkB0SMZ6FMVtuKUdvvvOITR+DcKo5KOwUVuOUUpt75jOY+Yw== dependencies: - https-proxy-agent "^5.0.0" + https-proxy-agent "^7.0.2" proxy-from-env "^1.1.0" "@vscode/spdlog@^0.13.11": @@ -113,27 +113,6 @@ resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.1.0.tgz#03dace7c29c46f658588b9885b9580e453ad21f9" integrity sha512-5AZzuWJpGscyiMOed0IuyEwt6iKmV5Us7zuwCDCFYMIq7tsvooO9BUiciywsvuthGz6UG4LSpeDeCxvgMVhnIw== -agent-base@4: - version "4.2.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" - integrity sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg== - dependencies: - es6-promisify "^5.0.0" - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - dependencies: - es6-promisify "^5.0.0" - agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" @@ -192,21 +171,7 @@ cookie@^0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -debug@3.1.0, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@4: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -debug@^4.3.4: +debug@4, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -237,18 +202,6 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -es6-promise@^4.0.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" - integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -288,14 +241,6 @@ graceful-fs@4.2.11: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy-agent@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" @@ -304,26 +249,10 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" -https-proxy-agent@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - -https-proxy-agent@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab" - integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ== +https-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== dependencies: agent-base "^7.0.2" debug "4" @@ -416,12 +345,7 @@ mkdirp@^0.5.5: dependencies: minimist "^1.2.6" -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2, ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== diff --git a/src/vs/platform/request/node/proxy.ts b/src/vs/platform/request/node/proxy.ts index ee2aae8814b..db448e06cc1 100644 --- a/src/vs/platform/request/node/proxy.ts +++ b/src/vs/platform/request/node/proxy.ts @@ -39,12 +39,12 @@ export async function getProxyAgent(rawRequestURL: string, env: typeof process.e const opts = { host: proxyEndpoint.hostname || '', - port: proxyEndpoint.port || (proxyEndpoint.protocol === 'https' ? '443' : '80'), + port: (proxyEndpoint.port ? +proxyEndpoint.port : 0) || (proxyEndpoint.protocol === 'https' ? 443 : 80), auth: proxyEndpoint.auth, rejectUnauthorized: isBoolean(options.strictSSL) ? options.strictSSL : true, }; return requestURL.protocol === 'http:' - ? new (await import('http-proxy-agent'))(opts as any as Url) - : new (await import('https-proxy-agent'))(opts); + ? new (await import('http-proxy-agent')).HttpProxyAgent(proxyURL, opts) + : new (await import('https-proxy-agent')).HttpsProxyAgent(proxyURL, opts); } diff --git a/test/automation/yarn.lock b/test/automation/yarn.lock index d8bc5440797..debf88d613c 100644 --- a/test/automation/yarn.lock +++ b/test/automation/yarn.lock @@ -130,9 +130,9 @@ debounce@^1.2.0: integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== debug@^4.1.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" diff --git a/test/leaks/yarn.lock b/test/leaks/yarn.lock index d1fa87793a9..ba64535793a 100644 --- a/test/leaks/yarn.lock +++ b/test/leaks/yarn.lock @@ -56,9 +56,9 @@ debug@^3.1.0: ms "^2.1.1" debug@^4.0.1, debug@^4.1.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index c08c24a1ddd..a50041b4bde 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -171,9 +171,9 @@ cross-spawn@^6.0.5: which "^1.2.9" debug@4: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" diff --git a/yarn.lock b/yarn.lock index af7cd277b64..bfdcd2d03d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -806,14 +806,14 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== -"@ts-morph/common@~0.16.0": - version "0.16.0" - resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.16.0.tgz#57e27d4b3fd65a4cd72cb36679ed08acb40fa3ba" - integrity sha512-SgJpzkTgZKLKqQniCjLaE3c2L2sdL7UShvmTmPBejAKd2OKV/yfMpQ2IWpAuA+VY5wy7PkSUaEObIqEK6afFuw== +"@ts-morph/common@~0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.20.0.tgz#3f161996b085ba4519731e4d24c35f6cba5b80af" + integrity sha512-7uKjByfbPpwuzkstL3L5MQyuXPSKdoNG93Fmi2JoDcTf3pEP731JdRFAduRVkOs8oqxPsXKA+ScrWkdQ8t/I+Q== dependencies: - fast-glob "^3.2.11" - minimatch "^5.1.0" - mkdirp "^1.0.4" + fast-glob "^3.2.12" + minimatch "^7.4.3" + mkdirp "^2.1.6" path-browserify "^1.0.1" "@tsconfig/node10@^1.0.7": @@ -870,10 +870,12 @@ dependencies: postcss "5 - 7" -"@types/debug@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" - integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== +"@types/debug@^4.1.5": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.9.tgz#906996938bc672aaf2fb8c0d3733ae1dda05b005" + integrity sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow== + dependencies: + "@types/ms" "*" "@types/eslint-scope@^3.7.3": version "3.7.4" @@ -997,6 +999,11 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== +"@types/ms@*": + version "0.7.32" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.32.tgz#f6cd08939ae3ad886fcc92ef7f0109dacddf61ab" + integrity sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g== + "@types/node-fetch@^2.5.0": version "2.5.12" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" @@ -1220,11 +1227,6 @@ "@typescript-eslint/types" "5.57.0" eslint-visitor-keys "^3.3.0" -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - "@vscode/gulp-electron@^1.36.0": version "1.36.0" resolved "https://registry.yarnpkg.com/@vscode/gulp-electron/-/gulp-electron-1.36.0.tgz#b2895c4bafaa0cf2b13042aa654e9fdd1f3a90cd" @@ -1273,34 +1275,26 @@ bindings "^1.5.0" node-addon-api "^6.0.0" -"@vscode/proxy-agent@^0.17.4": - version "0.17.4" - resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.17.4.tgz#e3ffb63357353a428436f15a69de3453a5061f0c" - integrity sha512-tX8eidofoJlZFRWzdiiW3wyu26hgIRk8HvM/RoP1wVSu3U/As36EgGIZYG6pPnqiythRqTcsddniVNA5M39g4w== +"@vscode/proxy-agent@^0.17.5": + version "0.17.5" + resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.17.5.tgz#a59f6087a39795425b2601c9ee95bcb0338154e6" + integrity sha512-plKfR1i9ce09aro1/yvK3Ckiu84Cj5ViuLqJ/7VRT6E9w5xP2YUPcgrCy+u7FGorKZmJb+wQ1L6f/cdJ7axulw== dependencies: "@tootallnate/once" "^3.0.0" agent-base "^7.0.1" debug "^4.3.4" http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.1" + https-proxy-agent "^7.0.2" socks-proxy-agent "^8.0.1" optionalDependencies: "@vscode/windows-ca-certs" "^0.3.1" -"@vscode/ripgrep@^1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@vscode/ripgrep/-/ripgrep-1.15.0.tgz#d6fec68d7c44d594967f21a6e6c97416cc7fb2bc" - integrity sha512-qbLYP3XPTfS5a80+WnGvDLhsD01LDrs03zjbbtWWnvwt8G9hP3j8mc3ckaIid7pj86MBSTyUb/ECaIWmJIGBYw== +"@vscode/ripgrep@^1.15.6": + version "1.15.6" + resolved "https://registry.yarnpkg.com/@vscode/ripgrep/-/ripgrep-1.15.6.tgz#17bdffc1fd0c4a034dc3e1e8203b8d07add96c0d" + integrity sha512-mCtfHqZ/g+75qDDeIPB9ST1xyJDaJornaSujuRKkB0SMZ6FMVtuKUdvvvOITR+DcKo5KOwUVuOUUpt75jOY+Yw== dependencies: - https-proxy-agent "^5.0.0" - proxy-from-env "^1.1.0" - -"@vscode/ripgrep@^1.15.5": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@vscode/ripgrep/-/ripgrep-1.15.5.tgz#26025884bbc3a8b40dfc29f5bda4b87b47bd7356" - integrity sha512-PVvKNEmtnlek3i4MJMaB910dz46CKQqcIY2gKR3PSlfz/ZPlSYuSuyQMS7iK20KL4hGUdSbWt964B5S5EIojqw== - dependencies: - https-proxy-agent "^5.0.0" + https-proxy-agent "^7.0.2" proxy-from-env "^1.1.0" "@vscode/spdlog@^0.13.11": @@ -1325,33 +1319,33 @@ resolved "https://registry.yarnpkg.com/@vscode/sudo-prompt/-/sudo-prompt-9.3.1.tgz#c562334bc6647733649fd42afc96c0eea8de3b65" integrity sha512-9ORTwwS74VaTn38tNbQhsA5U44zkJfcb0BdTSyyG6frP4e8KMtHuTXYmwefe5dpL8XB1aGSIVTaLjD3BbWb5iA== -"@vscode/telemetry-extractor@^1.9.9": - version "1.9.9" - resolved "https://registry.yarnpkg.com/@vscode/telemetry-extractor/-/telemetry-extractor-1.9.9.tgz#fe1029a58181287d6ab809aae26ee877f181536c" - integrity sha512-nWuXoyXvuS1VBM+U2UQUxUC9fjkquD5QBOv1FlpVkzY+n9hJQ/G4woJdSsOdNgEKnOMUFUSByg8Bl52E4YakKw== +"@vscode/telemetry-extractor@^1.9.10": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@vscode/telemetry-extractor/-/telemetry-extractor-1.10.1.tgz#15c6fff544e8b99b2b79454887b3e5d3f0df9d2f" + integrity sha512-oiEfGQ9CxfzbhipivSxV2obmi3CaYLoiJv8CaPRynSNdH4VyZuTyL3j9VJBBNjyrxdlo5wXWC/ovwWBT8hEMng== dependencies: - "@vscode/ripgrep" "^1.15.0" + "@vscode/ripgrep" "^1.15.6" command-line-args "^5.2.1" - ts-morph "^15.1.0" + ts-morph "^19.0.0" -"@vscode/test-web@^0.0.41": - version "0.0.41" - resolved "https://registry.yarnpkg.com/@vscode/test-web/-/test-web-0.0.41.tgz#851b98d80a7839f6b95c48fc6e6d8a76fb09c479" - integrity sha512-+P1Ji+ulXM0NWVdDq1e9DtvGCMWA/HiUDbSCSrvSjtM5hv3PwK/FCYOtJQgLIfB/BwmFuKaa7hNIT3hejoELJg== +"@vscode/test-web@^0.0.42": + version "0.0.42" + resolved "https://registry.yarnpkg.com/@vscode/test-web/-/test-web-0.0.42.tgz#c69449ca6974c5052d4d89a0068e14ff32f8ebe4" + integrity sha512-9D4SaV9wHHUaF3h60D4wNzILSuoW4/9kcB2ufnKnmY494D/a7U4d6mPhgi+K20pRaAQ/oYJ3qQu2GgyrpU+zcQ== dependencies: "@koa/cors" "^4.0.0" "@koa/router" "^12.0.0" - decompress "^4.2.1" - decompress-targz "^4.1.1" get-stream "6.0.1" + gunzip-maybe "^1.4.2" http-proxy-agent "^5.0.0" https-proxy-agent "^5.0.1" - koa "^2.14.1" + koa "^2.14.2" koa-morgan "^1.0.1" koa-mount "^4.0.0" koa-static "^5.0.0" minimist "^1.2.8" - playwright "^1.32.2" + playwright "^1.32.3" + tar-fs "^2.1.1" vscode-uri "^3.0.7" "@vscode/vscode-languagedetection@1.0.21": @@ -1592,13 +1586,6 @@ acorn@^8.7.1, acorn@^8.8.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== -agent-base@4: - version "4.2.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" - integrity sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg== - dependencies: - es6-promisify "^5.0.0" - agent-base@6: version "6.0.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.1.tgz#808007e4e5867decb0ab6ab2f928fbdb5a596db4" @@ -1606,13 +1593,6 @@ agent-base@6: dependencies: debug "4" -agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - dependencies: - es6-promisify "^5.0.0" - agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" @@ -2076,14 +2056,6 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" - integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - bl@^4.0.2, bl@^4.0.3: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -2153,6 +2125,13 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browserify-zlib@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + integrity sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ== + dependencies: + pako "~0.2.0" + browserslist@^4.0.0, browserslist@^4.14.5: version "4.16.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" @@ -2174,19 +2153,6 @@ browserslist@^4.20.2: node-releases "^2.0.6" update-browserslist-db "^1.0.5" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -2197,17 +2163,12 @@ buffer-equal@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -2382,10 +2343,10 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -charenc@~0.0.1: +charenc@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== chokidar@3.5.3: version "3.5.3" @@ -2587,12 +2548,10 @@ coa@^2.0.2: chalk "^2.4.1" q "^1.1.2" -code-block-writer@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-11.0.0.tgz#5956fb186617f6740e2c3257757fea79315dd7d4" - integrity sha512-GEqWvEWWsOvER+g9keO4ohFoD3ymwyCnqY3hoTr7GZipYFwEhMHJw+TtV0rfgRhNImM6QWZGO2XYjlJVyYT62w== - dependencies: - tslib "2.3.1" +code-block-writer@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770" + integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w== code-point-at@^1.0.0: version "1.1.0" @@ -2698,7 +2657,7 @@ commander@2.11.x: resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== -commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@^2.8.1: +commander@^2.11.0, commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2865,10 +2824,10 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypt@~0.0.1: +crypt@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== css-color-names@0.0.4, css-color-names@^0.0.4: version "0.0.4" @@ -3075,49 +3034,14 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@3.X: +debug@3.X, debug@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@4: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -debug@4.3.3, debug@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - -debug@^4.3.4: +debug@4, debug@4.3.4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -3146,59 +3070,6 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" -decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - -decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - -decompress-targz@^4.0.0, decompress-targz@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - -decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" - integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.0.0" - deemon@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/deemon/-/deemon-1.8.0.tgz#7b9498905634a89bfe6db11b5edf779e2fac5248" @@ -3435,7 +3306,7 @@ duplexer@^0.1.1, duplexer@~0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= -duplexify@^3.6.0: +duplexify@^3.5.0, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== @@ -3645,18 +3516,6 @@ es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" -es6-promise@^4.0.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" - integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - es6-symbol@^3.1.1, es6-symbol@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" @@ -4089,6 +3948,17 @@ fast-glob@^3.2.11, fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.2.12: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -4159,21 +4029,6 @@ file-loader@^6.2.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= - -file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha1-LdvqfHP/42No365J3DOMBYwritY= - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -4480,14 +4335,6 @@ get-stream@6.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -4741,11 +4588,6 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -graceful-fs@^4.1.10: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - graceful-fs@^4.1.2, graceful-fs@^4.2.4: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" @@ -4761,11 +4603,6 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - gulp-azure-storage@^0.12.1: version "0.12.1" resolved "https://registry.yarnpkg.com/gulp-azure-storage/-/gulp-azure-storage-0.12.1.tgz#be2be1268af7dea6fdf56045b3eb3f090335de4a" @@ -4998,6 +4835,18 @@ gulplog@^1.0.0: dependencies: glogg "^1.0.0" +gunzip-maybe@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac" + integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw== + dependencies: + browserify-zlib "^0.1.4" + is-deflate "^1.0.0" + is-gzip "^1.0.0" + peek-stream "^1.1.0" + pumpify "^1.3.3" + through2 "^2.0.3" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -5157,14 +5006,6 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -5190,22 +5031,6 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" -https-proxy-agent@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -5214,10 +5039,10 @@ https-proxy-agent@^5.0.1: agent-base "6" debug "4" -https-proxy-agent@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab" - integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ== +https-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== dependencies: agent-base "^7.0.2" debug "4" @@ -5443,7 +5268,7 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.1.5, is-buffer@~1.1.1: +is-buffer@^1.1.5, is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -5517,6 +5342,11 @@ is-date-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== +is-deflate@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14" + integrity sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ== + is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -5600,10 +5430,10 @@ is-glob@^4.0.3: dependencies: is-extglob "^2.1.1" -is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= +is-gzip@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83" + integrity sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ== is-negated-glob@^1.0.0: version "1.0.0" @@ -6045,10 +5875,10 @@ koa-static@^5.0.0: debug "^3.1.0" koa-send "^5.0.0" -koa@^2.14.1: - version "2.14.1" - resolved "https://registry.yarnpkg.com/koa/-/koa-2.14.1.tgz#defb9589297d8eb1859936e777f3feecfc26925c" - integrity sha512-USJFyZgi2l0wDgqkfD27gL4YGno7TfUkcmOe6UOLFOVuN+J7FwnNu4Dydl4CUQzraM1lBAiGed0M9OVJoT0Kqw== +koa@^2.14.2: + version "2.14.2" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.14.2.tgz#a57f925c03931c2b4d94b19d2ebf76d3244863fc" + integrity sha512-VFI2bpJaodz6P7x2uyLiX6RLYpZmOJqNmoCst/Yyd7hQlszyPwG/I9CQJ63nOtKSxpt5M7NH67V6nJL2BwCl7g== dependencies: accepts "^1.3.5" cache-content-type "^1.0.0" @@ -6290,13 +6120,6 @@ lru-queue@^0.1.0: dependencies: es5-ext "~0.10.2" -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - make-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.0.tgz#1b5f39f6b9270ed33f9f054c5c0f84304989f801" @@ -6362,14 +6185,14 @@ matcher@^3.0.0: dependencies: escape-string-regexp "^4.0.0" -md5@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" - integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== dependencies: - charenc "~0.0.1" - crypt "~0.0.1" - is-buffer "~1.1.1" + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" mdn-data@2.0.14: version "2.0.14" @@ -6560,20 +6383,27 @@ mimic-response@^3.1.0: dependencies: brace-expansion "^1.1.7" -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" -minimatch@^5.0.1, minimatch@^5.1.0: +minimatch@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== dependencies: brace-expansion "^2.0.1" +minimatch@^7.4.3: + version "7.4.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb" + integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" @@ -6631,16 +6461,26 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mocha-junit-reporter@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.0.0.tgz#3bf990fce7a42c0d2b718f188553a25d9f24b9a2" - integrity sha512-20HoWh2HEfhqmigfXOKUhZQyX23JImskc37ZOhIjBKoBEsb+4cAFRJpAVhFpnvsztLklW/gFVzsrobjLwmX4lA== +mkdirp@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== + +mkdirp@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + +mocha-junit-reporter@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.2.1.tgz#739f5595d0f051d07af9d74e32c416e13a41cde5" + integrity sha512-iDn2tlKHn8Vh8o4nCzcUVW4q7iXp7cC4EB78N0cDHIobLymyHNwe0XG8HEHHjc3hJlXm0Vy6zcrxaIhnI2fWmw== dependencies: - debug "^2.2.0" - md5 "^2.1.0" - mkdirp "~0.5.1" - strip-ansi "^4.0.0" - xml "^1.0.0" + debug "^4.3.4" + md5 "^2.3.0" + mkdirp "^3.0.0" + strip-ansi "^6.0.1" + xml "^1.0.1" mocha-multi-reporters@^1.5.1: version "1.5.1" @@ -6650,32 +6490,29 @@ mocha-multi-reporters@^1.5.1: debug "^4.1.1" lodash "^4.17.15" -mocha@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" - integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== +mocha@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== dependencies: - "@ungap/promise-all-settled" "1.1.2" ansi-colors "4.1.1" browser-stdout "1.3.1" chokidar "3.5.3" - debug "4.3.3" + debug "4.3.4" diff "5.0.0" escape-string-regexp "4.0.0" find-up "5.0.0" glob "7.2.0" - growl "1.10.5" he "1.2.0" js-yaml "4.1.0" log-symbols "4.1.0" - minimatch "4.2.1" + minimatch "5.0.1" ms "2.1.3" - nanoid "3.3.1" + nanoid "3.3.3" serialize-javascript "6.0.0" strip-json-comments "3.1.1" supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" + workerpool "6.2.1" yargs "16.2.0" yargs-parser "20.2.4" yargs-unparser "2.0.0" @@ -6736,10 +6573,10 @@ nan@^2.17.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== -nanoid@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== nanoid@^3.3.4: version "3.3.6" @@ -7263,6 +7100,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -7418,6 +7260,15 @@ pause-stream@0.0.11, pause-stream@^0.0.11: dependencies: through "~2.3" +peek-stream@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67" + integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA== + dependencies: + buffer-from "^1.0.0" + duplexify "^3.5.0" + through2 "^2.0.3" + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -7453,7 +7304,7 @@ pidtree@^0.3.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== -pify@^2.0.0, pify@^2.3.0: +pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== @@ -7487,16 +7338,16 @@ playwright-core@1.30.0: resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.30.0.tgz#de987cea2e86669e3b85732d230c277771873285" integrity sha512-7AnRmTCf+GVYhHbLJsGUtskWTE33SwMZkybJ0v6rqR1boxq2x36U7p1vDRV7HO2IwTZgmycracLxPEJI49wu4g== -playwright-core@1.32.2: - version "1.32.2" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.32.2.tgz#608810c3c4486fb86a224732ac0d3560a96ded8b" - integrity sha512-zD7aonO+07kOTthsrCR3YCVnDcqSHIJpdFUtZEMOb6//1Rc7/6mZDRdw+nlzcQiQltOOsiqI3rrSyn/SlyjnJQ== - playwright-core@1.37.1: version "1.37.1" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.37.1.tgz#cb517d52e2e8cb4fa71957639f1cd105d1683126" integrity sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA== +playwright-core@1.39.0: + version "1.39.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.39.0.tgz#efeaea754af4fb170d11845b8da30b2323287c63" + integrity sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw== + playwright@^1.29.2: version "1.30.0" resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.30.0.tgz#b1d7be2d45d97fbb59f829f36f521f12010fe072" @@ -7504,12 +7355,14 @@ playwright@^1.29.2: dependencies: playwright-core "1.30.0" -playwright@^1.32.2: - version "1.32.2" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.32.2.tgz#9f5a510274c74d87128f7edfb709016a1f957e01" - integrity sha512-jHVnXJke0PXpuPszKtk9y1zZSlzO5+2a+aockT/AND0oeXx46FiJEFrafthurglLygVZA+1gEbtUM1C7qtTV+Q== +playwright@^1.32.3: + version "1.39.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.39.0.tgz#184c81cd6478f8da28bcd9e60e94fcebf566e077" + integrity sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw== dependencies: - playwright-core "1.32.2" + playwright-core "1.39.0" + optionalDependencies: + fsevents "2.3.2" plist@^3.0.1: version "3.0.5" @@ -7997,7 +7850,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.5: +pumpify@^1.3.3, pumpify@^1.3.5: version "1.5.1" resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== @@ -8107,7 +7960,7 @@ read-pkg@^3.0.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -8434,7 +8287,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -8484,13 +8337,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" -seek-bzip@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" - integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== - dependencies: - commander "^2.8.1" - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -9075,13 +8921,6 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -9211,7 +9050,7 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== -tar-fs@^2.0.0: +tar-fs@^2.0.0, tar-fs@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -9221,19 +9060,6 @@ tar-fs@^2.0.0: pump "^3.0.0" tar-stream "^2.1.4" -tar-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - tar-stream@^2.1.4: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" @@ -9402,11 +9228,6 @@ to-absolute-glob@^2.0.0: is-absolute "^1.0.0" is-negated-glob "^1.0.0" -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -9486,13 +9307,13 @@ ts-loader@^9.4.2: micromatch "^4.0.0" semver "^7.3.4" -ts-morph@^15.1.0: - version "15.1.0" - resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-15.1.0.tgz#53deea5296d967ff6eba8f15f99d378aa7074a4e" - integrity sha512-RBsGE2sDzUXFTnv8Ba22QfeuKbgvAGJFuTN7HfmIRUkgT/NaVLfDM/8OFm2NlFkGlWEXdpW5OaFIp1jvqdDuOg== +ts-morph@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-19.0.0.tgz#43e95fb0156c3fe3c77c814ac26b7d0be2f93169" + integrity sha512-D6qcpiJdn46tUqV45vr5UGM2dnIEuTGNxVhg0sk5NX11orcouwj6i1bMqZIz2mZTZB1Hcgy7C3oEVhAT+f6mbQ== dependencies: - "@ts-morph/common" "~0.16.0" - code-block-writer "^11.0.0" + "@ts-morph/common" "~0.20.0" + code-block-writer "^12.0.0" ts-node@^10.9.1: version "10.9.1" @@ -9521,11 +9342,6 @@ tsec@0.2.7: glob "^7.1.1" minimatch "^3.0.3" -tslib@2.3.1, tslib@^2.0.0, tslib@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - tslib@^1.8.1: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -9536,6 +9352,11 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0, tslib@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -9640,14 +9461,6 @@ typical@^4.0.0: resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== -unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - unc-path-regex@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" @@ -10144,13 +9957,6 @@ which-typed-array@^1.1.11, which-typed-array@^1.1.2: gopd "^1.0.1" has-tostringtag "^1.0.0" -which@2.0.2, which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - which@^1.2.14, which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -10158,6 +9964,13 @@ which@^1.2.14, which@^1.2.9: dependencies: isexe "^2.0.0" +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + wildcard@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" @@ -10173,10 +9986,10 @@ word-wrap@^1.2.3, word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== wrap-ansi@^2.0.0: version "2.1.0" @@ -10246,10 +10059,10 @@ xml2js@^0.5.0: sax ">=0.6.0" xmlbuilder "~11.0.0" -xml@^1.0.0: +xml@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" - integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== xmlbuilder@^9.0.7: version "9.0.7" @@ -10261,11 +10074,6 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== -xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - xtend@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" @@ -10273,6 +10081,11 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" +xtend@~4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + xterm-addon-canvas@0.6.0-beta.27: version "0.6.0-beta.27" resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.27.tgz#2517f050d165b093a3c3e564e4420ccc3ccbad75" @@ -10471,7 +10284,7 @@ yaserver@^0.4.0: resolved "https://registry.yarnpkg.com/yaserver/-/yaserver-0.4.0.tgz#71b5fc53fb14c0f241d2dcfb3910707feeb619da" integrity sha512-98Vj4sgqB1fLcpf2wK7h3dFCaabISHU9CXZHaAx3QLkvTTCD31MzMcNbw5V5jZFBK7ffkFqfWig6B20KQt4wtA== -yauzl@^2.10.0, yauzl@^2.4.2, yauzl@^2.9.2: +yauzl@^2.10.0, yauzl@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= From 77ed7186a34b92521bd66a51a8588492e1a6dfce Mon Sep 17 00:00:00 2001 From: David Dossett Date: Fri, 13 Oct 2023 09:21:38 -0700 Subject: [PATCH 074/290] Remove duplicated border --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index c4e73897ca1..683eec1507e 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -467,7 +467,7 @@ .interactive-response-progress-tree .monaco-list, .chat-used-context-list .monaco-list { - border: 1px solid var(--vscode-input-border, transparent); + border: none; border-radius: 4px; width: auto; } From a82ba5f0a4d5ebf9019f7981d87a213c4c910a79 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 09:27:29 -0700 Subject: [PATCH 075/290] fix issue --- .../accessibility/browser/accessibleNotificationService.ts | 2 +- src/vs/platform/accessibility/common/accessibility.ts | 2 +- .../accessibility/browser/accessibility.contribution.ts | 3 +++ .../contrib/audioCues/browser/audioCues.contribution.ts | 2 +- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 +- src/vs/workbench/workbench.web.main.ts | 4 +--- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts index 836cf2e09ad..28986f44188 100644 --- a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts +++ b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts @@ -29,7 +29,7 @@ export class AccessibleNotificationService extends Disposable implements IAccess } } -export class TestAccessibleNotificationService implements IAccessibleNotificationService { +export class TestAccessibleNotificationService extends Disposable implements IAccessibleNotificationService { declare readonly _serviceBrand: undefined; diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index 71192169845..d8b0df4eb0c 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -47,6 +47,7 @@ export function isAccessibilityInformation(obj: any): obj is IAccessibilityInfor && (typeof obj.role === 'undefined' || typeof obj.role === 'string'); } +export const IAccessibleNotificationService = createDecorator('accessibleNotificationService'); /** * Manages whether an audio cue or an aria alert will be used * in response to actions taken around the workbench. @@ -57,4 +58,3 @@ export interface IAccessibleNotificationService { notifyCleared(): void; } -export const IAccessibleNotificationService = createDecorator('accessibleNotificationService'); diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibility.contribution.ts b/src/vs/workbench/contrib/accessibility/browser/accessibility.contribution.ts index efc4a052f46..5d513a9be9a 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibility.contribution.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibility.contribution.ts @@ -13,9 +13,12 @@ import { UnfocusedViewDimmingContribution } from 'vs/workbench/contrib/accessibi import { EditorAccessibilityHelpContribution, HoverAccessibleViewContribution, InlineCompletionsAccessibleViewContribution, NotificationAccessibleViewContribution } from 'vs/workbench/contrib/accessibility/browser/accessibilityContributions'; import { AccessibilityStatus } from 'vs/workbench/contrib/accessibility/browser/accessibilityStatus'; import { CommentsAccessibilityHelpContribution } from 'vs/workbench/contrib/comments/browser/comments.contribution'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { AccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; registerAccessibilityConfiguration(); registerSingleton(IAccessibleViewService, AccessibleViewService, InstantiationType.Delayed); +registerSingleton(IAccessibleNotificationService, AccessibleNotificationService, InstantiationType.Delayed); const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(EditorAccessibilityHelpContribution, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 22a4a7e390b..369a1668f97 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -133,7 +133,7 @@ Registry.as(ConfigurationExtensions.Configuration).regis default: 'off' }, 'audioCues.clear': { - 'description': localize('audioCues.clear', "Plays a sound when a feature is cleared (for example, the terminal, debug console, or output channel)."), + 'description': localize('audioCues.clear', "Plays a sound when a feature is cleared (for example, the terminal, debug console, or output channel). When this is disabled, an aria alert will announce 'Cleared'."), ...audioCueFeatureBase, default: 'off' }, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 467a5190c30..a7c08bc63d8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -355,7 +355,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { @IOpenerService private readonly _openerService: IOpenerService, @ICommandService private readonly _commandService: ICommandService, @IAudioCueService private readonly _audioCueService: IAudioCueService, - @IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService, + @IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService ) { super(); diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index dbc49cb9dd7..c61a78d6fc1 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -66,7 +66,7 @@ import 'vs/platform/extensionResourceLoader/browser/extensionResourceLoaderServi import 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -93,7 +93,6 @@ import { WebLanguagePacksService } from 'vs/platform/languagePacks/browser/langu registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, InstantiationType.Delayed); registerSingleton(IAccessibilityService, AccessibilityService, InstantiationType.Delayed); -registerSingleton(IAccessibleNotificationService, AccessibleNotificationService, InstantiationType.Delayed); registerSingleton(IContextMenuService, ContextMenuService, InstantiationType.Delayed); registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService, InstantiationType.Delayed); registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, InstantiationType.Delayed); @@ -182,7 +181,6 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { AccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; export { From 9085a2cc0bc576ac6e908e3e717be1b9693083b0 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 10:09:45 -0700 Subject: [PATCH 076/290] don't leak disposable --- .../accessibility/test/browser/bufferContentTracker.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index 417eb6d9028..cfe91ea6d7d 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -67,7 +67,7 @@ suite('Buffer Content Tracker', () => { instantiationService.stub(IContextMenuService, store.add(instantiationService.createInstance(ContextMenuService))); instantiationService.stub(ILifecycleService, store.add(new TestLifecycleService())); instantiationService.stub(IContextKeyService, store.add(new MockContextKeyService())); - instantiationService.stub(IAccessibleNotificationService, new TestAccessibleNotificationService()); + instantiationService.stub(IAccessibleNotificationService, store.add(new TestAccessibleNotificationService())); configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper)); capabilities = store.add(new TerminalCapabilityStore()); if (!isWindows) { From 4efeb37cc34ba648c03a8eeb565c8bc55de16165 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Fri, 13 Oct 2023 10:18:48 -0700 Subject: [PATCH 077/290] fix: raise chat agent execution timeout (#195575) --- src/vs/workbench/api/common/extHostChatAgents2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index bd48108cd4a..13a6b7d6b85 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -63,7 +63,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { const commandExecution = new DeferredPromise(); token.onCancellationRequested(() => commandExecution.complete()); - setTimeout(() => commandExecution.complete(), 3 * 1000); + setTimeout(() => commandExecution.complete(), 10 * 1000); this._extHostChatProvider.allowListExtensionWhile(agent.extension.identifier, commandExecution.p); const slashCommand = request.command From c488899ee341e927b4e1c7b4eda489d471d2c9ba Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 10:37:31 -0700 Subject: [PATCH 078/290] Show "used references" at the top of the response --- .../contrib/chat/browser/chatListRenderer.ts | 33 +++++++++++++++---- .../contrib/chat/browser/chatWidget.ts | 4 ++- .../contrib/chat/common/chatModel.ts | 17 +++++----- .../contrib/chat/common/chatViewModel.ts | 25 ++++++++++++-- 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index d37fa7c8286..b2744d7ca7d 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -85,6 +85,7 @@ interface IChatListItemTemplate { avatar: HTMLElement; username: HTMLElement; value: HTMLElement; + referencesListContainer: HTMLElement; contextKeyService: IContextKeyService; templateDisposables: IDisposable; elementDisposables: DisposableStore; @@ -233,6 +234,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { if (!partToRender) { @@ -527,6 +540,12 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer; readonly usedContext: IUsedContext | undefined; readonly contentReferences: ReadonlyArray; - onDidChangeValue: Event; - updateContent(responsePart: ResponsePart, quiet?: boolean): void; asString(): string; } @@ -161,16 +159,18 @@ export class Response implements IResponse { const responsePartLength = this._responseParts.length - 1; const lastResponsePart = this._responseParts[responsePartLength]; - if ('inlineReference' in lastResponsePart || lastResponsePart.isPlaceholder === true || isCompleteInteractiveProgressTreeData(lastResponsePart)) { + if (lastResponsePart && ('inlineReference' in lastResponsePart || lastResponsePart.isPlaceholder === true || isCompleteInteractiveProgressTreeData(lastResponsePart))) { // The last part is resolving or a tree data item, start a new part this._responseParts.push({ string: typeof responsePart === 'string' ? new MarkdownString(responsePart) : responsePart }); - } else { + } else if (lastResponsePart) { // Combine this part with the last, non-resolving string part if (isMarkdownString(responsePart)) { this._responseParts[responsePartLength] = { string: new MarkdownString(lastResponsePart.string.value + responsePart.value, responsePart) }; } else { this._responseParts[responsePartLength] = { string: new MarkdownString(lastResponsePart.string.value + responsePart, lastResponsePart.string) }; } + } else { + this._responseParts.push({ string: isMarkdownString(responsePart) ? responsePart : new MarkdownString(responsePart) }); } this._updateRepr(quiet); @@ -199,6 +199,7 @@ export class Response implements IResponse { this._usedContext = responsePart; } else if ('reference' in responsePart) { this._contentReferences.push(responsePart); + this._onDidChangeValue.fire(); } else if ('inlineReference' in responsePart) { this._responseParts.push(responsePart); this._updateRepr(quiet); @@ -265,7 +266,7 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel return this._followups; } - private _response: IResponse; + private _response: Response; public get response(): IResponse { return this._response; } @@ -650,7 +651,7 @@ export class ChatModel extends Disposable implements IChatModel { } const request = new ChatRequestModel(this, message); - request.response = new ChatResponseModel(new MarkdownString(''), this, chatAgent); + request.response = new ChatResponseModel([], this, chatAgent); this._requests.push(request); this._onDidChange.fire({ kind: 'addRequest', request }); @@ -663,7 +664,7 @@ export class ChatModel extends Disposable implements IChatModel { } if (!request.response) { - request.response = new ChatResponseModel(new MarkdownString(''), this, undefined); + request.response = new ChatResponseModel([], this, undefined); } if (request.response.isComplete) { @@ -708,7 +709,7 @@ export class ChatModel extends Disposable implements IChatModel { } if (!request.response) { - request.response = new ChatResponseModel(new MarkdownString(''), this, undefined); + request.response = new ChatResponseModel([], this, undefined); } request.response.setErrorDetails(rawResponse.errorDetails); diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index 09aa29178b2..4f8c05006a6 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -261,7 +261,14 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi get response(): IResponse { if (this._isPlaceholder) { - return new Response(new MarkdownString(localize('thinking', "Thinking") + '\u2026')); + // TODO@roblourens- this is suspicious. We may want to separate the markdown content from other types of content? + const placeholderText = new MarkdownString(localize('thinking', "Thinking") + '\u2026'); + return { + value: [placeholderText], + contentReferences: this._model.response.contentReferences, + usedContext: this._model.response.usedContext, + asString: () => placeholderText.value, + }; } return this._model.response; @@ -300,7 +307,19 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi currentRenderedHeight: number | undefined; - usedReferencesExpanded?: boolean | undefined; + private _usedReferencesExpanded: boolean | undefined; + + get usedReferencesExpanded(): boolean | undefined { + if (typeof this._usedReferencesExpanded === 'boolean') { + return this._usedReferencesExpanded; + } + + return this.isPlaceholder; + } + + set usedReferencesExpanded(v: boolean) { + this._usedReferencesExpanded = v; + } private _contentUpdateTimings: IChatLiveUpdateData | undefined = undefined; get contentUpdateTimings(): IChatLiveUpdateData | undefined { @@ -325,7 +344,7 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi } this._register(_model.onDidChange(() => { - if (this._isPlaceholder && (_model.response.value || this.isComplete)) { + if (this._isPlaceholder && (_model.response.value.length > 0 || this.isComplete)) { this._isPlaceholder = false; } From 2ffbb6acfbb025ea465489547ec932ff1e784ac8 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 10:43:13 -0700 Subject: [PATCH 079/290] add saved cue --- .../browser/accessibleNotificationService.ts | 30 ++++++++++++++---- .../accessibility/common/accessibility.ts | 8 ++++- .../audioCues/browser/audioCueService.ts | 7 ++++ .../platform/audioCues/browser/media/save.mp3 | Bin 0 -> 30428 bytes .../browser/audioCues.contribution.ts | 12 +++++++ .../chat/browser/actions/chatClearActions.ts | 4 +-- .../workbench/contrib/debug/browser/repl.ts | 4 +-- .../output/browser/output.contribution.ts | 4 +-- .../terminal/browser/xterm/xtermTerminal.ts | 4 +-- .../services/editor/browser/editorService.ts | 11 +++++-- 10 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 src/vs/platform/audioCues/browser/media/save.mp3 diff --git a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts index 28986f44188..6fc2bac7dab 100644 --- a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts +++ b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts @@ -5,26 +5,41 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; -import { IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { AccessibleNotificationEvent, IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export class AccessibleNotificationService extends Disposable implements IAccessibleNotificationService { declare readonly _serviceBrand: undefined; - + private _events: Map = new Map(); constructor( @IAudioCueService private readonly _audioCueService: IAudioCueService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService) { super(); + this._events.set(AccessibleNotificationEvent.Clear, { audioCue: AudioCue.clear, alertMessage: localize('cleared', "Cleared") }); + this._events.set(AccessibleNotificationEvent.Save, { audioCue: AudioCue.save, alertMessage: localize('saved', "Saved") }); } - notifyCleared(): void { - const audioCueValue = this._configurationService.getValue(AudioCue.clear.settingsKey); + notify(event: AccessibleNotificationEvent): void { + const { audioCue, alertMessage } = this._events.get(event)!; + const audioCueValue = this._configurationService.getValue(audioCue.settingsKey); if (audioCueValue === 'on' || audioCueValue === 'auto' && this._accessibilityService.isScreenReaderOptimized()) { - this._audioCueService.playAudioCue(AudioCue.clear); + this._audioCueService.playAudioCue(audioCue); } else { - alert(localize('cleared', "Cleared")); + alert(alertMessage); + } + } + notifySaved(userGesture: boolean): void { + const { audioCue, alertMessage } = this._events.get(AccessibleNotificationEvent.Save)!; + const audioCueSetting = this._configurationService.getValue(audioCue.settingsKey); + if (audioCueSetting === 'off') { + alert(alertMessage); + return; + } else if (audioCueSetting === 'always') { + this._audioCueService.playAudioCue(audioCue); + } else if (audioCueSetting === 'userGesture' && userGesture) { + this._audioCueService.playAudioCue(audioCue); } } } @@ -33,5 +48,6 @@ export class TestAccessibleNotificationService extends Disposable implements IAc declare readonly _serviceBrand: undefined; - notifyCleared(): void { } + notify(event: AccessibleNotificationEvent): void { } + notifySaved(userGesture: boolean): void { } } diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index d8b0df4eb0c..78b0ff84ee5 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -55,6 +55,12 @@ export const IAccessibleNotificationService = createDecorator2KgJ8!*tv+kQUZ|=l&`1aPOKI_cEzRB8)$*^UfximT zA^l1i>;5%^U*eGdMWA2T>g)cC9Dlu=d+D!I|7PN+PJVB{HSk*lzcuh%1HU!!TLZr} z@LL1FHSk*lzcuh%1HU!!&!Pd&Y7?1Tm#3IE+Ixs89U#7FK93hd9-9<;&+9OCvV^_% zT+J?%Z7Td+K!8|=`ih0s2#!`A@EJ6Or6psR!auaH4>Xf6uM%b6gi-ZjPg=6hdsk19 zT%Vub#R^0|Vn5(|#R8y_{{kMs|YuPG=q*I|#jt)r3f4Z3Uv=ZyRW*Jap(G z58$$qs)6i6VFq6H?mE0MgHc01rqGCfemBh; z^WD5U&t@2xZHy8UVzFSHhlMzZ1m6YCB5I&1BnukE`h@kLZ;jMv@CB&QQ=m(91IQcJ z4QT*IhtALVsqCzJ!3@RN!|^2O4rYK4A10KB8K8I&H{vIrAatz`?Ai-M!bnxE@2AU4 zH|1Sw-?L-SwF^5=dpW9U2DtUg+&yEMoIC{qoVh!gIL-%Z4f0$3XQh}zBm9>53o0bm zY`XB>P)bg6IDZ7S7xpdwE9@4v4)(m>l<_8FK&wc1pE9mcvYeDn$6&}*6-T6G7Fpax zD-3}qBLxNQ^46h1nk%fvD7f1WYXsv1sP-AUsQ&5AQynF5MJ2cQq2}uBLg`vznaU~+ z3pM)5dtM1Pj$IUE=Wcj;X;K3+Acz}e^NY{DT}`2NqCbfltXzNgj`IlsgsG4#5DK*> zeGEq=7Y8;aD+TS@oe*Xv3_<%~I?z3MEEEGEp>}E@WCXlLBm2iK3sBC=m63WFhIge_ zwk@{UIxS@%J^NHQ-a?LMSG0H3%RcwrIrme!$mCEz$t&0J@h+&Ku2xHb(p~!XJI58g zTN$>A-eLF4i>tZFLHPj6LF3B#)g!?GfL`PRDAGOjHfolidH_|zZcxhRJXg=|Hq$9Y zM7dtWv@osB3NLavoE7;~5h+ZgQL;|*U8($o`+cvTJCTs58jC0?Q+GK+~%kBY1+Gy1!wYsuR z^(QZm4}`o;s%pIIC8wOILgGFKHwuGf8eWYz)?Qm|`*QI?P~5tkJL=8+WWA+6_-B6c ze!#T|=jme($0B)oJv({cH?>8nSGd8p^2(>x?X>Up#llrzkI?dr1U^t_u;uYe!XFYx z00-I-Y6}hI6Q;Few$LsBZ#SrZrCgFLE+ia>j@ zYxa#^_D0`5jCh4dq;P;7aFJ%=1W4YNe+Iqh_x4n28TBby8Jy6RzoTVMn7+Aq=f0EA z4y~I74r!lf*Z)Y{EcnyQRZ~&^n#QO&A~0NCICb$2AidQBE_sBCn6h8jrR@s1^ zSRq6Ji>-~PV7*@|Q9BFyl(18a4%9AlR0|ehVyHbAdHk?a0D;x6 z`l&5sDlN(81%`8b{^qdDTMlOixn;*JAHHJ;*Mc%poM|9P_@^;B!)+YS_fr=+@6aM% z6%drIB#suSc>)C$tlN*4n%V`0ze({xD_}M;AsoUU_~-vZaU|(qb>!;vyqyjF1&$ollL;OQ%JPsJz@}Lk?Ls&i{uECLAevJNfA&mJf?i+cZ$PVW@HME7o zc{^@Jy#{YywCZP;{O@W%?7RBo;yVDK11vFcGtZK6HVx#J$&=rI2}~5AOW|_CJ)(3T zqB-aY>w>wO!eCdZkPsT?KyAmIZzRL<06<`~TrpTtL8c+qKjr&RFQ*KkBq2MABUEHq zFD84z3=m7ymGOK7z)lsuyxU6UYF(Br<2N#aOk|E@ji>q$^8ER!Spi7ZCM8x35l#i$ z&!k~gW^40&_#Kd=kKdT&ZCHNRU}#ZiJunq0eEQt=o7}2!0+;XCg>($9ooL&};ZzrK z9pxuCjY~9yfHO_;5gCQ++bd{Un=g6!-~lPySix?@eZd3X1-Um<+}&Cbd`< zZSTGJMNVMhi~rLnnyMvd4d359KUtEeb^hYfhsIeymPcnD-JG*7$Di@$a6&oX;ts7v zacW&SBY;E_F)%PlD{Ll&cr`fMIMk|2E27YLM(c%OKr4?eKS0C)2m}rd2Woe-SjZ7J z6~1;Vb{l+^m$F&$(b;rGYj3~~c$6Y0qQRu$gc;~*>$$u>iW?~V%2G46DDSNOoJwAa zewc_`da6=Y-=oiMJ}2HDRm)E|(aZ2JJLU7KVK}6sFjp_DZnkNpMYE&gs?$!jvEHx+ z`%p1nYGKuK+m1ZWr!R3&IV*1fz>V4#s&a5=M0JN&q=W6At!bfxyB;%J(vx0|&OEI@ zU5M_XY|y8h*ffV0;ElF^zC70FXWp&9YWF?j&_tY{yIG|V`%-zcDqkw~!sG_C!e?)G z2La{h${eyAJ^UI?x>w`cIAdf0#ADC^YPg2*X)_R_dKQ+}Wr8Td17!CeSNtt~cMh0a{7$SkM0A-k+j+mr%D`aicEicbz&U@nbem7ri8d^gp z)fJjz1w^&e^WChmN!ja6j*VZi5dsWw@l-sZX>k~q@DsU>01rExa@vOs?AgmZbz2XR z5Zj?7`xb!h7geNR%?48Ad8-G>;}ho|>&Q?9V;gwL%{}r5_xYS(KSEccy;#j=&*u=8 zqUYB2LcXIb&zv`fTopMMjoYUK%^rBH=pW^ut!4UHFn)M!kIROK3c-v4eob0d0K!xq zCu;S2a1)2~V}eu8`F3oU_F&c_yq-0B-&gvK*`8hWs;f?kmtpo)f<62)4F$lVJU!VY zC6BRlHiMrUw9i%D91y^fof6O76a45mksQ0jy5HFH-WR2N%r;>fiN8_Wa%3B4b?aG^ zO`q4CM=rZ@KHdD0JAc;WRvc$}(~6ox+Nm-fpT9f~9M0ORC+Ab^Fu)qqDOas5JQAnF zvK{vNpsnMCr}N=(N_=@}S49v9RM~(?SS1{Qc@QDYAu3Y_l7W*$lz_u5(=V)tA_xNv zcqw@A?e(|Zo7jN&vASbJW$PW+yD9Q_$7^q?h}^j${H{bwv(m0+Q4b96wU|e6fn?6% z2&KFYwl*{NkJZ(x3Y5y69_)DYrs82mdPTaYkA6jZq!VYPAXNFGjnwJDz&EG1>{|d> zgODtb>ujp_svF0+{;eJic&TLH6(6-E|7Kqyp6H3w)TCNJAX4zcOl&r<3anv!tot3! zt%k#o`Z$}OtL@-?vbWKdR}QtWPH=P9$cTX&m2P)dgw`jxsU60g#b6eretL z1p-uH0M}{6UTmZELAcInMFF&BJBuZTpkvr?;N9^lta>>2A+7A0wSezrFeOvU2uEhS z?@0B#EjsFmEOO#vIaaF?kE(15|5hR zNpnd%!~SvYIlgryRC%+5p?2D^+wGbV{Qj*Gb#LEEK0h()^UyU$Q@oGhmQ<5e-`M}8 zYu4~`QbT~wXGsV9F*k#zoID@9veUK=0Xa>#ZS4+vO{=OZ$rM3);;O1)1h?Ktof&-X zi;MU#N8`TYb1pRV=E#6gyoPBzK9i{5m$EG!bX+x-cpFcH4no6N5JTF?k8lygU#SRg|@_<6!NsgwwMgDO89o_aFHWJR5%~bn!ZZvw1s1$<5G?IJ)F=&3&}7l z?-cEa=G0x39F$cMrG0)2MTd3U^C^dOe>I$Aw-U$Qt=;5&b_?K1YlH^dZ3EsP&W92z zV2q&>It}i&W-ItcPQ`%u-R@iWk!sWD z%eJ0IMJmW>$LjMA>t3=#6i9dR)mUD_em;U0j+&HiOUAma2NJVK41yfCBuC4BODQso zUmM=U;jD5$fB9NN;{mUk4ZPz#H;m4Nnh`el0yr}jsjtFG=qY$Lyr0mgLXezK3D|Ng z(KevlW0U18%7wZX+aCj$ahbU55$YChogT+7C3NF&rLF9iUns;&o~+m-oYgA9PFLs0 z?a#hLshqX_ z6@O%6y_u4J5_Im1B5S`Q`(t zC!saypmfWzC!QuDhb6v;ea(yy{D6d@%=mZE1nfdICSssRWrGNe{G2V1Lo!t5<eR!njSSCs@fp zkV6QI-JpLDV9`3iG{)UC!p?8~D)iwstXtq2?8mjK=G&N zP~?*d?b(;K z#NV1B)%Pia#y|wP1=s}2S>QJIR`zZu!Iw}Qx25VdCL}JNJKWKfG`gV7GskneqSvVK zt&E`Wx)JT`8&5W3^6H}Nmzqv~dQ{2Vui7k@iLsh=mb6mbe}S$zV6h~gV6F)BKy{%R zl-wHLYLt-*8ZSq<;TK-+I@JO`AtEv{eDEOR$RCX=f&L3rdjIpauW8g>nzTRsL-do3rdRGPA_@H{fvogKZ7Au zkk}2S75wsYEfO2)s{yR&X^FxbajCm|KYjo`Bm1zkJ_I0j+6QYMnWFByW!sv_G_z*fMX;Dv1>Ru5d4 z4GFz;?)nOaa3t12xHn-&-9YhSwZ((_%Jzo7dAq~TK3>A|k3X5kYBL9S#0qcU@nvaT zZ#_>wJtv(P<7d{XDLnLW!-fM&GjnTaINSk_|Jn_-vD{2@7yND(qtr}dW<`?Lx-p=r z#WZM2J_FiQUw{Uz!=NHLg&zf!OAxVqr9fVS)me>zx|;bbS2yN=&~W=wA{`+7M8bP_ z!8(uS&kyZn*hfNk?zEdQZ#$7LLyc`LCg>$>39nn${p8Di^qRS!-DqqquZqg^!|1)2 z4%kZGzg(SfEYJ(~tIVK{tZjK~1kloN@G~eQK`TI%BU)Hx2{HS(Gkkbovmjj&R^}Dv8 zdE#~YN}y}Q>xWQWsvowU`c-IF&5|iKVX;Pv)^@PUt?`J4SDbhnA7#`s^3L-5i5Z2@ zFZFfhHoAoJZ{YRM335;-ymj-DC^0$p^^xC;qyndWPr)s@ci({L5L-xg9=1APDm%cr zd#QR)tpmZjcqx#?E(F_bj)8Hkeh>x(fI_V6@OZw6rJ}?nKa0$&sF%2ta%rJyv?TG2 zemaRcd?l_`;blv!V5O5}uG55LSmOP{rdj@PN(Wy*Gevhs6x9aSbchvtkevb))n_HW z?%X@sGr zXkns3VRaRbxF0v^KfnFj7mxZ(tI1v3(;@1d*TLs&1GlT&?)Tc_q;*_k8Xwm&cl^#L z&iOSirrtCVyCwMsWIUZzmyTjK#S` zLil0QhvX7Mwo$YsPHN3R7;sUqHN@X%v{=Vw_4J3X1iJTyQg8f4oL>59Z zG&hI`u5zSa&{r1j*E_+(gVtkH`LL;rdRWGs%|gUs1LK`g*~i;T7(kY5bSketF(L~(-Xgg`ad=+e%BgN3eqKvJ-Lr_@zJTR|_Za9&HvtRmTUG%c@ve8l=1bnQ9si2Q|w6AIJF7Xf@Q*IO^E zrx!%3uWc#Vwj-+k|A8EhR!Q>ig*GboIgw7=odD&KXF-S>0_s!EK_RLs0`Nn@qC4G% zc?6?`l)QtjF#X~#XyKWUHf*ydF2hO08TcIz>@BndO#+t9j2$cs5=Gi)w zq{C!K+*M#XN+zX{i844>DdPSOrI!aDC+Q_PI%KN0m`hZ|*Rh1|_=leSUT_7$Rz(Wl z5#XUGKq?pvZNUD7`7LeDqEP&7+J0O7fXv&keFyi~%++3ijtjm2aoOg4o8kVL53g_y zqi5fFykFC??byUw!D?^WhPAAIuvs$GCPN3>fsF|`PqAWY44?p?3>cF)1IALs@{<+V z8*&v+Fcmz)0=%s468n8S_52f@v;jSIgyPQKcenoXazq)fmveNjuzN_3Q}q+}x;iiP zN-f?WKVk8M1lCdbtS^roJW+^|uui!&cI$)iR?p&>wW_zI>Nb9A?vG@YRpzH*aN70?neC4r^4hTK{nDXAb~De)?%d@bU^kgKW@9}d1bzg9c*TtI3^hCtwz z^rmexdp6hZKkRm6F7ilC>*Eo`-uDK#w@H>9YPl?s*D8Da!i|S#Zy(?K;f3-5tS^Hg zi;y~6d>I%Yqo`HLIox>7`OFPoE9Ae8+F#FtQeD!d&Dmb2p``1i*!a^r8R#tVm1QkA znC<|jsZ$_^+os#VGBHreNa>88%BzH>;?Ldo5N~AcEz(g=OJ3OWI;My`>>>ZBd(-P3Hi_Utch z+yy3k0X@|Nm!r&R>W}msgJF6-MEtsRG0|}J;dock*hNcQUIJghQR>Hpy?0z2Q*Hzz zHvkq>)VzlK2P*4s?w9VX2K>jKGa^rboSSdE<-bNN=PbYSQ0omzh&htyK+ zKyU+V{MmD^aTJO`W9~blSE-f}h2u0Xa-Chm4mJ^Qr*oS8JFZ`zDLS~c`$Y4ju_*Sj zch{fPbSGX_Z(2^PxVbzAT|{+4r4`IzR9Qt}OU8K6Bk`&LQ@9MI1fPU*5XI0j>VBvc zUV{*nEE^Auo>GOA1^jJ|0fr2pAdCl&D|fb~=iLHs;3oonI)5Zo*C#q$JDCv@nHwGZ zoM6X`t<>n?z2$ntE9BY6WoeKxc7E#Qjeg2tMP$yV^D{e=nlJWK06%NW6BpH`u1d!7 zJpnI8>l*BL>ql7rm7V|K9_;DvCT*68GH+I*ke&&&fyOCEbqH|o94d?f>e8NoXzpB) z6xq~FX^>r6=s>R{aaiI6}TuHks6)?D6 zTRt<=S}kL*1S~TgB~O(?2~+FW)zZe{m#9<`?}XH(xWr;tNKjD-$8rGKm<%MuOr-&V zR28jnDK!4Wr;t1)eAXKs#(JK(i*Ix7ycVo{%I$RbD89l-x1}h#JzAB-D_B}Dj@~RGarT0$&*-Jd$h9ZS z$NkZ;@R(4Iy~R97M=h%L*a9j-?eezr*$LHXkcj?;oWAPSpUBnr^Z{`vDY)*W8KH$) z%ZtU_l_aESo*J!QtUaDd78OvIL3jjK!TR0^g2L_sFnf7|X2{_2ZFi2`e*F1y)>Ha^ zCs9STY3}SGjmIvd!R1`Yk**qN&&W90++Fv4HW$af>I8B#CV4Y7wGLDUh&oMv4OQP; zvX1lP40l4B(@N)Q(Rs;Rq@k<%ygf)7u-&)r>z8J@m#r=`c%2oZ#>^c#FSx`@S%=^* zXHkSPq?W3$-Agu9P4cBr6zL@K64+wnW=6zRh!BIrgzc%Em2wty4Wl?pSU;@9VQmUP zaYdB1sQjsft}2B3hD_s_hmU)*idwF>-o5L+@tbeh_KMz{5kA3dmroD=xYOm=_L6C3 zk?jX%qd_me18==01ow)_sr*=4_xZCsXN?HP!^%iOeX(ZAmPw@H-aOK@O*E;7Tm$0C zP2d5G<6ts5738PJ;7d!HVyaHQ0pVMOb=-~j*C5(ov2!sOY9piUy9KzNiH@;UfNMxE_l9s!_cTddp)K?>%El`;;Uozopmns}-8} zk@gHKT)kS(etk7RXz;?_4iw)vHDf{!A*$fu0pzY;%nuot3qvB*muP7bc(ixLW#g#f z!Y9{+AFUc!!d23q@=HiO@EBS<9X)e@{L`}I;=-Nwx1TclMs6Qhc~;zd>hht`BQSwP zx^gMSIi>=|NK8{Xb)jK{9jAU9vrAeO=sxW`{yy+pe{a2o-_S)RncfGuH>}raGW!(o zeD?+viya5^fZ+#(MDzq@LYxq!qA%sN92jS{kz7heILTh6e{*y#2x$Z2c2Pu>>ZZ7D zx%f2c655(_bXkj6i3U0H{&q}|z*W@}&!VnABGifV(jpGS-2 zV!Mvb=;hNFS2c6b7#=@6#LSLWH0ZJ{Z-yN-;~nJ9zIS4|a2u!fB)1jk7NCX{3=&Ak zosc?nHJGn$F)S%#S9rJ30Mr6cf^_IZfuq!LD4XU39e^K%;B;o(PQJ?qoI3OUvtD)Ehs-Sc(jndd8wtwfUiN1jLtJvp`1+=hpyo+oc!Z@co# zCxS-w7_cyF#`w|(7$`F!52mxiz!>Ca5a6yGv13nya^zj$Mk?NPxU;J7alB1BQXCUX zAqE`1g;9Hyg2gH+tCo#b4^I(}k12|?=&9Rv4X)gdU%Pz^Ke{tzuAX&iWJy1(ZLfsn z(ONVOMglQ14xUVFFCHav`&6+{YGeFu6Dz-BYo`Ma*QG@XeiWEZ=o$+2>RB_cXFF`@ zW?g`Jv0m`Dvk#yN5bC9hg@Deq2%V9CkPnR|SfLV#mPGeuA}WQJv4ARs8NcMMYt+7~ z*;Fw9?bfV6oAv#zmbM7rs0h??ExrzGh}E<_f|XYfU*rk5I9 z&~ineQ|r+dv=>-5o&3|uodb|tmD+!HSedUvr?^f|5R<}na%z@^Qcr&p$DKfvfmu)s ziacUX>zNcLzRs2L-m;S@u+cY-VK7vE;<4n2n~ipfOwWaJ%ck{|(k8vt;Vt_=y4ncT zcp9XOQ2acn32a#LDd3Hd;TWWv5E>{X=W*20s4n0YDJAp+wkjN*x(uC*e*vY!2mxiV zH;^hU9FnC`xU1R%Bj#w4#Y>@qwHH-va3Ywl96@+il_Rw?N8AB^>7W}+tw8!oS?<^w z%3RlO+RcpHFQfa(BC3i+Y0>9eIhk4|E}kxRk~WJ8)jU%)YGidTnJOvr|s( zV3n)pXsh$i@D7SBaK*WL__gnkV*9wYXKVi|{(_}ewj`&l%uO-4ZXFrn0-eqDRL~mf z4?1xhr8X=TFqO)KMH2435GC~fvaiAME>r?9ek%YFq`ZC`(EQ<)ebMK8NiSVt&rEA}bE# zyCFJoj5iN4fLcPP;G1DofTf_+bJ0@g1GS47L`tH-pjsL$;_C>Fn9#N1FJ;<3b;1;~8aKCwDgbX3~hj@v2yeH-qJ-r{(ZD@{Qx5QL?*QTzYQ) zT}%1eGD9<~XWBkHwh={LFp#o1V{Hxl7^nNfB0sCe_1f;FznZF2GCHai@Od z4$Y;4mss84W|lE1K~BIM>gII4#!02?h{)q;btpQ3EJ?6b5z&NGz^T!XnrPNT*Jz)@ zR_ml7`^Coh8m~M|ghQrYnBg~%WPB3G&wUs|4h zJz~x|9{9OB7?!x1=XP#*OWx^Res_A`zKoSsQ?;k6P!O^c>J$aScip)P-6yt24GQfI zdPdiRTIgT7&+p!VINDtRt=h@&+*{86==qIS2e0$#xF;4i6YJ)aRKs`i$`;b|Unt z$e31eR4Tk2Hd~5jf_T64SgL(WsxFe;&Frtw3}Q#G#Hlo^Zc9}d3izU2YQQ{(#?`gs zw0X$0e#Q4`ZMPoUez+dh&P zyw!1oP{`2^!)1mPKqvTCMij5rZzSAM6D@vc*+@{4uO^7f3lTt~KVb{ggTW7+W-y`y z1srPWGiFkZWdkuBV_ZfM&W$myf#T(QGMES&?Uei>W1D-Pse#oo-3f8)zU3$l+_0Cs zTQk*Yt3GKu8~-Zx!Q(NP)74#Hx&CMpA@K+aZbNzjW#+T=#%=PU6^f{I>e_eZ!{O2 zG-9h=h-Zw63>Yh6;<7l8JLM=rfH#c?SjugL*xJ4aPmE{?o zRjhkhXf}>wRILU27?QN!d|g|(vnu=4ci`Q;uKuCty=mTMfj^PU0+9RF+7M3zAqINu zR2;=mc$|yeLTdav318axv!IgC!TksB-O*hYZ-(hfy7S?BDsx!{qT<8?MfLi)AY_Zu z66~7HFlrIz4qwI$BN_N5WRjqc$afw*^AQ_RGgqR~dKHwi1K>)429P+r+k4tRe}*j6 zSzx92`K*$>(cb%F*c9{Jv_d)h#k3+vX%cqlxU${Ac9{mj(x=XIJ0G7|9td_)ttpt| zub6ot<@i`pDtRm^W`a8%t~et=GD16D;hzx=bW_nBikXp#RY*cLuIm*r5>f$}Xf%RK zIERwoO+m4*G{x|vZ)5vo**T}a-b$-kGj}$?-9Q83HYR z7&tW?vRT*o` zg#PK}JFuY~>SIG{ZeE0e%*kNSQQ_gr`B_knstsmzx039vtwCvA7`PK@4PJwRAio71 zOl0o^ov8P@1J`!KxkXB_GC{bLH4K1Nies#U1O&)xCz8lR*atM=qtg8dt@;L^w2pEi zZ-xB2&s)W;ZA_1Q*H46N=0w*P3qmv44?DMBy{m5IB`C))qOhN~x7Hl18qM7JF-2;d z@78CBR^D?vgq#uRWTFhDFR?ciG_np5%=;dc`xCiBD$+~MklSH}PEOlSaYur28ENA} zv#A!BvP;+t%Bl$mp-EIc6b>_k{D8NR9;_6K2I_)1(x($uG4^yC;3KW`Qa*v4NFA&Y z-FKsE%=Z*P*4#w1IMx(uesaECMyT>*(u7ku>3qjdPsYv4B*XV7ebiwVOw}AV0r_nj zEmu+$gSlPb;2+1i_?OW#3V-JmJ4D3gspWWAlpIAU!_gqt^NKlzU08@g=fT> zdjb{sEod&{{5kQ^xB|1+x_Rqc84CbuA*TSnH{C$#T`_xWyAJbikd9^G<8Rd;F9|>v zTCLY{Y1!|G7jVx;* zn$-su_y7H_Q7{CRQuP zu&sF^Iv^nP%xGUyF5&g+g`?)*uK#dlE#e1wdcME;-vMiW7U9O@Iw(bWW)nJq|ORwt`vga%qQ1p;Wn5>@QE|&v=8(B-IAk4|E`8zffsAi<>kY~qdR=#A(&OhHAH05cp7W#e z-?HbQ;25}}Q;*x8q3PJm?PW;fPTJPS?N#77&v;UEdCr@GZr8%RSbDTbc z9z7<(qOf!aWRXIWE;YC)PX&AksHDR*0xlIzOC)b9iB#b&GSc}-q(}*C7yBjV+_?Dk zwOG!km?MI><%zdd4i2))=ZwZqk(3_R-0A9EXK?kq>-~{S!o3SYer2}2_I$mvuDf_t z7g;mw76n!K`_+4eRQbz+-2@?OK^bvo5O&Rn=!h#9?Ci~%GCFFmeRVwRPEY({W1su% z!<}bcIxg({cqODHF_dzeKj~gBOuoDbjQ=wF9cfDtL(mUN+FEK>qH4w5ZV^fDFyfcg`B)}8~wWjYlk)ZCvyB=UXwzz$uNHbU-m-d zl9?33==OS}i>m9zu+2+(#ii8cu zw3Nk5PSE>$vo?L+p}ns#bLUC;tS{E$wK1h(=`LrP00X=eFxX;ZO%Xj+l+Z6BobmNA zfd@WId*o0`WNIEJ;bdH)+uP6nc=U2iVqanRvp#CCaEqG;x}Xg-7Ixh<<8W4Wd%RO+RxOGZFt$*F1?Jy>;bJU z6Av|fPBaWVs|Xv^;^W@Pqr1@iEc7*;t)yf2=|mfM;lXrJoo^TkTsL~@rdBCL45PDl zHE2KSFeoc%ew}2X3M02eKI$r(O0HWwU%W~sz7^8*fx=D>K6AF=_<&~Ial8{fp$3so z!(bu%CU}-T4tle0f#Os&C}tsNLhaJ`P?CVhf7pNFn2cS#BJy6x9u!+aqDZpGQP=3o zJ!Fq%Z&Kzh83&P0@84qdDMS=x%#YKj-*@7S+Y6&wHV*0@{fu2@KCgIC( z9EJ{>^7$=}$rm!@j1F6xIr-uN}L04et+umw@v>GIWGxrU=3hxhPN&r4Ks3J zagkeC50mES23Do#e>;c&31>k`wiI{8n6VBv`zy%PeH090Ab*PY$#wFrjl0~lzWcabiaB`U zcH0}!3O!7yV3`d(a#u*$1l}X$2{FS#K3Er$>S7YK_pzzX6=;uTZ?Z;9U!H47pv8x+ zs?U4)n$k^0tA~3%H^#_QRr&aq3?6ENJN%jj$Vd{87#z?6A^81k&~U>lkGLItc5wTE z^NY6=Oc85B?wBNS7x(_nLgcaCPbY8qz17}9{{J!hFXT+{hV)ejmTf23%Q+Zfuw3MJ z^T2qqPuUBEssEq+|2ggj6Oc=ijc+%}Z>}Wj_K-x-FoHc}9c+;RyGtZD$xlsL2|azg z(CdShcyxyYBp|BbI$b#Ra}uaLRfoPT>Ag25>A(~MbP~~#hyqm|ngzh`1fD!N)e-}f zCzZ>iuF)(lT=Fg|(_T+UziMYV2zo1uh`l6(L=|PieRco*H{c;YMWL5r#!ogQBoL;c z5dTXQ_Z=-|IN6@RMwou#ijdr^gy@=}(X*b!a3V$FORoN&FB>0Ug7yiY7w0fp31V0T zU;TqI1Xld+H5PLn0ujK=c8%Qlz`|pxfBRX5F&#`cekQ>cQgdB0@lNg6|i-l0_ zSpGZM?-z1-kv94h5^G~Tw=EZ8#MACJDFpQa3#ldSdB$(#06ruyJ*G|SHK;}hMj1wY zkLhHhgen^;z`kTWB(H$m++ydWIVPV{!cm`ky6>@+!?xy_SvPwBn4=!66i(4Zex2R2 zeIO`xxqFu(g@?toNA?3$zjB%;qZ7yXt=vj`+%2tTe(gg8{_%XITF?U}zC?7svmVDg z9ujBlN}&x)q6oW^9w(|QQvr`@MZX7xrUn>`#t4?PN7>XpD3)>3INuV%pcEb*`H;c4GPApTQcR))el<-0>@Q8T1t06AQEE+ou&wW&W|K{!*&x!}h>xuGjC+vI*l_-g) zWuNKF$Z;P19SHlsvit)%*ccbNM-D9W7vev?9Qw`1NuhuQ)=M5=_WZS?|LdmzaRTp&oAasFB6gLa6a3uOPdQ$%}+#c@S>+#7OZYQF`efcSHLMCLVJwq$6e(%${ z6)X>&61p)ft7PDWe%1$#0Z53bXeqqkDiKnqjeY+FTYNOy8hO|HMo!R_AuuzrRRG?M zV#D>7JVX)1R+1bqk#$?EHc7=DR$Mm6?m2RHs}NJmY8x?GK^!4?plxFQzukDhkgF3k zx)VC*MyHdGxha!RZViCp9uIsf*Z|C5exh)JLq&Gmds?6F`^ z-9Jg@pMOuUyB@s@?dK?Gd;5+|zK8I_+U3ts_VxhBU9sO+0^1)%=Dee9XTWIS;h{HU zwY`Z*?VQT&TR})Tl`Oey!p}GfV!9o%+NLWVRFo{*>n%bT52-03 zHB}}Bq3)FI#HZ|W!tZwqfkY~bPEVG1V|2Q{VGrqV6TIXsTYIEiaNU8>TV+P;-FZ~% zXkA-H}d z`To{=e=+p^ksI^rCW%ELQ4;hQF;-EQm!Nno>20+4hC1uM1rY2*;JduMt`>jz68@(p z?Oz1{xm>QA3X|e(qqln#m7c3`yAOD)?@E(`5%JUvWC?ph$@O0@{vVpKno=8>+{f(r zYI&vXxXDqx)FU*zGp8xFJ03mxjLiy29bLclLx^_(wXAGG&gS*s9ew=+)J!vXxkUE( zNQt(V%#>;heVea7NB6RDi4=8RT43U^0gcuBhgt)(UHQkmY|d0qN8(KVwx8&boeJ9H z>l-ls&#UU6PVO84%wr7cMMf1;Q!|VEC?W`J;-p}3XG#*6xbem<|Gc&T_tq?;8U=$* z&uDwgu;Z&eVg%=^32>>{uzX{kmuIRp`2zllW50=Vc(-eCgjS&Y%0b zKjJDd!)r({2AR_GDvMESc=(hI*U7!G52Qb34_tHjbJy@cL;7RZaI&{sCr%(uW?pA0 z5dMnfg?F#@XIXss?xDoMbRmjYZ|i&29`zB1pSmw>b%`;JGBQ{+LcSWaI7AJ*ZRjg6 zYaO;b(W-2S-jG>as~<9aFvWT7KSQ!VVIIGbYvgI8AF4fBiJ~KxZ6)#u5YJ>mA>No{Y4r|1^pI#2NiUt_;;i_p#3vX3Z={ z*^0o)_(^O8)!v3)!oDW+8#y2&rF&hTVp@0k`mIXH3`c1PF&Pujp$IVJ)Mtqlg!C;} zk^1+6c8vacza(^34qq_6L48U%TZQnT1%|XgME(==@plmY7jnnB$Zht@#Zh|~ch87e zOp8xqp-!?{d~!25S7_D_~&AgccdzT0$h9<3j%K}~&?;w?`UyMxUwdHhu{*Ff-? z&|b4npYnQnFcCTGJ(PHv_$RC1f2p{?kPAY#(Z1S?V3~!Bx+-uBZeZn^3M6aA`?9`c zG5@6k{X-TOuh#h%55Bg&;-mH)xnm4(;O&B!9co`MZ5|T;*tEv}`4*9~rd`&Re45mM zNcsPvg!+Y?4~mN%E}I`HTr@<(EsSuJ=#VKu4PL?;!2b4fKmuM=SMrVA#+|#n_`6zC z8}B+b!lk7?Twh87XdkHw_5}MAZI4&{h~|?C13WTb(AQ&MGwVnX{-G@W4T(8zr7qF$q!S)xv6&Gwxc$k{6URRB)$R?1riL| zcJ2Q#mi*HQ@(Z~bL>qM;g!2;*E)re>WEuD*j9Udb;LF1OX{z#f6!g&FG4KCzS^q)~ h3A9m(+{#nM7myBkY@d{|NZ@21OHhX_+QgG=;HtY literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 369a1668f97..385924a665e 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -137,6 +137,18 @@ Registry.as(ConfigurationExtensions.Configuration).regis ...audioCueFeatureBase, default: 'off' }, + 'audioCues.save': { + 'description': localize('audioCues.save', "Plays a sound when a file is saved."), + 'type': 'string', + 'enum': ['userGesture', 'always', 'off'], + 'default': 'off', + 'enumDescriptions': [ + localize('audioCues.enabled.userGesture', "Plays the audio cue when a user explicitly saves a file."), + localize('audioCues.enabled.always', "Plays the audio cue whenever a file is saved, including auto save."), + localize('audioCues.enabled.off', "Disable audio cue.") + ], + tags: ['accessibility'] + }, }, }); diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts index 21cd019327c..ebd4ed9b647 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts @@ -7,7 +7,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { Action2, IAction2Options, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -118,5 +118,5 @@ export function getClearAction(viewId: string, providerId: string) { } function announceChatCleared(accessor: ServicesAccessor): void { - accessor.get(IAccessibleNotificationService).notifyCleared(); + accessor.get(IAccessibleNotificationService).notify(AccessibleNotificationEvent.Clear); } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 5db4b41197d..7be4e8eb0bd 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -69,7 +69,7 @@ import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; import { ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { registerNavigableContainer } from 'vs/workbench/browser/actions/widgetNavigationCommands'; -import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; const $ = dom.$; @@ -978,7 +978,7 @@ registerAction2(class extends ViewAction { runInView(_accessor: ServicesAccessor, view: Repl): void { const accessibleNotificationService = _accessor.get(IAccessibleNotificationService); view.clearRepl(); - accessibleNotificationService.notifyCleared(); + accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); } }); diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index c03fe479393..358b67f43e6 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -28,7 +28,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; -import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; // Register Service registerSingleton(IOutputService, OutputService, InstantiationType.Delayed); @@ -225,7 +225,7 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { const activeChannel = outputService.getActiveChannel(); if (activeChannel) { activeChannel.clear(); - accessibleNotificationService.notifyCleared(); + accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); } } })); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 1bb7bf8f194..3b3d418f5d4 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -43,7 +43,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { debounce } from 'vs/base/common/decorators'; import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent'; -import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; const enum RenderConstants { /** @@ -590,7 +590,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach // the prompt being written this._capabilities.get(TerminalCapability.CommandDetection)?.handlePromptStart(); this._capabilities.get(TerminalCapability.CommandDetection)?.handleCommandStart(); - this._accessibleNotificationService.notifyCleared(); + this._accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); } hasSelection(): boolean { diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index dde1c5723e5..3f8e21a8300 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -33,6 +33,7 @@ import { IWorkspaceTrustRequestService, WorkspaceTrustUriResponse } from 'vs/pla import { IHostService } from 'vs/workbench/services/host/browser/host'; import { findGroup } from 'vs/workbench/services/editor/common/editorGroupFinder'; import { ITextEditorService } from 'vs/workbench/services/textfile/common/textEditorService'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; export class EditorService extends Disposable implements EditorServiceImpl { @@ -70,7 +71,8 @@ export class EditorService extends Disposable implements EditorServiceImpl { @IEditorResolverService private readonly editorResolverService: IEditorResolverService, @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, @IHostService private readonly hostService: IHostService, - @ITextEditorService private readonly textEditorService: ITextEditorService + @ITextEditorService private readonly textEditorService: ITextEditorService, + @IAccessibleNotificationService private readonly accessibleNotificationService: IAccessibleNotificationService ) { super(); @@ -972,9 +974,12 @@ export class EditorService extends Disposable implements EditorServiceImpl { } } } - + const success = saveResults.every(result => !!result); + if (success) { + this.accessibleNotificationService.notifySaved(options?.reason === SaveReason.EXPLICIT); + } return { - success: saveResults.every(result => !!result), + success, editors: coalesce(saveResults) }; } From 0301ad15a38d2f2c248b803d31f5ca10a23d3757 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:56:05 -0700 Subject: [PATCH 080/290] Ensure detach is done using right element --- src/vs/workbench/contrib/terminal/browser/terminalEditor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index 8b38e35a16e..0318448425a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -85,8 +85,8 @@ export class TerminalEditor extends EditorPane { override clearInput(): void { super.clearInput(); - if (this._overflowGuardElement && this._editorInput?.terminalInstance?.domElement === this._overflowGuardElement) { - this._editorInput?.detachInstance(); + if (this._overflowGuardElement && this._editorInput?.terminalInstance?.domElement.parentElement === this._overflowGuardElement) { + this._editorInput.terminalInstance?.detachFromElement(); } this._editorInput = undefined; } From 13fc2026fa4efc6c9eea71671c7e2f2561f5fd13 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 11:22:43 -0700 Subject: [PATCH 081/290] Clean up --- .../contrib/chat/browser/chatListRenderer.ts | 35 +++++++------------ .../contrib/chat/common/chatViewModel.ts | 2 +- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index b2744d7ca7d..f4ead3e0d7e 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -337,10 +337,8 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { if (!partToRender) { @@ -540,12 +531,6 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer, element: IChatResponseViewModel, templateData: IChatListItemTemplate): { element: HTMLElement; dispose: () => void } { const listDisposables = new DisposableStore(); const referencesLabel = data.length > 1 ? @@ -670,9 +664,6 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { - this._onDidChangeItemHeight.fire({ element, height: templateData.rowContainer.offsetHeight }); - }); return { element: container, diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index 4f8c05006a6..8f0eda274d5 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { ChatModelInitState, IChatModel, IChatRequestModel, IChatResponseModel, IChatWelcomeMessageContent, IResponse, Response } from 'vs/workbench/contrib/chat/common/chatModel'; +import { ChatModelInitState, IChatModel, IChatRequestModel, IChatResponseModel, IChatWelcomeMessageContent, IResponse } from 'vs/workbench/contrib/chat/common/chatModel'; import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChatReplyFollowup, IChatResponseCommandFollowup, IChatResponseErrorDetails, IChatResponseProgressFileTreeData, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; import { countWords } from 'vs/workbench/contrib/chat/common/chatWordCounter'; From d34b4d401441db9144e2f0ca529de249768e754d Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 11:23:50 -0700 Subject: [PATCH 082/290] get it to work --- .../browser/accessibleNotificationService.ts | 11 +++++------ .../workbench/browser/parts/editor/editorAutoSave.ts | 6 ++++-- .../audioCues/browser/audioCues.contribution.ts | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts index 6fc2bac7dab..9be896353aa 100644 --- a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts +++ b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts @@ -6,7 +6,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; import { AccessibleNotificationEvent, IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; -import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; +import { AudioCue, IAudioCueService, Sound } from 'vs/platform/audioCues/browser/audioCueService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export class AccessibleNotificationService extends Disposable implements IAccessibleNotificationService { @@ -33,13 +33,12 @@ export class AccessibleNotificationService extends Disposable implements IAccess notifySaved(userGesture: boolean): void { const { audioCue, alertMessage } = this._events.get(AccessibleNotificationEvent.Save)!; const audioCueSetting = this._configurationService.getValue(audioCue.settingsKey); - if (audioCueSetting === 'off') { + if (audioCueSetting === 'never') { alert(alertMessage); return; - } else if (audioCueSetting === 'always') { - this._audioCueService.playAudioCue(audioCue); - } else if (audioCueSetting === 'userGesture' && userGesture) { - this._audioCueService.playAudioCue(audioCue); + } else if (audioCueSetting === 'always' || audioCueSetting === 'userGesture' && userGesture) { + // Play sound bypasses the usual audio cue checks IE screen reader optimized, auto, etc. + this._audioCueService.playSound(Sound.save, true); } } } diff --git a/src/vs/workbench/browser/parts/editor/editorAutoSave.ts b/src/vs/workbench/browser/parts/editor/editorAutoSave.ts index 5fed6253090..0abccd10742 100644 --- a/src/vs/workbench/browser/parts/editor/editorAutoSave.ts +++ b/src/vs/workbench/browser/parts/editor/editorAutoSave.ts @@ -14,6 +14,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { ILogService } from 'vs/platform/log/common/log'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; export class EditorAutoSave extends Disposable implements IWorkbenchContribution { @@ -32,7 +33,8 @@ export class EditorAutoSave extends Disposable implements IWorkbenchContribution @IEditorService private readonly editorService: IEditorService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IAccessibleNotificationService private readonly _accessibleNotificationService: IAccessibleNotificationService ) { super(); @@ -196,7 +198,7 @@ export class EditorAutoSave extends Disposable implements IWorkbenchContribution // Save if dirty if (workingCopy.isDirty()) { this.logService.trace(`[editor auto save] running auto save`, workingCopy.resource.toString(), workingCopy.typeId); - + this._accessibleNotificationService.notifySaved(false); workingCopy.save({ reason: SaveReason.AUTO }); } }, this.autoSaveAfterDelay); diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 385924a665e..b297893238d 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -140,12 +140,12 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'audioCues.save': { 'description': localize('audioCues.save', "Plays a sound when a file is saved."), 'type': 'string', - 'enum': ['userGesture', 'always', 'off'], - 'default': 'off', + 'enum': ['userGesture', 'always', 'never'], + 'default': 'never', 'enumDescriptions': [ localize('audioCues.enabled.userGesture', "Plays the audio cue when a user explicitly saves a file."), localize('audioCues.enabled.always', "Plays the audio cue whenever a file is saved, including auto save."), - localize('audioCues.enabled.off', "Disable audio cue.") + localize('audioCues.enabled.never', "Never plays the audio cue.") ], tags: ['accessibility'] }, From 116916866fadddc99fa31d3ad36835459f7d3ed2 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 11:39:12 -0700 Subject: [PATCH 083/290] add alert --- .../browser/accessibleNotificationService.ts | 19 +++++++++++++------ .../browser/accessibilityConfiguration.ts | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts index 9be896353aa..e7bbe5c406b 100644 --- a/src/vs/platform/accessibility/browser/accessibleNotificationService.ts +++ b/src/vs/platform/accessibility/browser/accessibleNotificationService.ts @@ -27,21 +27,28 @@ export class AccessibleNotificationService extends Disposable implements IAccess if (audioCueValue === 'on' || audioCueValue === 'auto' && this._accessibilityService.isScreenReaderOptimized()) { this._audioCueService.playAudioCue(audioCue); } else { - alert(alertMessage); + this._accessibilityService.alert(alertMessage); } } + notifySaved(userGesture: boolean): void { const { audioCue, alertMessage } = this._events.get(AccessibleNotificationEvent.Save)!; - const audioCueSetting = this._configurationService.getValue(audioCue.settingsKey); - if (audioCueSetting === 'never') { - alert(alertMessage); - return; - } else if (audioCueSetting === 'always' || audioCueSetting === 'userGesture' && userGesture) { + const alertSetting: NotificationSetting = this._configurationService.getValue('accessibility.alert.save'); + if (this._shouldNotify(alertSetting, userGesture)) { + this._accessibilityService.alert(alertMessage); + } + const audioCueSetting: NotificationSetting = this._configurationService.getValue(audioCue.settingsKey); + if (this._shouldNotify(audioCueSetting, userGesture)) { // Play sound bypasses the usual audio cue checks IE screen reader optimized, auto, etc. this._audioCueService.playSound(Sound.save, true); } } + + private _shouldNotify(settingValue: NotificationSetting, userGesture: boolean): boolean { + return settingValue === 'always' || settingValue === 'userGesture' && userGesture; + } } +type NotificationSetting = 'never' | 'always' | 'userGesture'; export class TestAccessibleNotificationService extends Disposable implements IAccessibleNotificationService { diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts index 35969027856..0dcc31ab070 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts @@ -47,6 +47,10 @@ export const enum AccessibilityVerbositySettingId { Comments = 'accessibility.verbosity.comments' } +export const enum AccessibilityAlertSettingId { + Save = 'accessibility.alert.save' +} + export const enum AccessibleViewProviderId { Terminal = 'terminal', TerminalHelp = 'terminal-help', @@ -117,7 +121,19 @@ const configuration: IConfigurationNode = { [AccessibilityVerbositySettingId.Comments]: { description: localize('verbosity.comments', 'Provide information about actions that can be taken in the comment widget or in a file which contains comments.'), ...baseProperty - } + }, + [AccessibilityAlertSettingId.Save]: { + 'description': localize('alert.save', "When in screen reader mode, alerts when a file is saved."), + 'type': 'string', + 'enum': ['userGesture', 'always', 'never'], + 'default': 'never', + 'enumDescriptions': [ + localize('alert.save.userGesture', "Alerts when a file is saved via user gesture."), + localize('alert.save.always', "Alerts whenever is a file is saved, including auto save."), + localize('alert.save.never', "Never alerts.") + ], + tags: ['accessibility'] + }, } }; From f938d8e3a08c626bc0d26404b2fa7ded3fceb909 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 11:44:37 -0700 Subject: [PATCH 084/290] reference each setting --- .../contrib/accessibility/browser/accessibilityConfiguration.ts | 2 +- .../contrib/audioCues/browser/audioCues.contribution.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts index 0dcc31ab070..93dacbcc23a 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts @@ -123,7 +123,7 @@ const configuration: IConfigurationNode = { ...baseProperty }, [AccessibilityAlertSettingId.Save]: { - 'description': localize('alert.save', "When in screen reader mode, alerts when a file is saved."), + 'markdownDescription': localize('alert.save', "When in screen reader mode, alerts when a file is saved. Also see {0}", '`#audioCues.save#`'), 'type': 'string', 'enum': ['userGesture', 'always', 'never'], 'default': 'never', diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index b297893238d..3da9c2eeade 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -138,7 +138,7 @@ Registry.as(ConfigurationExtensions.Configuration).regis default: 'off' }, 'audioCues.save': { - 'description': localize('audioCues.save', "Plays a sound when a file is saved."), + 'markdownDescription': localize('audioCues.save', "Plays a sound when a file is saved. Also see {0}", '`#accessibility.alert.save#`'), 'type': 'string', 'enum': ['userGesture', 'always', 'never'], 'default': 'never', From e8c025cb35a13c1292efbc38df4308e9d431200c Mon Sep 17 00:00:00 2001 From: David Dossett Date: Fri, 13 Oct 2023 12:24:39 -0700 Subject: [PATCH 085/290] Fix missing focus outline (#195583) --- src/vs/workbench/contrib/chat/browser/media/chat.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 683eec1507e..1ecdf245718 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -519,10 +519,6 @@ outline-offset: unset !important; } -.interactive-session .chat-used-context-label .monaco-button:focus-within { - outline: none; -} - .interactive-session .chat-used-context .chat-used-context-label .monaco-button .codicon { margin: 0 2px 0 0; } From 02a0399b8109695f659fada7e0b1774fcb2b0308 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 12:27:31 -0700 Subject: [PATCH 086/290] fix failing test --- .../contrib/files/test/browser/editorAutoSave.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts b/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts index 1f89d3dc33c..185bab56c8e 100644 --- a/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts @@ -23,6 +23,8 @@ import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices'; import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; suite('EditorAutoSave', () => { @@ -42,7 +44,7 @@ suite('EditorAutoSave', () => { const configurationService = new TestConfigurationService(); configurationService.setUserConfiguration('files', autoSaveConfig); instantiationService.stub(IConfigurationService, configurationService); - + instantiationService.stub(IAccessibleNotificationService, disposables.add(new TestAccessibleNotificationService())); instantiationService.stub(IFilesConfigurationService, disposables.add(new TestFilesConfigurationService( instantiationService.createInstance(MockContextKeyService), configurationService, From 865556747b34bbd19f290270b1cae5cc9bd4c2df Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 12:30:21 -0700 Subject: [PATCH 087/290] fix #195468 --- .../contrib/accessibility/browser/accessibleViewActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts index 23bea8fe3a2..0721b08a570 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts @@ -184,8 +184,8 @@ class AccessibleViewAcceptInlineCompletionAction extends Action2 { id: AccessibilityCommandId.AccessibleViewAcceptInlineCompletion, precondition: ContextKeyExpr.and(accessibleViewIsShown, ContextKeyExpr.equals(accessibleViewCurrentProviderId.key, AccessibleViewProviderId.InlineCompletions)), keybinding: { - primary: KeyMod.CtrlCmd | KeyCode.Enter, - mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, + primary: KeyMod.CtrlCmd | KeyCode.Slash, + mac: { primary: KeyMod.WinCtrl | KeyCode.Slash }, weight: KeybindingWeight.WorkbenchContrib }, icon: Codicon.check, From 11ca8b71b2b4b73f1788c1696df85666ac3545e9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Oct 2023 12:30:57 -0700 Subject: [PATCH 088/290] Await in terminal editor commands This allows linking together with runCommands as expected. Part of #10121 --- .../workbench/contrib/terminal/browser/terminalActions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 06284075661..39ed8377236 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -253,7 +253,7 @@ export function registerTerminalActions() { run: async (c, _, args) => { const options = (isObject(args) && 'location' in args) ? args as ICreateTerminalOptions : { location: TerminalLocation.Editor }; const instance = await c.service.createTerminal(options); - instance.focusWhenReady(); + await instance.focusWhenReady(); } }); @@ -268,7 +268,7 @@ export function registerTerminalActions() { const instance = await c.service.createTerminal({ location: { viewColumn: editorGroupsService.activeGroup.index } }); - instance.focusWhenReady(); + await instance.focusWhenReady(); } }); @@ -279,7 +279,7 @@ export function registerTerminalActions() { const instance = await c.service.createTerminal({ location: { viewColumn: SIDE_GROUP } }); - instance.focusWhenReady(); + await instance.focusWhenReady(); } }); From 37a996b4e0adbdc4d76f012a04d61721f4cd53f7 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 12:45:35 -0700 Subject: [PATCH 089/290] fix other tests --- .../services/editor/test/browser/editorService.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 14e96886f5d..92f47353b7c 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -28,6 +28,8 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; +import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; +import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; suite('EditorService', () => { @@ -60,6 +62,9 @@ suite('EditorService', () => { const editorService = disposables.add(instantiationService.createInstance(EditorService)); instantiationService.stub(IEditorService, editorService); + const accessibleNotificationService = disposables.add(new TestAccessibleNotificationService()); + instantiationService.stub(IAccessibleNotificationService, accessibleNotificationService); + testLocalInstantiationService = instantiationService; return [part, editorService, instantiationService.createInstance(TestServiceAccessor)]; From 9a1628df6ef8ac9e1c7a8120443f61b2f13f6874 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 12:49:54 -0700 Subject: [PATCH 090/290] proper fix --- .../services/editor/test/browser/editorService.test.ts | 5 ----- src/vs/workbench/test/browser/workbenchTestServices.ts | 5 ++++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 92f47353b7c..14e96886f5d 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -28,8 +28,6 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; -import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; -import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; suite('EditorService', () => { @@ -62,9 +60,6 @@ suite('EditorService', () => { const editorService = disposables.add(instantiationService.createInstance(EditorService)); instantiationService.stub(IEditorService, editorService); - const accessibleNotificationService = disposables.add(new TestAccessibleNotificationService()); - instantiationService.stub(IAccessibleNotificationService, accessibleNotificationService); - testLocalInstantiationService = instantiationService; return [part, editorService, instantiationService.createInstance(TestServiceAccessor)]; diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 0633ed98296..ba78acae038 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -73,7 +73,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IWorkingCopyService, WorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopy, IWorkingCopyBackupMeta, IWorkingCopyIdentifier } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { IFilesConfigurationService, FilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { BrowserTextFileService } from 'vs/workbench/services/textfile/browser/browserTextFileService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -166,6 +166,7 @@ import { IHoverOptions, IHoverService, IHoverWidget } from 'vs/workbench/service import { IRemoteExtensionsScannerService } from 'vs/platform/remote/common/remoteExtensionsScanner'; import { IRemoteSocketFactoryService, RemoteSocketFactoryService } from 'vs/platform/remote/common/remoteSocketFactoryService'; import { EditorParts } from 'vs/workbench/browser/parts/editor/editorParts'; +import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; export function createFileEditorInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined, undefined, undefined, undefined, undefined); @@ -274,6 +275,8 @@ export function workbenchInstantiationService( instantiationService.stub(IDialogService, new TestDialogService()); const accessibilityService = new TestAccessibilityService(); instantiationService.stub(IAccessibilityService, accessibilityService); + const accessibleNotificationService = disposables.add(new TestAccessibleNotificationService()); + instantiationService.stub(IAccessibleNotificationService, accessibleNotificationService); instantiationService.stub(IFileDialogService, instantiationService.createInstance(TestFileDialogService)); instantiationService.stub(ILanguageService, disposables.add(instantiationService.createInstance(LanguageService))); instantiationService.stub(ILanguageFeaturesService, new LanguageFeaturesService()); From c2a6932e9e24132fda9f979c8ab0f31217efdc8f Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 13 Oct 2023 13:11:05 -0700 Subject: [PATCH 091/290] eng: onboard to the extension test runner (#195570) * eng: onboard to the extension test runner Adds a `.vscode-test.js` file that uses the new extension test CLI to run tests. Also, onboards the markdown-language-features as the first built-in extension to use it. With the `ms-vscode.extension-test-runner` extension installed, the markdown-language-features' tests can be run and debugged easily in the UI :) * fixup --- .gitignore | 1 + .vscode-test.js | 71 ++++++++++ .vscode/extensions.json | 7 +- .vscode/settings.json | 6 + package.json | 3 + scripts/test-integration.bat | 2 +- scripts/test-integration.sh | 2 +- test/smoke/package.json | 1 - test/smoke/yarn.lock | 149 +------------------- yarn.lock | 260 +++++++++++++++++++++++++++++++---- 10 files changed, 324 insertions(+), 178 deletions(-) create mode 100644 .vscode-test.js diff --git a/.gitignore b/.gitignore index 0601e762dff..c0459c86043 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ vscode.db /cli/openssl product.overrides.json *.snap.actual +.vscode-test diff --git a/.vscode-test.js b/.vscode-test.js new file mode 100644 index 00000000000..9b9a35e5cbd --- /dev/null +++ b/.vscode-test.js @@ -0,0 +1,71 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +const path = require('path'); +const { defineConfig } = require('@vscode/test-cli'); + +/** + * A list of extension folders who have opted into tests, or configuration objects. + * Edit me to add more! + * + * @type {Array & { label: string })>} + */ +const extensions = [ + { + label: 'markdown-language-features', + workspaceFolder: `extensions/markdown-language-features/test-workspace`, + mocha: { timeout: 60_000 } + }, +]; + + +const defaultLaunchArgs = process.env.API_TESTS_EXTRA_ARGS?.split(' ') || [ + '--disable-telemetry', '--skip-welcome', '--skip-release-notes', `--crash-reporter-directory=${__dirname}/.build/crashes`, `--logsPath=${__dirname}/.build/logs/integration-tests`, '--no-cached-data', '--disable-updates', '--use-inmemory-secretstorage', '--disable-extensions', '--disable-workspace-trust' +]; + +module.exports = defineConfig(extensions.map(extension => { + /** @type {import('@vscode/test-cli').TestConfiguration} */ + const config = typeof extension === 'object' + ? { files: `extensions/${extension.label}/out/**/*.test.js`, ...extension } + : { files: `extensions/${extension}/out/**/*.test.js`, label: extension }; + + config.mocha ??= {}; + if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { + let suite = ''; + if (process.env.VSCODE_BROWSER) { + suite = `${process.env.VSCODE_BROWSER} Browser Integration ${config.label} tests`; + } else if (process.env.REMOTE_VSCODE) { + suite = `Remote Integration ${config.label} tests`; + } else { + suite = `Integration ${config.label} tests`; + } + + config.mocha.reporter = 'mocha-multi-reporters'; + config.mocha.reporterOptions = { + reporterEnabled: 'spec, mocha-junit-reporter', + mochaJunitReporterReporterOptions: { + testsuitesTitle: `${suite} ${process.platform}`, + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + } + }; + } + + if (!config.platform || config.platform === 'desktop') { + config.launchArgs = defaultLaunchArgs; + config.useInstallation = { + fromPath: process.env.INTEGRATION_TEST_ELECTRON_PATH || `${__dirname}/scripts/code.${process.platform === 'win32' ? 'cmd' : 'sh'}`, + }; + config.env = { + ...config.env, + VSCODE_SKIP_PRELAUNCH: '1', + }; + } else { + // web configs not supported, yet + } + + return config; +})); diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0d3101d30a8..2dd8a08255d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,9 +3,10 @@ // for the documentation about the extensions.json format "recommendations": [ "dbaeumer.vscode-eslint", - "EditorConfig.EditorConfig", - "GitHub.vscode-pull-request-github", + "editorconfig.editorconfig", + "github.vscode-pull-request-github", "ms-vscode.vscode-github-issue-notebooks", - "ms-vscode.vscode-selfhost-test-provider" + "ms-vscode.vscode-selfhost-test-provider", + "ms-vscode.extension-test-runner" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 0069fee3d12..0c73cc745a6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ ".build": true, ".profile-oss": true, "**/.DS_Store": true, + ".vscode-test": true, "cli/target": true, "build/**/*.js": { "when": "$(basename).ts" @@ -143,6 +144,11 @@ "${workspaceFolder}/build/**/*.js" ] }, + "extension-test-runner.debugOptions": { + "outFiles": [ + "${workspaceFolder}/extensions/*/out/**/*.js", + ] + }, "githubPullRequests.assignCreated": "${user}", "githubPullRequests.defaultMergeMethod": "squash", "githubPullRequests.ignoredPullRequestBranches": [ diff --git a/package.json b/package.json index 306121e894e..1401d9cb39c 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "test-browser": "npx playwright install && node test/unit/browser/index.js", "test-browser-no-install": "node test/unit/browser/index.js", "test-node": "mocha test/unit/node/index.js --delay --ui=tdd --timeout=5000 --exit", + "test-extension": "vscode-test", "preinstall": "node build/npm/preinstall.js", "postinstall": "node build/npm/postinstall.js", "compile": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile", @@ -136,6 +137,8 @@ "@vscode/gulp-electron": "^1.36.0", "@vscode/l10n-dev": "0.0.21", "@vscode/telemetry-extractor": "^1.9.10", + "@vscode/test-cli": "^0.0.3", + "@vscode/test-electron": "^2.3.5", "@vscode/test-web": "^0.0.42", "@vscode/vscode-perf": "^0.0.14", "ansi-colors": "^3.2.3", diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index fb9498937f6..16efa750a49 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -59,7 +59,7 @@ if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ### Markdown tests -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\markdown-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test %API_TESTS_EXTRA_ARGS% +call yarn test-extension -l markdown-language-features if %errorlevel% neq 0 exit /b %errorlevel% echo. diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 85e4f80dea6..35b97b58e59 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -79,7 +79,7 @@ kill_app echo echo "### Markdown tests" echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/markdown-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test $API_TESTS_EXTRA_ARGS +yarn test-extension -l markdown-language-features kill_app echo diff --git a/test/smoke/package.json b/test/smoke/package.json index f43c80e4372..13728583887 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -11,7 +11,6 @@ "mocha": "node ../node_modules/mocha/bin/mocha" }, "dependencies": { - "@vscode/test-electron": "^2.3.2", "mkdirp": "^1.0.4", "ncp": "^2.0.0", "node-fetch": "^2.6.7", diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index a50041b4bde..00e5dcd85ab 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -71,23 +66,6 @@ "@types/glob" "*" "@types/node" "*" -"@vscode/test-electron@^2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.3.2.tgz#25db8d1a94e8274c27015cf806ae8b180c83545b" - integrity sha512-CRfQIs5Wi5Ok5SUCC3PTvRRXa74LD43cSXHC8EuNlmHHEPaJa/AGrv76brcA1hVSxrdja9tiYwp95Lq8kwY0tw== - dependencies: - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - jszip "^3.10.1" - semver "^7.3.8" - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -154,11 +132,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -170,13 +143,6 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -debug@4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -302,28 +268,6 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -332,7 +276,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@~2.0.3: +inherits@2: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -383,11 +327,6 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -398,23 +337,6 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -jszip@^3.10.1: - version "3.10.1" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" - integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== - dependencies: - lie "~3.3.0" - pako "~1.0.2" - readable-stream "~2.3.6" - setimmediate "^1.0.5" - -lie@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" - integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== - dependencies: - immediate "~3.0.5" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -425,13 +347,6 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -471,11 +386,6 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ncp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" @@ -545,11 +455,6 @@ once@^1.3.0: dependencies: wrappy "1" -pako@~1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -590,11 +495,6 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -604,19 +504,6 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - resolve@^1.10.0: version "1.19.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" @@ -632,28 +519,11 @@ rimraf@3.0.2: dependencies: glob "^7.1.3" -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - "semver@2 || 3 || 4 || 5", semver@^5.5.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^7.3.8: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -722,13 +592,6 @@ string.prototype.trimstart@^1.0.1: call-bind "^1.0.0" define-properties "^1.1.3" -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -746,11 +609,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -791,8 +649,3 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== diff --git a/yarn.lock b/yarn.lock index bfdcd2d03d8..ba42d595ab9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -404,6 +404,18 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/schema@^0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" @@ -668,6 +680,11 @@ node-addon-api "^3.2.1" node-gyp-build "^4.3.0" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@playwright/test@^1.37.1": version "1.37.1" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.37.1.tgz#e7f44ae0faf1be52d6360c6bbf689fd0057d9b6f" @@ -791,6 +808,11 @@ dependencies: defer-to-connect "^2.0.0" +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -994,6 +1016,11 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== +"@types/mocha@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.2.tgz#96d63314255540a36bf24da094cce7a13668d73b" + integrity sha512-NaHL0+0lLNhX6d9rs+NSt97WH/gIlRHmszXbQ/8/MV/eVcFNdeJ/GYhrFuUc8K7WuPhRhTSdMkCp8VMzhUq85w== + "@types/mocha@^9.1.1": version "9.1.1" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" @@ -1328,6 +1355,29 @@ command-line-args "^5.2.1" ts-morph "^19.0.0" +"@vscode/test-cli@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@vscode/test-cli/-/test-cli-0.0.3.tgz#9b02943713652e84a675894ffa4a6fe5375496ab" + integrity sha512-Gk2Vo5OOoJ3bFChW+THN5/gVz7qsGfZUsTgMgQtpx39Z2NqyddONM4MDVGM83Hgjlr+4rCP9RUS5C0WL3ERtdw== + dependencies: + "@types/mocha" "^10.0.2" + chokidar "^3.5.3" + glob "^10.3.10" + minimatch "^9.0.3" + mocha "^10.2.0" + supports-color "^9.4.0" + yargs "^17.7.2" + +"@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== + dependencies: + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + jszip "^3.10.1" + semver "^7.5.2" + "@vscode/test-web@^0.0.42": version "0.0.42" resolved "https://registry.yarnpkg.com/@vscode/test-web/-/test-web-0.0.42.tgz#c69449ca6974c5052d4d89a0068e14ff32f8ebe4" @@ -1717,6 +1767,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -1737,6 +1792,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + ansi-wrap@0.1.0, ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -2348,7 +2408,7 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -chokidar@3.5.3: +chokidar@3.5.3, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -2815,7 +2875,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3324,6 +3384,11 @@ each-props@^1.3.2: is-plain-object "^2.0.1" object.defaults "^1.1.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + editorconfig@^0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.0.tgz#b6dd4a0b6b9e76ce48e066bdc15381aebb8804fd" @@ -3382,6 +3447,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -4189,6 +4259,14 @@ for-own@^1.0.0: dependencies: for-in "^1.0.1" +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + form-data@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" @@ -4427,6 +4505,17 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.3.10: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + glob@^5.0.13: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -5006,6 +5095,15 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -5031,7 +5129,7 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" -https-proxy-agent@^5.0.1: +https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -5089,6 +5187,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -5656,6 +5759,15 @@ istextorbinary@1.0.2: binaryextensions "~1.0.0" textextensions "~1.0.0" +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-worker@^27.0.2: version "27.0.6" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.6.tgz#a5fdb1e14ad34eb228cfe162d9f729cdbfa28aed" @@ -5768,6 +5880,16 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jszip@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + just-debounce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" @@ -5961,6 +6083,13 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + liftoff@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" @@ -6113,6 +6242,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +"lru-cache@^9.1.1 || ^10.0.0": + version "10.0.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" + integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== + lru-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" @@ -6404,6 +6538,13 @@ minimatch@^7.4.3: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.1, minimatch@^9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" @@ -6421,6 +6562,11 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -7105,6 +7251,11 @@ pako@~0.2.0: resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -7220,6 +7371,14 @@ path-root@^0.1.1: dependencies: path-root-regex "^0.1.0" +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== + dependencies: + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" @@ -8364,7 +8523,7 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.4: +semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -8400,6 +8559,11 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -8456,6 +8620,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -8781,6 +8950,15 @@ streamx@^2.12.5: fast-fifo "^1.1.0" queue-tick "^1.0.1" +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -8816,14 +8994,14 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" string.prototype.padend@^3.0.0: version "3.1.1" @@ -8869,6 +9047,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -8897,12 +9082,12 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: - ansi-regex "^5.0.1" + ansi-regex "^6.0.1" strip-bom-string@^1.0.0: version "1.0.0" @@ -8990,6 +9175,11 @@ supports-color@^7.2.0: dependencies: has-flag "^4.0.0" +supports-color@^9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.4.0.tgz#17bfcf686288f531db3dea3215510621ccb55954" + integrity sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw== + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -9991,6 +10181,15 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -10017,14 +10216,14 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" wrappy@1: version "1.0.2" @@ -10185,7 +10384,7 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.0.0: +yargs-parser@^21.0.0, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -10260,6 +10459,19 @@ yargs@^17.2.1, yargs@^17.5.1: y18n "^5.0.5" yargs-parser "^21.0.0" +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yargs@^7.1.0: version "7.1.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.1.tgz#67f0ef52e228d4ee0d6311acede8850f53464df6" From 3ce69fc3fa73fd66a8ec1700f4b3d25ece15c7cc Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 13:46:35 -0700 Subject: [PATCH 092/290] rm unused css --- .../terminal/browser/media/terminal.css | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index a11d5cc80b7..c222df0deb8 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -552,34 +552,6 @@ background-color: var(--vscode-scrollbarSlider-activeBackground); } -.monaco-workbench .terminal-accessible-widget { - position: absolute; - left: 10px; - top: 0; - bottom: 0; - right: 0; - opacity: 0; - /* Reset cursor style as monaco controls it here */ - cursor: default; - padding: 0; - overflow: initial; - overflow-x: initial; - pointer-events: none; - z-index: 0; -} - -.monaco-workbench .terminal-accessible-widget div { - white-space: pre-wrap; -} - -.monaco-workbench .terminal-accessible-widget.focus-within, -.monaco-workbench .terminal-accessible-widget.active { - pointer-events: all; - opacity: 1; - z-index: 33; - background-color: var(--vscode-terminal-background, var(--vscode-panel-background)); -} - .monaco-workbench .xterm.terminal.hide { visibility: hidden; } From b40a630d8a4b6e442ffbea4a2d32291bea27111d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:05:05 -0700 Subject: [PATCH 093/290] Adopt documentOverride in xterm.js Fixes #195595 --- package.json | 14 ++--- remote/package.json | 14 ++--- remote/web/package.json | 10 ++-- remote/web/yarn.lock | 40 ++++++------- remote/yarn.lock | 56 +++++++++---------- .../terminal/browser/xterm/xtermTerminal.ts | 5 +- yarn.lock | 56 +++++++++---------- 7 files changed, 99 insertions(+), 96 deletions(-) diff --git a/package.json b/package.json index 1401d9cb39c..e80f9ad0223 100644 --- a/package.json +++ b/package.json @@ -96,14 +96,14 @@ "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "9.0.0", - "xterm": "5.4.0-beta.27", - "xterm-addon-canvas": "0.6.0-beta.27", + "xterm": "5.4.0-beta.31", + "xterm-addon-canvas": "0.6.0-beta.31", "xterm-addon-image": "0.6.0-beta.21", - "xterm-addon-search": "0.14.0-beta.27", - "xterm-addon-serialize": "0.12.0-beta.26", - "xterm-addon-unicode11": "0.7.0-beta.26", - "xterm-addon-webgl": "0.17.0-beta.26", - "xterm-headless": "5.4.0-beta.27", + "xterm-addon-search": "0.14.0-beta.30", + "xterm-addon-serialize": "0.12.0-beta.30", + "xterm-addon-unicode11": "0.7.0-beta.30", + "xterm-addon-webgl": "0.17.0-beta.30", + "xterm-headless": "5.4.0-beta.31", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index b0cce32e568..a144d3f85b2 100644 --- a/remote/package.json +++ b/remote/package.json @@ -26,14 +26,14 @@ "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "9.0.0", - "xterm": "5.4.0-beta.27", - "xterm-addon-canvas": "0.6.0-beta.27", + "xterm": "5.4.0-beta.31", + "xterm-addon-canvas": "0.6.0-beta.31", "xterm-addon-image": "0.6.0-beta.21", - "xterm-addon-search": "0.14.0-beta.27", - "xterm-addon-serialize": "0.12.0-beta.26", - "xterm-addon-unicode11": "0.7.0-beta.26", - "xterm-addon-webgl": "0.17.0-beta.26", - "xterm-headless": "5.4.0-beta.27", + "xterm-addon-search": "0.14.0-beta.30", + "xterm-addon-serialize": "0.12.0-beta.30", + "xterm-addon-unicode11": "0.7.0-beta.30", + "xterm-addon-webgl": "0.17.0-beta.30", + "xterm-headless": "5.4.0-beta.31", "yauzl": "^2.9.2", "yazl": "^2.4.3" } diff --git a/remote/web/package.json b/remote/web/package.json index d5b3de25362..0fb5ee2bcfc 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,11 +11,11 @@ "tas-client-umd": "0.1.8", "vscode-oniguruma": "1.7.0", "vscode-textmate": "9.0.0", - "xterm": "5.4.0-beta.27", - "xterm-addon-canvas": "0.6.0-beta.27", + "xterm": "5.4.0-beta.31", + "xterm-addon-canvas": "0.6.0-beta.31", "xterm-addon-image": "0.6.0-beta.21", - "xterm-addon-search": "0.14.0-beta.27", - "xterm-addon-unicode11": "0.7.0-beta.26", - "xterm-addon-webgl": "0.17.0-beta.26" + "xterm-addon-search": "0.14.0-beta.30", + "xterm-addon-unicode11": "0.7.0-beta.30", + "xterm-addon-webgl": "0.17.0-beta.30" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 3c4dfaae98c..bd6e5adf267 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,32 +68,32 @@ vscode-textmate@9.0.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c" integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg== -xterm-addon-canvas@0.6.0-beta.27: - version "0.6.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.27.tgz#2517f050d165b093a3c3e564e4420ccc3ccbad75" - integrity sha512-mSxEJKPnXYKkD6/zQLdNH6kB+sr4B+4DMFzntWgxLjHJdyOO95wUSAtBFnhAUez2nNYvXbs/OXpEbdVdO7f2kQ== +xterm-addon-canvas@0.6.0-beta.31: + version "0.6.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb" + integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ== xterm-addon-image@0.6.0-beta.21: version "0.6.0-beta.21" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== -xterm-addon-search@0.14.0-beta.27: - version "0.14.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.27.tgz#b6f81eac5047253a5c664349c47498a81b6ec168" - integrity sha512-T4Exwf/rqoLHqGUUIta5Pw/i9PljvroZwLxc7RnVyDqpNsTifDn3675kS54CxwqPlv4owFhxujTDzJPCUEkM2A== +xterm-addon-search@0.14.0-beta.30: + version "0.14.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea" + integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ== -xterm-addon-unicode11@0.7.0-beta.26: - version "0.7.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.26.tgz#f9606231a8f13e57dbdec5e884b044b0813931f5" - integrity sha512-po+z1ayyrkWh8IGXKpbwCLKLKfcjotZVKqowU6PtHuDtJm/J8rlzvV2eJU1WQ/8ezpopU09ibWCvaf1a7EPuxA== +xterm-addon-unicode11@0.7.0-beta.30: + version "0.7.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3" + integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw== -xterm-addon-webgl@0.17.0-beta.26: - version "0.17.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.26.tgz#aee4a043981d5d303b7112ef7049bc2865e75393" - integrity sha512-N8CuAPZnoDlQ6yV7n4eXQ2ONPr/GdxiwgxrJjNks4CzzHiJREm23FQIv0fCTwKQS5xU3qoc4LlT3vZ1tKGjtQw== +xterm-addon-webgl@0.17.0-beta.30: + version "0.17.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f" + integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q== -xterm@5.4.0-beta.27: - version "5.4.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.27.tgz#f641ee045a65c9c8967fac534a202062706a8fa9" - integrity sha512-gKqtrjy0RLk2123oFyPw5tkV96jGz4c/JkY8/XUvBXoMVsX4A7rVKpHlmHhmnuK1X5ERAkvCD21YE7LfB8WYkw== +xterm@5.4.0-beta.31: + version "5.4.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174" + integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA== diff --git a/remote/yarn.lock b/remote/yarn.lock index 0e4bdb1df9d..4b7185b4ffa 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -591,45 +591,45 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-canvas@0.6.0-beta.27: - version "0.6.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.27.tgz#2517f050d165b093a3c3e564e4420ccc3ccbad75" - integrity sha512-mSxEJKPnXYKkD6/zQLdNH6kB+sr4B+4DMFzntWgxLjHJdyOO95wUSAtBFnhAUez2nNYvXbs/OXpEbdVdO7f2kQ== +xterm-addon-canvas@0.6.0-beta.31: + version "0.6.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb" + integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ== xterm-addon-image@0.6.0-beta.21: version "0.6.0-beta.21" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== -xterm-addon-search@0.14.0-beta.27: - version "0.14.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.27.tgz#b6f81eac5047253a5c664349c47498a81b6ec168" - integrity sha512-T4Exwf/rqoLHqGUUIta5Pw/i9PljvroZwLxc7RnVyDqpNsTifDn3675kS54CxwqPlv4owFhxujTDzJPCUEkM2A== +xterm-addon-search@0.14.0-beta.30: + version "0.14.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea" + integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ== -xterm-addon-serialize@0.12.0-beta.26: - version "0.12.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.26.tgz#cb5bd80128e82880369cb012938e14414b182aa1" - integrity sha512-b4lOcttE6lqAF3zB2l8XtDShe5djhl9SueljnVWuG4mYMYPQoiklxFcpY66sjSCIAS6NsbtrL/LGQ/0eZGi+Ig== +xterm-addon-serialize@0.12.0-beta.30: + version "0.12.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.30.tgz#80c4101f45a463ef139705bcd3dcaf0811f51ea4" + integrity sha512-nZP0ip5bd9LBoCTN9vCnn4iLatF4RRwzLupQf9r2N9x1bULzTZ1kAXAQe5gghsXjSEDDtyY2LzGigqTd2KVAqQ== -xterm-addon-unicode11@0.7.0-beta.26: - version "0.7.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.26.tgz#f9606231a8f13e57dbdec5e884b044b0813931f5" - integrity sha512-po+z1ayyrkWh8IGXKpbwCLKLKfcjotZVKqowU6PtHuDtJm/J8rlzvV2eJU1WQ/8ezpopU09ibWCvaf1a7EPuxA== +xterm-addon-unicode11@0.7.0-beta.30: + version "0.7.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3" + integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw== -xterm-addon-webgl@0.17.0-beta.26: - version "0.17.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.26.tgz#aee4a043981d5d303b7112ef7049bc2865e75393" - integrity sha512-N8CuAPZnoDlQ6yV7n4eXQ2ONPr/GdxiwgxrJjNks4CzzHiJREm23FQIv0fCTwKQS5xU3qoc4LlT3vZ1tKGjtQw== +xterm-addon-webgl@0.17.0-beta.30: + version "0.17.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f" + integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q== -xterm-headless@5.4.0-beta.27: - version "5.4.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.27.tgz#cfce5f86e83580388238ea204bb451b7ffe94dc9" - integrity sha512-vdrq5eeNMyHZRDw5XR/TPl8oPln0BqbR07akt/fDXMsVg6YwWG+UOnU6GIMj7bJaBed5YkPV9NeBtdsVQn4Lyw== +xterm-headless@5.4.0-beta.31: + version "5.4.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.31.tgz#9538553c7426222f94d7da7ed467e699ebaeeedd" + integrity sha512-EE/ZlsZcBE5VOkjQU/KdRL4gvSkfrC2P7VxrmK1+PLc6+QMjPxs60A4Pun3mIIS0MFfN23p6hmN22GAXVckCXA== -xterm@5.4.0-beta.27: - version "5.4.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.27.tgz#f641ee045a65c9c8967fac534a202062706a8fa9" - integrity sha512-gKqtrjy0RLk2123oFyPw5tkV96jGz4c/JkY8/XUvBXoMVsX4A7rVKpHlmHhmnuK1X5ERAkvCD21YE7LfB8WYkw== +xterm@5.4.0-beta.31: + version "5.4.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174" + integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA== yallist@^4.0.0: version "4.0.0" diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 3b3d418f5d4..4bf8712da82 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -44,6 +44,7 @@ import { debounce } from 'vs/base/common/decorators'; import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent'; import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; const enum RenderConstants { /** @@ -204,7 +205,8 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach @ITelemetryService private readonly _telemetryService: ITelemetryService, @IClipboardService private readonly _clipboardService: IClipboardService, @IContextKeyService contextKeyService: IContextKeyService, - @IAccessibleNotificationService private readonly _accessibleNotificationService: IAccessibleNotificationService + @IAccessibleNotificationService private readonly _accessibleNotificationService: IAccessibleNotificationService, + @ILayoutService layoutService: ILayoutService ) { super(); const font = this._configHelper.getFont(undefined, true); @@ -215,6 +217,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach allowProposedApi: true, cols, rows, + documentOverride: layoutService.container.ownerDocument, altClickMovesCursor: config.altClickMovesCursor && editorOptions.multiCursorModifier === 'alt', scrollback: config.scrollback, theme: this._getXtermTheme(), diff --git a/yarn.lock b/yarn.lock index ba42d595ab9..4283bf58f52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10285,45 +10285,45 @@ xtend@~4.0.0, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xterm-addon-canvas@0.6.0-beta.27: - version "0.6.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.27.tgz#2517f050d165b093a3c3e564e4420ccc3ccbad75" - integrity sha512-mSxEJKPnXYKkD6/zQLdNH6kB+sr4B+4DMFzntWgxLjHJdyOO95wUSAtBFnhAUez2nNYvXbs/OXpEbdVdO7f2kQ== +xterm-addon-canvas@0.6.0-beta.31: + version "0.6.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb" + integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ== xterm-addon-image@0.6.0-beta.21: version "0.6.0-beta.21" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== -xterm-addon-search@0.14.0-beta.27: - version "0.14.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.27.tgz#b6f81eac5047253a5c664349c47498a81b6ec168" - integrity sha512-T4Exwf/rqoLHqGUUIta5Pw/i9PljvroZwLxc7RnVyDqpNsTifDn3675kS54CxwqPlv4owFhxujTDzJPCUEkM2A== +xterm-addon-search@0.14.0-beta.30: + version "0.14.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea" + integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ== -xterm-addon-serialize@0.12.0-beta.26: - version "0.12.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.26.tgz#cb5bd80128e82880369cb012938e14414b182aa1" - integrity sha512-b4lOcttE6lqAF3zB2l8XtDShe5djhl9SueljnVWuG4mYMYPQoiklxFcpY66sjSCIAS6NsbtrL/LGQ/0eZGi+Ig== +xterm-addon-serialize@0.12.0-beta.30: + version "0.12.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.30.tgz#80c4101f45a463ef139705bcd3dcaf0811f51ea4" + integrity sha512-nZP0ip5bd9LBoCTN9vCnn4iLatF4RRwzLupQf9r2N9x1bULzTZ1kAXAQe5gghsXjSEDDtyY2LzGigqTd2KVAqQ== -xterm-addon-unicode11@0.7.0-beta.26: - version "0.7.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.26.tgz#f9606231a8f13e57dbdec5e884b044b0813931f5" - integrity sha512-po+z1ayyrkWh8IGXKpbwCLKLKfcjotZVKqowU6PtHuDtJm/J8rlzvV2eJU1WQ/8ezpopU09ibWCvaf1a7EPuxA== +xterm-addon-unicode11@0.7.0-beta.30: + version "0.7.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3" + integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw== -xterm-addon-webgl@0.17.0-beta.26: - version "0.17.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.26.tgz#aee4a043981d5d303b7112ef7049bc2865e75393" - integrity sha512-N8CuAPZnoDlQ6yV7n4eXQ2ONPr/GdxiwgxrJjNks4CzzHiJREm23FQIv0fCTwKQS5xU3qoc4LlT3vZ1tKGjtQw== +xterm-addon-webgl@0.17.0-beta.30: + version "0.17.0-beta.30" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f" + integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q== -xterm-headless@5.4.0-beta.27: - version "5.4.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.27.tgz#cfce5f86e83580388238ea204bb451b7ffe94dc9" - integrity sha512-vdrq5eeNMyHZRDw5XR/TPl8oPln0BqbR07akt/fDXMsVg6YwWG+UOnU6GIMj7bJaBed5YkPV9NeBtdsVQn4Lyw== +xterm-headless@5.4.0-beta.31: + version "5.4.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.31.tgz#9538553c7426222f94d7da7ed467e699ebaeeedd" + integrity sha512-EE/ZlsZcBE5VOkjQU/KdRL4gvSkfrC2P7VxrmK1+PLc6+QMjPxs60A4Pun3mIIS0MFfN23p6hmN22GAXVckCXA== -xterm@5.4.0-beta.27: - version "5.4.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.27.tgz#f641ee045a65c9c8967fac534a202062706a8fa9" - integrity sha512-gKqtrjy0RLk2123oFyPw5tkV96jGz4c/JkY8/XUvBXoMVsX4A7rVKpHlmHhmnuK1X5ERAkvCD21YE7LfB8WYkw== +xterm@5.4.0-beta.31: + version "5.4.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174" + integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA== y18n@^3.2.1: version "3.2.2" From c9a7a1dfeccdd60e2118700acc8fd8d7cb1df33b Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 14:41:54 -0700 Subject: [PATCH 094/290] fix #195288 --- src/vs/platform/terminal/common/terminal.ts | 1 + .../contrib/accessibility/browser/accessibleView.ts | 4 ++++ .../codeEditor/browser/accessibility/accessibility.css | 6 ++++++ .../contrib/terminal/common/terminalConfiguration.ts | 5 +++++ 4 files changed, 16 insertions(+) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 2465abe9ad6..1f7225a801c 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -117,6 +117,7 @@ export const enum TerminalSettingId { IgnoreBracketedPasteMode = 'terminal.integrated.ignoreBracketedPasteMode', FocusAfterRun = 'terminal.integrated.focusAfterRun', AccessibleViewPreserveCursorPosition = 'terminal.integrated.accessibleViewPreserveCursorPosition', + HideAccessibleView = 'terminal.integrated.hideAccessibleView', // Debug settings that are hidden from user diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index fc79523928e..7432219e9ea 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -38,6 +38,7 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { AccessibilityVerbositySettingId, AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; @@ -215,6 +216,9 @@ export class AccessibleView extends Disposable { this._accessibleViewVerbosityEnabled.set(this._configurationService.getValue(this._currentProvider.verbositySettingKey)); this._updateToolbar(this._currentProvider.actions, this._currentProvider.options.type); } + if (e.affectsConfiguration(TerminalSettingId.HideAccessibleView)) { + this._container.classList.toggle('hide', this._configurationService.getValue(TerminalSettingId.HideAccessibleView)); + } })); this._register(this._editorWidget.onDidDispose(() => this._resetContextKeys())); this._register(this._editorWidget.onDidChangeCursorPosition(() => { diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css index f8044ced3b2..8b7c1096017 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css @@ -52,3 +52,9 @@ background-repeat: no-repeat; padding: 2px; } + +.accessible-view.hide { + position: fixed; + top: -2000px; + left:-2000px; +} diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index a12b0440283..2d6b942d632 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -619,6 +619,11 @@ const terminalConfiguration: IConfigurationNode = { markdownDescription: localize('terminal.integrated.accessibleViewPreserveCursorPosition', "Preserve the cursor position on reopen of the terminal's accessible view rather than setting it to the bottom of the buffer."), type: 'boolean', default: false + }, + [TerminalSettingId.HideAccessibleView]: { + description: localize('terminal.integrated.hideAccessibleView', "Controls whether the terminal's accessible view is hidden."), + type: 'boolean', + default: false } } }; From de504b2d7236a6d29fbe064aa05caddd432ed2da Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 14:44:26 -0700 Subject: [PATCH 095/290] apply only to terminal's --- .../workbench/contrib/accessibility/browser/accessibleView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 7432219e9ea..a084209a4bf 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -216,7 +216,7 @@ export class AccessibleView extends Disposable { this._accessibleViewVerbosityEnabled.set(this._configurationService.getValue(this._currentProvider.verbositySettingKey)); this._updateToolbar(this._currentProvider.actions, this._currentProvider.options.type); } - if (e.affectsConfiguration(TerminalSettingId.HideAccessibleView)) { + if (e.affectsConfiguration(TerminalSettingId.HideAccessibleView) && this._currentProvider?.id === AccessibleViewProviderId.Terminal) { this._container.classList.toggle('hide', this._configurationService.getValue(TerminalSettingId.HideAccessibleView)); } })); From 2ac11b37d27ba16d75d6e64286a827f99d1369ce Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 14:47:14 -0700 Subject: [PATCH 096/290] Add 'default agent' concept (#195599) So that every request can be routed through an agent --- src/vs/workbench/api/common/extHostChatAgents2.ts | 9 +++++++++ .../chat/browser/contrib/chatInputEditorContrib.ts | 3 ++- src/vs/workbench/contrib/chat/common/chatAgents.ts | 8 +++++++- .../contrib/chat/common/chatServiceImpl.ts | 12 +++++++----- .../extensions/common/extensionsApiProposals.ts | 1 + .../vscode.proposed.defaultChatAgent.d.ts | 14 ++++++++++++++ 6 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 13a6b7d6b85..f765884967e 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -185,6 +185,7 @@ class ExtHostChatAgent { private _description: string | undefined; private _fullName: string | undefined; private _iconPath: URI | undefined; + private _isDefault: boolean | undefined; private _onDidReceiveFeedback = new Emitter(); private _onDidPerformAction = new Emitter(); @@ -258,6 +259,7 @@ class ExtHostChatAgent { icon: this._iconPath, hasSlashCommands: this._slashCommandProvider !== undefined, hasFollowup: this._followupProvider !== undefined, + isDefault: this._isDefault }); updateScheduled = false; }); @@ -304,6 +306,13 @@ class ExtHostChatAgent { that._followupProvider = v; updateMetadataSoon(); }, + get isDefault() { + return that._isDefault; + }, + set isDefault(v) { + that._isDefault = v; + updateMetadataSoon(); + }, get onDidReceiveFeedback() { return that._onDidReceiveFeedback.event; }, diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index 3c015b89c42..bb7a7b77e79 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -329,7 +329,8 @@ class AgentCompletions extends Disposable { return null; } - const agents = this.chatAgentService.getAgents(); + const agents = this.chatAgentService.getAgents() + .filter(a => !a.metadata.isDefault); return { suggestions: agents.map((c, i) => { const withAt = `@${c.id}`; diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index 525137f000e..886c5aa60a7 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -5,6 +5,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; +import { Iterable } from 'vs/base/common/iterator'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -36,7 +37,7 @@ export interface IChatAgentMetadata { description?: string; // subCommands: IChatAgentCommand[]; requireCommand?: boolean; // Do some agents not have a default action? - isImplicit?: boolean; // Only @workspace. slash commands get promoted to the top-level and this agent is invoked when those are used + isDefault?: boolean; // The agent invoked when no agent is specified fullName?: string; icon?: URI; } @@ -69,6 +70,7 @@ export interface IChatAgentService { getFollowups(id: string, sessionId: string, token: CancellationToken): Promise; getAgents(): Array; getAgent(id: string): IChatAgent | undefined; + getDefaultAgent(): IChatAgent | undefined; hasAgent(id: string): boolean; updateAgent(id: string, updateMetadata: IChatAgentMetadata): void; } @@ -112,6 +114,10 @@ export class ChatAgentService extends Disposable implements IChatAgentService { this._onDidChangeAgents.fire(); } + getDefaultAgent(): IChatAgent | undefined { + return Iterable.find(this._agents.values(), a => !!a.agent.metadata.isDefault)?.agent; + } + getAgents(): Array { return Array.from(this._agents.values(), v => v.agent); } diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index eb3b8680044..92ae2ff6307 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -507,7 +507,9 @@ export class ChatService extends Disposable implements IChatService { let rawResponse: IChatResponse | null | undefined; let agentOrCommandFollowups: Promise | undefined = undefined; - if (typeof message === 'string' && agentPart) { + const defaultAgent = this.chatAgentService.getDefaultAgent(); + if (typeof message === 'string' && (agentPart || defaultAgent)) { + const agent = (agentPart?.agent ?? defaultAgent)!; const history: IChatMessage[] = []; for (const request of model.getRequests()) { if (!request.response) { @@ -518,11 +520,11 @@ export class ChatService extends Disposable implements IChatService { history.push({ role: ChatMessageRole.Assistant, content: request.response.response.asString() }); } - request = model.addRequest(parsedRequest, agentPart.agent); + request = model.addRequest(parsedRequest, agent); const requestProps: IChatAgentRequest = { sessionId, requestId: generateUuid(), - message: message, + message, variables: {}, command: agentSlashCommandPart?.command.name ?? '', }; @@ -532,7 +534,7 @@ export class ChatService extends Disposable implements IChatService { requestProps.message = varResult.prompt; } - const agentResult = await this.chatAgentService.invokeAgent(agentPart.agent.id, requestProps, new Progress(p => { + const agentResult = await this.chatAgentService.invokeAgent(agent.id, requestProps, new Progress(p => { progressCallback(p); }), history, token); rawResponse = { @@ -541,7 +543,7 @@ export class ChatService extends Disposable implements IChatService { timings: agentResult.timings }; agentOrCommandFollowups = agentResult?.followUp ? Promise.resolve(agentResult.followUp) : - this.chatAgentService.getFollowups(agentPart.agent.id, sessionId, CancellationToken.None); + this.chatAgentService.getFollowups(agent.id, sessionId, CancellationToken.None); } else if (commandPart && typeof message === 'string' && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) { request = model.addRequest(parsedRequest); // contributed slash commands diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 3ebf8b558b3..c5e30e4de43 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -38,6 +38,7 @@ export const allApiProposals = Object.freeze({ createFileSystemWatcher: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.createFileSystemWatcher.d.ts', customEditorMove: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorMove.d.ts', debugFocus: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.debugFocus.d.ts', + defaultChatAgent: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts', diffCommand: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffCommand.d.ts', diffContentOptions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffContentOptions.d.ts', documentFiltersExclusive: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.documentFiltersExclusive.d.ts', diff --git a/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts b/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts new file mode 100644 index 00000000000..573b0668744 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + export interface ChatAgent2 { + /** + * When true, this agent is invoked by default when no other agent is being invoked + */ + isDefault?: boolean; + } +} From 7314532ae976809f0a3a72c93f25e9094ae3e28a Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 13 Oct 2023 14:49:32 -0700 Subject: [PATCH 097/290] eng: fix extension test runner on windows (#195600) --- .vscode-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode-test.js b/.vscode-test.js index 9b9a35e5cbd..3741ea0eb44 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -57,7 +57,7 @@ module.exports = defineConfig(extensions.map(extension => { if (!config.platform || config.platform === 'desktop') { config.launchArgs = defaultLaunchArgs; config.useInstallation = { - fromPath: process.env.INTEGRATION_TEST_ELECTRON_PATH || `${__dirname}/scripts/code.${process.platform === 'win32' ? 'cmd' : 'sh'}`, + fromPath: process.env.INTEGRATION_TEST_ELECTRON_PATH || `${__dirname}/scripts/code.${process.platform === 'win32' ? 'bat' : 'sh'}`, }; config.env = { ...config.env, From 2abb82ec24e8d84efa8ece90c9e60ee643b9ddfe Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 14:52:29 -0700 Subject: [PATCH 098/290] rm provider check --- .../workbench/contrib/accessibility/browser/accessibleView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index a084209a4bf..7432219e9ea 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -216,7 +216,7 @@ export class AccessibleView extends Disposable { this._accessibleViewVerbosityEnabled.set(this._configurationService.getValue(this._currentProvider.verbositySettingKey)); this._updateToolbar(this._currentProvider.actions, this._currentProvider.options.type); } - if (e.affectsConfiguration(TerminalSettingId.HideAccessibleView) && this._currentProvider?.id === AccessibleViewProviderId.Terminal) { + if (e.affectsConfiguration(TerminalSettingId.HideAccessibleView)) { this._container.classList.toggle('hide', this._configurationService.getValue(TerminalSettingId.HideAccessibleView)); } })); From 070edaede767aea303709470584cbac99c93eb5c Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Oct 2023 14:57:50 -0700 Subject: [PATCH 099/290] apply to all accessible views --- src/vs/platform/terminal/common/terminal.ts | 1 - .../accessibility/browser/accessibilityConfiguration.ts | 9 ++++++++- .../contrib/accessibility/browser/accessibleView.ts | 7 +++---- .../contrib/terminal/common/terminalConfiguration.ts | 5 ----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 1f7225a801c..2465abe9ad6 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -117,7 +117,6 @@ export const enum TerminalSettingId { IgnoreBracketedPasteMode = 'terminal.integrated.ignoreBracketedPasteMode', FocusAfterRun = 'terminal.integrated.focusAfterRun', AccessibleViewPreserveCursorPosition = 'terminal.integrated.accessibleViewPreserveCursorPosition', - HideAccessibleView = 'terminal.integrated.hideAccessibleView', // Debug settings that are hidden from user diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts index 93dacbcc23a..b0faf8916b8 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts @@ -23,7 +23,8 @@ export const accessibleViewCurrentProviderId = new RawContextKey('access */ export const enum AccessibilityWorkbenchSettingId { DimUnfocusedEnabled = 'accessibility.dimUnfocused.enabled', - DimUnfocusedOpacity = 'accessibility.dimUnfocused.opacity' + DimUnfocusedOpacity = 'accessibility.dimUnfocused.opacity', + HideAccessibleView = 'accessibility.hideAccessibleView' } export const enum ViewDimUnfocusedOpacityProperties { @@ -159,6 +160,12 @@ export function registerAccessibilityConfiguration() { default: ViewDimUnfocusedOpacityProperties.Default, tags: ['accessibility'], scope: ConfigurationScope.APPLICATION, + }, + [AccessibilityWorkbenchSettingId.HideAccessibleView]: { + description: localize('terminal.integrated.hideAccessibleView', "Controls whether the terminal's accessible view is hidden."), + type: 'boolean', + default: false, + tags: ['accessibility'] } } }); diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 7432219e9ea..751f8aa7bd0 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -38,8 +38,7 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; -import { AccessibilityVerbositySettingId, AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; +import { AccessibilityVerbositySettingId, AccessibilityWorkbenchSettingId, AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; @@ -216,8 +215,8 @@ export class AccessibleView extends Disposable { this._accessibleViewVerbosityEnabled.set(this._configurationService.getValue(this._currentProvider.verbositySettingKey)); this._updateToolbar(this._currentProvider.actions, this._currentProvider.options.type); } - if (e.affectsConfiguration(TerminalSettingId.HideAccessibleView)) { - this._container.classList.toggle('hide', this._configurationService.getValue(TerminalSettingId.HideAccessibleView)); + if (e.affectsConfiguration(AccessibilityWorkbenchSettingId.HideAccessibleView)) { + this._container.classList.toggle('hide', this._configurationService.getValue(AccessibilityWorkbenchSettingId.HideAccessibleView)); } })); this._register(this._editorWidget.onDidDispose(() => this._resetContextKeys())); diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 2d6b942d632..a12b0440283 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -619,11 +619,6 @@ const terminalConfiguration: IConfigurationNode = { markdownDescription: localize('terminal.integrated.accessibleViewPreserveCursorPosition', "Preserve the cursor position on reopen of the terminal's accessible view rather than setting it to the bottom of the buffer."), type: 'boolean', default: false - }, - [TerminalSettingId.HideAccessibleView]: { - description: localize('terminal.integrated.hideAccessibleView', "Controls whether the terminal's accessible view is hidden."), - type: 'boolean', - default: false } } }; From 583d56685fe79d71c8eb83f9848259adeb2bbaf2 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 14:50:34 -0700 Subject: [PATCH 100/290] use test extension to test extensions --- .vscode-test.js | 10 ++++++++++ scripts/test-integration.bat | 8 ++------ scripts/test-integration.sh | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.vscode-test.js b/.vscode-test.js index 3741ea0eb44..069cd0ac6c0 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -20,6 +20,16 @@ const extensions = [ workspaceFolder: `extensions/markdown-language-features/test-workspace`, mocha: { timeout: 60_000 } }, + { + label: 'ipynb', + workspaceFolder: '%TEMPDIR%/ipynb-%RANDOM%', + mocha: { timeout: 60_000 } + }, + { + label: 'notebook-renderers', + workspaceFolder: '%TEMPDIR%/nbout-%RANDOM%', + mocha: { timeout: 60_000 } + }, ]; diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 16efa750a49..1834f26162d 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -77,16 +77,12 @@ if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ### Ipynb tests -set IPYNBWORKSPACE=%TEMPDIR%\ipynb-%RANDOM% -mkdir %IPYNBWORKSPACE% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %IPYNBWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\ipynb --extensionTestsPath=%~dp0\..\extensions\ipynb\out\test %API_TESTS_EXTRA_ARGS% +call yarn test-extension -l ipynb if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ### Notebook Output tests -set NBOUTWORKSPACE=%TEMPDIR%\nbout-%RANDOM% -mkdir %NBOUTWORKSPACE% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %NBOUTWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\notebook-renderers --extensionTestsPath=%~dp0\..\extensions\notebook-renderers\out\test %API_TESTS_EXTRA_ARGS% +call yarn test-extension -l notebook-renderers if %errorlevel% neq 0 exit /b %errorlevel% echo. diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 35b97b58e59..6a7a1fe4a75 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -97,13 +97,13 @@ kill_app echo echo "### Ipynb tests" echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/ipynb --extensionTestsPath=$ROOT/extensions/ipynb/out/test $API_TESTS_EXTRA_ARGS +yarn test-extension -l ipynb kill_app echo echo "### Notebook Output tests" echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/notebook-renderers --extensionTestsPath=$ROOT/extensions/notebook-renderers/out/test $API_TESTS_EXTRA_ARGS +yarn test-extension -l notebook-renderers kill_app echo From e614d43eb4f00baa1ea50a9db7b6362e14819463 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 15:36:34 -0700 Subject: [PATCH 101/290] generate a valid temp directory --- .vscode-test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode-test.js b/.vscode-test.js index 069cd0ac6c0..e09b8443b7f 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -7,6 +7,7 @@ const path = require('path'); const { defineConfig } = require('@vscode/test-cli'); +const os = require('os'); /** * A list of extension folders who have opted into tests, or configuration objects. @@ -22,12 +23,12 @@ const extensions = [ }, { label: 'ipynb', - workspaceFolder: '%TEMPDIR%/ipynb-%RANDOM%', + workspaceFolder: path.join(os.tmpdir(), `ipynb-${Math.floor(Math.random() * 100000)}`), mocha: { timeout: 60_000 } }, { label: 'notebook-renderers', - workspaceFolder: '%TEMPDIR%/nbout-%RANDOM%', + workspaceFolder: path.join(os.tmpdir(), `nbout-${Math.floor(Math.random() * 100000)}`), mocha: { timeout: 60_000 } }, ]; From 4efef1f42c3214705c39d6953f7d71c876538272 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 16:09:20 -0700 Subject: [PATCH 102/290] Add missing proposed API check (#195605) --- src/vs/workbench/api/common/extHostChatAgents2.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index f765884967e..c1dd23a6965 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -19,7 +19,7 @@ import { ChatAgentResultFeedbackKind } from 'vs/workbench/api/common/extHostType import { IChatAgentCommand, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents'; import { IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; import { IChatFollowup, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; -import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import type * as vscode from 'vscode'; export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { @@ -307,9 +307,11 @@ class ExtHostChatAgent { updateMetadataSoon(); }, get isDefault() { + checkProposedApiEnabled(that.extension, 'defaultChatAgent'); return that._isDefault; }, set isDefault(v) { + checkProposedApiEnabled(that.extension, 'defaultChatAgent'); that._isDefault = v; updateMetadataSoon(); }, From 54afbddf867c0c03baf67e5184dd0a07b7abf26a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 16:13:12 -0700 Subject: [PATCH 103/290] Update distro (#195604) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1401d9cb39c..860e50402fa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.84.0", - "distro": "ca54f82b1adb64bbf5601501cc4edef8043f045c", + "distro": "f69d4735763562c6fd1d2a56596fe808865081ed", "author": { "name": "Microsoft Corporation" }, From e41e8bca4d48d68a9bc8c9e28eb6577c5be6573c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 18:39:13 -0700 Subject: [PATCH 104/290] Fix tests --- .../common/__snapshots__/Chat_can_deserialize.0.snap | 9 +-------- .../test/common/__snapshots__/Chat_can_serialize.1.snap | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap index bd85fe7d442..cdc587a8cad 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap @@ -26,14 +26,7 @@ } ] }, - response: [ - { - value: "", - isTrusted: false, - supportThemeIcons: false, - supportHtml: false - } - ], + response: [ ], responseErrorDetails: undefined, followups: undefined, isCanceled: false, diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap index cc7309c9489..1d0f757b587 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap @@ -26,14 +26,7 @@ ], text: "test request" }, - response: [ - { - value: "", - isTrusted: false, - supportThemeIcons: false, - supportHtml: false - } - ], + response: [ ], responseErrorDetails: undefined, followups: undefined, isCanceled: false, From 267f09acea3b2416861661d702b3be767bdeef6e Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 23:10:56 -0700 Subject: [PATCH 105/290] Don't pass the followup object in with the request (#195610) --- .../workbench/api/common/extHost.protocol.ts | 2 +- src/vs/workbench/api/common/extHostChat.ts | 2 +- .../contrib/chat/browser/chatInputPart.ts | 2 +- .../contrib/chat/browser/chatWidget.ts | 12 ++++--- .../contrib/chat/common/chatModel.ts | 8 ++--- .../contrib/chat/common/chatService.ts | 4 +-- .../contrib/chat/common/chatServiceImpl.ts | 31 ++++++++----------- .../vscode.proposed.interactive.d.ts | 4 +-- 8 files changed, 31 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index bf0b7392ca4..88b6f6904a3 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1229,7 +1229,7 @@ export interface IChatDto { } export interface IChatRequestDto { - message: string | IChatReplyFollowup; + message: string; variables?: Record; } diff --git a/src/vs/workbench/api/common/extHostChat.ts b/src/vs/workbench/api/common/extHostChat.ts index 683cff67437..f90aff58189 100644 --- a/src/vs/workbench/api/common/extHostChat.ts +++ b/src/vs/workbench/api/common/extHostChat.ts @@ -189,7 +189,7 @@ export class ExtHostChat implements ExtHostChatShape { const requestObj: vscode.InteractiveRequest = { session: realSession, - message: typeof request.message === 'string' ? request.message : typeConvert.ChatReplyFollowup.to(request.message), + message: request.message, variables: {} }; diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 517a7e1faea..55116ec3aa5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -156,7 +156,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge return this._inputEditor.hasWidgetFocus(); } - async acceptInput(query?: string | IChatReplyFollowup): Promise { + async acceptInput(query?: string): Promise { const editorValue = this._inputEditor.getValue(); if (!query && editorValue) { // Followups and programmatic messages don't go to history diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 706319d7b6f..a38f5b899b6 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -325,7 +325,8 @@ export class ChatWidget extends Disposable implements IChatWidget { rendererDelegate )); this._register(this.renderer.onDidClickFollowup(item => { - this.acceptInput(item); + // is this used anymore? + this.acceptInput(item.message); })); this.tree = >scopedInstantiationService.createInstance( @@ -408,7 +409,10 @@ export class ChatWidget extends Disposable implements IChatWidget { this.inputPart.render(container, '', this); this._register(this.inputPart.onDidFocus(() => this._onDidFocus.fire())); - this._register(this.inputPart.onDidAcceptFollowup(followup => this.acceptInput(followup))); + this._register(this.inputPart.onDidAcceptFollowup(followup => { + // this.chatService.notifyUserAction + this.acceptInput(followup.message); + })); this._register(this.inputPart.onDidChangeHeight(() => this.bodyDimension && this.layout(this.bodyDimension.height, this.bodyDimension.width))); } @@ -469,14 +473,14 @@ export class ChatWidget extends Disposable implements IChatWidget { this.inputPart.setValue(value); } - async acceptInput(query?: string | IChatReplyFollowup): Promise { + async acceptInput(query?: string): Promise { if (this.viewModel) { this._onDidAcceptInput.fire(); const editorValue = this.inputPart.inputEditor.getValue(); this._chatAccessibilityService.acceptRequest(); const input = query ?? editorValue; - const usedSlashCommand = this.lookupSlashCommand(typeof input === 'string' ? input : input.message); + const usedSlashCommand = this.lookupSlashCommand(input); const result = await this.chatService.sendRequest(this.viewModel.sessionId, input, usedSlashCommand); if (result) { diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 2d4dce54ed5..2100149d975 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -92,7 +92,7 @@ export class ChatRequestModel implements IChatRequestModel { constructor( public readonly session: ChatModel, - public readonly message: IParsedChatRequest | IChatReplyFollowup, + public readonly message: IParsedChatRequest, private _providerRequestId?: string) { this._id = 'request_' + ChatRequestModel.nextId++; } @@ -521,7 +521,7 @@ export class ChatModel extends Disposable implements IChatModel { get title(): string { const firstRequestMessage = firstOrDefault(this._requests)?.message; - const message = (firstRequestMessage && 'text' in firstRequestMessage) ? firstRequestMessage.text : firstRequestMessage?.message ?? ''; + const message = firstRequestMessage?.text ?? ''; return message.split('\n')[0].substring(0, 50); } @@ -645,7 +645,7 @@ export class ChatModel extends Disposable implements IChatModel { return this._requests; } - addRequest(message: IParsedChatRequest | IChatReplyFollowup, chatAgent?: IChatAgent): ChatRequestModel { + addRequest(message: IParsedChatRequest, chatAgent?: IChatAgent): ChatRequestModel { if (!this._session) { throw new Error('addRequest: No session'); } @@ -753,7 +753,7 @@ export class ChatModel extends Disposable implements IChatModel { requests: this._requests.map((r): ISerializableChatRequestData => { return { providerRequestId: r.providerRequestId, - message: 'text' in r.message ? r.message : r.message.message, + message: r.message, response: r.response ? r.response.response.value : undefined, responseErrorDetails: r.response?.errorDetails, followups: r.response?.followups, diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index f71d8b7ae24..b9d1fe9af4a 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -28,7 +28,7 @@ export interface IChat { export interface IChatRequest { session: IChat; - message: string | IChatReplyFollowup; + message: string; variables: Record; } @@ -270,7 +270,7 @@ export interface IChatService { /** * Returns whether the request was accepted. */ - sendRequest(sessionId: string, message: string | IChatReplyFollowup, usedSlashCommand?: ISlashCommand): Promise<{ responseCompletePromise: Promise } | undefined>; + sendRequest(sessionId: string, message: string, usedSlashCommand?: ISlashCommand): Promise<{ responseCompletePromise: Promise } | undefined>; removeRequest(sessionid: string, requestId: string): Promise; cancelCurrentRequestForSession(sessionId: string): void; getSlashCommands(sessionId: string, token: CancellationToken): Promise; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 92ae2ff6307..8791a463620 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -25,7 +25,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IChatAgentRequest, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; import { ChatModel, ChatModelInitState, ChatRequestModel, ChatWelcomeMessageModel, IChatModel, ISerializableChatData, ISerializableChatsData, isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel'; -import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; +import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser'; import { IChat, IChatCompleteResponse, IChatDetail, IChatDynamicRequest, IChatFollowup, IChatProgress, IChatProvider, IChatProviderInfo, IChatReplyFollowup, IChatRequest, IChatResponse, IChatService, IChatTransferredSessionData, IChatUserActionEvent, ISlashCommand, InteractiveSessionCopyKind, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; @@ -412,10 +412,9 @@ export class ChatService extends Disposable implements IChatService { return this._startSession(data.providerId, data, CancellationToken.None); } - async sendRequest(sessionId: string, request: string | IChatReplyFollowup, usedSlashCommand?: ISlashCommand): Promise<{ responseCompletePromise: Promise } | undefined> { - const messageText = typeof request === 'string' ? request : request.message; - this.trace('sendRequest', `sessionId: ${sessionId}, message: ${messageText.substring(0, 20)}${messageText.length > 20 ? '[...]' : ''}}`); - if (!messageText.trim()) { + async sendRequest(sessionId: string, request: string, usedSlashCommand?: ISlashCommand): Promise<{ responseCompletePromise: Promise } | undefined> { + this.trace('sendRequest', `sessionId: ${sessionId}, message: ${request.substring(0, 20)}${request.length > 20 ? '[...]' : ''}}`); + if (!request.trim()) { this.trace('sendRequest', 'Rejected empty message'); return; } @@ -440,10 +439,8 @@ export class ChatService extends Disposable implements IChatService { return { responseCompletePromise: this._sendRequestAsync(model, sessionId, provider, request, usedSlashCommand) }; } - private async _sendRequestAsync(model: ChatModel, sessionId: string, provider: IChatProvider, message: string | IChatReplyFollowup, usedSlashCommand?: ISlashCommand): Promise { - const parsedRequest = typeof message === 'string' ? - await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(sessionId, message) : - message; // Handle the followup type along with the response + private async _sendRequestAsync(model: ChatModel, sessionId: string, provider: IChatProvider, message: string, usedSlashCommand?: ISlashCommand): Promise { + const parsedRequest = await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(sessionId, message); let request: ChatRequestModel; const agentPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestAgentPart => r instanceof ChatRequestAgentPart); @@ -451,9 +448,7 @@ export class ChatService extends Disposable implements IChatService { const commandPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestSlashCommandPart => r instanceof ChatRequestSlashCommandPart); let gotProgress = false; - const requestType = typeof message === 'string' ? - commandPart ? 'slashCommand' : 'string' : - 'followup'; + const requestType = commandPart ? 'slashCommand' : 'string'; const rawResponsePromise = createCancelablePromise(async token => { const progressCallback = (progress: IChatProgress) => { @@ -508,7 +503,7 @@ export class ChatService extends Disposable implements IChatService { let agentOrCommandFollowups: Promise | undefined = undefined; const defaultAgent = this.chatAgentService.getDefaultAgent(); - if (typeof message === 'string' && (agentPart || defaultAgent)) { + if (agentPart || defaultAgent) { const agent = (agentPart?.agent ?? defaultAgent)!; const history: IChatMessage[] = []; for (const request of model.getRequests()) { @@ -516,7 +511,7 @@ export class ChatService extends Disposable implements IChatService { continue; } - history.push({ role: ChatMessageRole.User, content: 'text' in request.message ? request.message.text : request.message.message }); + history.push({ role: ChatMessageRole.User, content: request.message.text }); history.push({ role: ChatMessageRole.Assistant, content: request.response.response.asString() }); } @@ -544,7 +539,7 @@ export class ChatService extends Disposable implements IChatService { }; agentOrCommandFollowups = agentResult?.followUp ? Promise.resolve(agentResult.followUp) : this.chatAgentService.getFollowups(agent.id, sessionId, CancellationToken.None); - } else if (commandPart && typeof message === 'string' && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) { + } else if (commandPart && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) { request = model.addRequest(parsedRequest); // contributed slash commands // TODO: spell this out in the UI @@ -553,7 +548,7 @@ export class ChatService extends Disposable implements IChatService { if (!request.response) { continue; } - history.push({ role: ChatMessageRole.User, content: 'text' in request.message ? request.message.text : request.message.message }); + history.push({ role: ChatMessageRole.User, content: request.message.text }); history.push({ role: ChatMessageRole.Assistant, content: request.response.response.asString() }); } const commandResult = await this.chatSlashCommandService.executeCommand(commandPart.slashCommand.command, message.substring(commandPart.slashCommand.command.length + 1).trimStart(), new Progress(p => { @@ -690,7 +685,7 @@ export class ChatService extends Disposable implements IChatService { return Array.from(this._providers.keys()); } - async addCompleteRequest(sessionId: string, message: string | IParsedChatRequest, response: IChatCompleteResponse): Promise { + async addCompleteRequest(sessionId: string, message: string, response: IChatCompleteResponse): Promise { this.trace('addCompleteRequest', `message: ${message}`); const model = this._sessionModels.get(sessionId); @@ -699,7 +694,7 @@ export class ChatService extends Disposable implements IChatService { } await model.waitForInitialization(); - const parsedRequest = typeof message === 'string' ? await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(sessionId, message) : message; + const parsedRequest = await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(sessionId, message); const request = model.addRequest(parsedRequest); if (typeof response.message === 'string') { model.acceptResponseProgress(request, { content: response.message }); diff --git a/src/vscode-dts/vscode.proposed.interactive.d.ts b/src/vscode-dts/vscode.proposed.interactive.d.ts index 30708bfda72..d10a0946dfa 100644 --- a/src/vscode-dts/vscode.proposed.interactive.d.ts +++ b/src/vscode-dts/vscode.proposed.interactive.d.ts @@ -108,9 +108,7 @@ declare module 'vscode' { export interface InteractiveRequest { session: InteractiveSession; - message: string | InteractiveSessionReplyFollowup; - // TODO@API move to agent - // slashCommand?: InteractiveSessionSlashCommand; + message: string; } export interface InteractiveResponseErrorDetails { From bf9a3c34b06d9050bc39ef308653a6b447c5421b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sat, 14 Oct 2023 09:48:58 -0700 Subject: [PATCH 106/290] Move list to the bottom of the response --- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index caf77ba4c53..808a8a64147 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -236,8 +236,8 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer Date: Sat, 14 Oct 2023 10:44:52 -0700 Subject: [PATCH 107/290] Render warning label as markdown, and some styling updates --- .../contrib/chat/browser/chatListRenderer.ts | 14 ++++++++------ .../contrib/chat/browser/media/chat.css | 17 +++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 808a8a64147..31d1e0eb7ed 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -339,9 +339,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer :last-child:not(.rendered-markdown) { - /* The container has padding on all sides except the bottom. The last element needs to provide this margin. rendered-markdown has its own margin. - TODO Another approach could be removing the margin on the very last element inside the markdown container? */ - margin-bottom: 16px; -} - -.interactive-item-container .value > .interactive-response-error-details:not(:last-child) { - margin-bottom: 8px; +.interactive-item-container .value > :last-child.rendered-markdown > :last-child { + margin-bottom: 0px; } .interactive-item-container .value .rendered-markdown h1 { @@ -330,6 +323,10 @@ gap: 6px; } +.interactive-response .interactive-response-error-details .rendered-markdown :last-child { + margin-bottom: 0px; +} + .interactive-response .interactive-response-error-details .codicon { margin-top: 1px; } From f01b050693eac7747393cc2691613d9956f813e9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 14 Oct 2023 21:45:48 +0200 Subject: [PATCH 108/290] speech - wire in to chat actions (#195469) * speech - wire in to chat actions * fixes * adjust to modul * fix cancel * adopt speech service directly * add auto accept * undo * drop identifier need --- .../workbench/api/browser/mainThreadSpeech.ts | 10 +- .../workbench/api/common/extHost.protocol.ts | 3 +- src/vs/workbench/api/common/extHostSpeech.ts | 33 +++-- .../actions/voiceChatActions.ts | 139 +++++++----------- .../electron-sandbox/chat.contribution.ts | 37 ++++- .../contrib/speech/common/speechService.ts | 32 +++- 6 files changed, 141 insertions(+), 113 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadSpeech.ts b/src/vs/workbench/api/browser/mainThreadSpeech.ts index c3efdd37cd2..d0c7acdc2b6 100644 --- a/src/vs/workbench/api/browser/mainThreadSpeech.ts +++ b/src/vs/workbench/api/browser/mainThreadSpeech.ts @@ -5,7 +5,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostContext, ExtHostSpeechShape, MainContext, MainThreadSpeechShape } from 'vs/workbench/api/common/extHost.protocol'; import { ISpeechProviderMetadata, ISpeechService, ISpeechToTextEvent } from 'vs/workbench/contrib/speech/common/speechService'; @@ -39,20 +39,22 @@ export class MainThreadSpeech extends Disposable implements MainThreadSpeechShap const registration = this.speechService.registerSpeechProvider(identifier, { metadata, createSpeechToTextSession: token => { + const disposables = new DisposableStore(); const cts = new CancellationTokenSource(token); const session = Math.random(); - this.proxy.$createSpeechToTextSession(handle, session, cts.token); + this.proxy.$createSpeechToTextSession(handle, session); + disposables.add(token.onCancellationRequested(() => this.proxy.$cancelSpeechToTextSession(session))); - const onDidChange = new Emitter(); + const onDidChange = disposables.add(new Emitter()); this.providerSessions.set(session, { onDidChange }); return { onDidChange: onDidChange.event, dispose: () => { cts.dispose(true); - onDidChange.dispose(); this.providerSessions.delete(session); + disposables.dispose(); } }; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 88b6f6904a3..160a072b71a 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1142,7 +1142,8 @@ export interface MainThreadSpeechShape extends IDisposable { } export interface ExtHostSpeechShape { - $createSpeechToTextSession(handle: number, session: number, token: CancellationToken): Promise; + $createSpeechToTextSession(handle: number, session: number): Promise; + $cancelSpeechToTextSession(session: number): Promise; } export interface MainThreadChatProviderShape extends IDisposable { diff --git a/src/vs/workbench/api/common/extHostSpeech.ts b/src/vs/workbench/api/common/extHostSpeech.ts index aa937496aa3..8207ab47a47 100644 --- a/src/vs/workbench/api/common/extHostSpeech.ts +++ b/src/vs/workbench/api/common/extHostSpeech.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken } from 'vs/base/common/cancellation'; -import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ExtHostSpeechShape, IMainContext, MainContext, MainThreadSpeechShape } from 'vs/workbench/api/common/extHost.protocol'; import type * as vscode from 'vscode'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -14,7 +14,9 @@ export class ExtHostSpeech implements ExtHostSpeechShape { private static ID_POOL = 1; private readonly proxy: MainThreadSpeechShape; + private readonly providers = new Map(); + private readonly sessions = new Map(); constructor( mainContext: IMainContext @@ -22,29 +24,32 @@ export class ExtHostSpeech implements ExtHostSpeechShape { this.proxy = mainContext.getProxy(MainContext.MainThreadSpeech); } - async $createSpeechToTextSession(handle: number, session: number, token: CancellationToken): Promise { + async $createSpeechToTextSession(handle: number, session: number): Promise { const provider = this.providers.get(handle); if (!provider) { return; } - const speechToTextSession = provider.provideSpeechToTextSession(token); - if (token.isCancellationRequested) { - return; - } + const disposables = new DisposableStore(); - const listener = speechToTextSession.onDidChange(e => { - if (token.isCancellationRequested) { + const cts = new CancellationTokenSource(); + this.sessions.set(session, cts); + + const speechToTextSession = disposables.add(provider.provideSpeechToTextSession(cts.token)); + disposables.add(speechToTextSession.onDidChange(e => { + if (cts.token.isCancellationRequested) { return; } this.proxy.$emitSpeechToTextEvent(session, e); - }); + })); - token.onCancellationRequested(() => { - listener.dispose(); - speechToTextSession.dispose(); - }); + disposables.add(cts.token.onCancellationRequested(() => disposables.dispose())); + } + + async $cancelSpeechToTextSession(session: number): Promise { + this.sessions.get(session)?.dispose(true); + this.sessions.delete(session); } registerProvider(extension: ExtensionIdentifier, identifier: string, provider: vscode.SpeechProvider): IDisposable { diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index 190cb579e00..033340c786f 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -9,25 +9,21 @@ import { firstOrDefault } from 'vs/base/common/arrays'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Codicon } from 'vs/base/common/codicons'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; -import { equalsIgnoreCase } from 'vs/base/common/strings'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Action2, MenuId } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { spinningLoading } from 'vs/platform/theme/common/iconRegistry'; import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions'; import { IChatWidget, IChatWidgetService, IQuickChatService } from 'vs/workbench/contrib/chat/browser/chat'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; -import { IWorkbenchVoiceRecognitionService } from 'vs/workbench/services/voiceRecognition/electron-sandbox/workbenchVoiceRecognitionService'; import { MENU_INLINE_CHAT_WIDGET } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { getCodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; -import product from 'vs/platform/product/common/product'; import { ActiveEditorContext } from 'vs/workbench/common/contextkeys'; import { IViewsService } from 'vs/workbench/common/views'; import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService'; @@ -35,6 +31,8 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { KeyCode } from 'vs/base/common/keyCodes'; import { isExecuteActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatExecuteActions'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; +import { ISpeechService, SpeechToTextStatus } from 'vs/workbench/contrib/speech/common/speechService'; +import { RunOnceScheduler } from 'vs/base/common/async'; const CONTEXT_VOICE_CHAT_GETTING_READY = new RawContextKey('voiceChatGettingReady', false, { type: 'boolean', description: localize('voiceChatGettingReady', "True when getting ready for receiving voice input from the microphone for voice chat.") }); const CONTEXT_VOICE_CHAT_IN_PROGRESS = new RawContextKey('voiceChatInProgress', false, { type: 'boolean', description: localize('voiceChatInProgress', "True when voice recording from microphone is in progress for voice chat.") }); @@ -192,6 +190,7 @@ class VoiceChatSessionControllerFactory { } interface ActiveVoiceChatSession { + readonly id: number; readonly controller: IVoiceChatSessionController; readonly disposables: DisposableStore; } @@ -220,37 +219,64 @@ class VoiceChatSessions { constructor( @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IWorkbenchVoiceRecognitionService private readonly voiceRecognitionService: IWorkbenchVoiceRecognitionService + @ISpeechService private readonly speechService: ISpeechService ) { } async start(controller: IVoiceChatSessionController): Promise { this.stop(); - const voiceChatSessionId = ++this.voiceChatSessionIds; - this.currentVoiceChatSession = { + const sessionId = ++this.voiceChatSessionIds; + const session = this.currentVoiceChatSession = { + id: sessionId, controller, disposables: new DisposableStore() }; const cts = new CancellationTokenSource(); - this.currentVoiceChatSession.disposables.add(toDisposable(() => cts.dispose(true))); + session.disposables.add(toDisposable(() => cts.dispose(true))); - this.currentVoiceChatSession.disposables.add(controller.onDidAcceptInput(() => this.stop(voiceChatSessionId, controller.context))); - this.currentVoiceChatSession.disposables.add(controller.onDidCancelInput(() => this.stop(voiceChatSessionId, controller.context))); + session.disposables.add(controller.onDidAcceptInput(() => this.stop(sessionId, controller.context))); + session.disposables.add(controller.onDidCancelInput(() => this.stop(sessionId, controller.context))); controller.updateInput(''); controller.focusInput(); this.voiceChatGettingReadyKey.set(true); - const onDidTranscribe = await this.voiceRecognitionService.transcribe(cts.token, { - onDidCancel: () => this.stop(voiceChatSessionId, controller.context) - }); + const speechToTextSession = session.disposables.add(this.speechService.createSpeechToTextSession(cts.token)); - if (cts.token.isCancellationRequested) { - return; - } + let transcription: string = ''; + const acceptTranscriptionScheduler = session.disposables.add(new RunOnceScheduler(() => session.controller.acceptInput(), 2000)); + session.disposables.add(speechToTextSession.onDidChange(({ status, text }) => { + if (cts.token.isCancellationRequested) { + return; + } + switch (status) { + case SpeechToTextStatus.Started: + this.onDidSpeechToTextSessionStart(controller); + break; + case SpeechToTextStatus.Recognizing: + if (text) { + session.controller.updateInput([transcription, text].join(' ')); + acceptTranscriptionScheduler.cancel(); + } + break; + case SpeechToTextStatus.Recognized: + if (text) { + transcription = [transcription, text].join(' '); + session.controller.updateInput(transcription); + acceptTranscriptionScheduler.schedule(); + } + break; + case SpeechToTextStatus.Stopped: + this.stop(session.id, controller.context); + break; + } + })); + } + + private onDidSpeechToTextSessionStart(controller: IVoiceChatSessionController): void { this.voiceChatGettingReadyKey.set(false); this.voiceChatInProgressKey.set(true); @@ -268,48 +294,6 @@ class VoiceChatSessions { this.voiceChatInEditorInProgressKey.set(true); break; } - - this.registerTranscriptionListener(this.currentVoiceChatSession, onDidTranscribe); - } - - private registerTranscriptionListener(session: ActiveVoiceChatSession, onDidTranscribe: Event) { - let lastText: string | undefined = undefined; - let lastTextSimilarCount = 0; - - session.disposables.add(onDidTranscribe(text => { - if (!text && lastText) { - text = lastText; - } - - if (text) { - if (lastText && this.isSimilarTranscription(text, lastText)) { - lastTextSimilarCount++; - } else { - lastTextSimilarCount = 0; - lastText = text; - } - - if (lastTextSimilarCount >= 2) { - session.controller.acceptInput(); - } else { - session.controller.updateInput(text); - } - } - })); - } - - private isSimilarTranscription(textA: string, textB: string): boolean { - - // Attempt to compare the 2 strings in a way to see - // if they are similar or not. As such we: - // - ignore trailing punctuation - // - collapse all whitespace - // - compare case insensitive - - return equalsIgnoreCase( - textA.replace(/[.,;:!?]+$/, '').replace(/\s+/g, ''), - textB.replace(/[.,;:!?]+$/, '').replace(/\s+/g, '') - ); } stop(voiceChatSessionId = this.voiceChatSessionIds, context?: VoiceChatSessionContext): void { @@ -345,7 +329,7 @@ class VoiceChatSessions { } } -class VoiceChatInChatViewAction extends Action2 { +export class VoiceChatInChatViewAction extends Action2 { static readonly ID = 'workbench.action.chat.voiceChatInChatView'; @@ -372,7 +356,7 @@ class VoiceChatInChatViewAction extends Action2 { } } -class InlineVoiceChatAction extends Action2 { +export class InlineVoiceChatAction extends Action2 { static readonly ID = 'workbench.action.chat.inlineVoiceChat'; @@ -399,7 +383,7 @@ class InlineVoiceChatAction extends Action2 { } } -class QuickVoiceChatAction extends Action2 { +export class QuickVoiceChatAction extends Action2 { static readonly ID = 'workbench.action.chat.quickVoiceChat'; @@ -426,7 +410,7 @@ class QuickVoiceChatAction extends Action2 { } } -class StartVoiceChatAction extends Action2 { +export class StartVoiceChatAction extends Action2 { static readonly ID = 'workbench.action.chat.startVoiceChat'; @@ -478,7 +462,7 @@ class StartVoiceChatAction extends Action2 { } } -class StopVoiceChatAction extends Action2 { +export class StopVoiceChatAction extends Action2 { static readonly ID = 'workbench.action.chat.stopVoiceChat'; @@ -505,7 +489,7 @@ class StopVoiceChatAction extends Action2 { } } -class StopVoiceChatInChatViewAction extends Action2 { +export class StopVoiceChatInChatViewAction extends Action2 { static readonly ID = 'workbench.action.chat.stopVoiceChatInChatView'; @@ -538,7 +522,7 @@ class StopVoiceChatInChatViewAction extends Action2 { } } -class StopVoiceChatInChatEditorAction extends Action2 { +export class StopVoiceChatInChatEditorAction extends Action2 { static readonly ID = 'workbench.action.chat.stopVoiceChatInChatEditor'; @@ -571,7 +555,7 @@ class StopVoiceChatInChatEditorAction extends Action2 { } } -class StopQuickVoiceChatAction extends Action2 { +export class StopQuickVoiceChatAction extends Action2 { static readonly ID = 'workbench.action.chat.stopQuickVoiceChat'; @@ -604,7 +588,7 @@ class StopQuickVoiceChatAction extends Action2 { } } -class StopInlineVoiceChatAction extends Action2 { +export class StopInlineVoiceChatAction extends Action2 { static readonly ID = 'workbench.action.chat.stopInlineVoiceChat'; @@ -637,7 +621,7 @@ class StopInlineVoiceChatAction extends Action2 { } } -class StopVoiceChatAndSubmitAction extends Action2 { +export class StopVoiceChatAndSubmitAction extends Action2 { static readonly ID = 'workbench.action.chat.stopVoiceChatAndSubmit'; @@ -658,20 +642,3 @@ class StopVoiceChatAndSubmitAction extends Action2 { VoiceChatSessions.getInstance(accessor.get(IInstantiationService)).accept(); } } - -export function registerVoiceChatActions() { - if (typeof process.env.VSCODE_VOICE_MODULE_PATH === 'string' && product.quality !== 'stable') { // TODO@bpasero package - registerAction2(VoiceChatInChatViewAction); - registerAction2(QuickVoiceChatAction); - registerAction2(InlineVoiceChatAction); - - registerAction2(StartVoiceChatAction); - registerAction2(StopVoiceChatAction); - registerAction2(StopVoiceChatAndSubmitAction); - - registerAction2(StopVoiceChatInChatViewAction); - registerAction2(StopVoiceChatInChatEditorAction); - registerAction2(StopQuickVoiceChatAction); - registerAction2(StopInlineVoiceChatAction); - } -} diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts b/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts index 1bd74f66eff..409022e8651 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts @@ -3,6 +3,39 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerVoiceChatActions } from 'vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions'; +import { InlineVoiceChatAction, QuickVoiceChatAction, StartVoiceChatAction, StopInlineVoiceChatAction, StopQuickVoiceChatAction, StopVoiceChatAction, StopVoiceChatAndSubmitAction, StopVoiceChatInChatEditorAction, StopVoiceChatInChatViewAction, VoiceChatInChatViewAction } from 'vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { ISpeechService } from 'vs/workbench/contrib/speech/common/speechService'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Event } from 'vs/base/common/event'; +import { registerAction2 } from 'vs/platform/actions/common/actions'; -registerVoiceChatActions(); +function registerVoiceChatActions(): void { + registerAction2(VoiceChatInChatViewAction); + registerAction2(QuickVoiceChatAction); + registerAction2(InlineVoiceChatAction); + + registerAction2(StartVoiceChatAction); + registerAction2(StopVoiceChatAction); + registerAction2(StopVoiceChatAndSubmitAction); + + registerAction2(StopVoiceChatInChatViewAction); + registerAction2(StopVoiceChatInChatEditorAction); + registerAction2(StopQuickVoiceChatAction); + registerAction2(StopInlineVoiceChatAction); +} + +class VoiceChatActionsContributor extends Disposable implements IWorkbenchContribution { + + constructor(@ISpeechService speechService: ISpeechService) { + super(); + + this._register(Event.once(speechService.onDidRegisterSpeechProvider)(() => { + registerVoiceChatActions(); + })); + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(VoiceChatActionsContributor, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/speech/common/speechService.ts b/src/vs/workbench/contrib/speech/common/speechService.ts index 4e54851f69a..c071ce0746d 100644 --- a/src/vs/workbench/contrib/speech/common/speechService.ts +++ b/src/vs/workbench/contrib/speech/common/speechService.ts @@ -3,11 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { firstOrDefault } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { Event } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; export const ISpeechService = createDecorator('speechService'); @@ -42,17 +44,28 @@ export interface ISpeechService { readonly _serviceBrand: undefined; + readonly onDidRegisterSpeechProvider: Event; + readonly onDidUnregisterSpeechProvider: Event; + registerSpeechProvider(identifier: string, provider: ISpeechProvider): IDisposable; - createSpeechToTextSession(identifier: string, token: CancellationToken): ISpeechToTextSession; + createSpeechToTextSession(token: CancellationToken): ISpeechToTextSession; } export class SpeechService implements ISpeechService { readonly _serviceBrand: undefined; + private readonly _onDidRegisterSpeechProvider = new Emitter(); + readonly onDidRegisterSpeechProvider = this._onDidRegisterSpeechProvider.event; + + private readonly _onDidUnregisterSpeechProvider = new Emitter(); + readonly onDidUnregisterSpeechProvider = this._onDidUnregisterSpeechProvider.event; + private readonly providers = new Map(); + constructor(@ILogService private readonly logService: ILogService) { } + registerSpeechProvider(identifier: string, provider: ISpeechProvider): IDisposable { if (this.providers.has(identifier)) { throw new Error(`Speech provider with identifier ${identifier} is already registered.`); @@ -60,13 +73,20 @@ export class SpeechService implements ISpeechService { this.providers.set(identifier, provider); - return toDisposable(() => this.providers.delete(identifier)); + this._onDidRegisterSpeechProvider.fire(provider); + + return toDisposable(() => { + this.providers.delete(identifier); + this._onDidUnregisterSpeechProvider.fire(provider); + }); } - createSpeechToTextSession(identifier: string, token: CancellationToken): ISpeechToTextSession { - const provider = this.providers.get(identifier); + createSpeechToTextSession(token: CancellationToken): ISpeechToTextSession { + const provider = firstOrDefault(Array.from(this.providers.values())); if (!provider) { - throw new Error(`Speech provider with identifier ${identifier} is not registered.`); + throw new Error(`No Speech provider is registered.`); + } else if (this.providers.size > 1) { + this.logService.warn(`Multiple speech providers registered. Picking first one: ${provider.metadata.displayName}`); } return provider.createSpeechToTextSession(token); From ae774a04cf1f5ecfc03d79165f30b8001cde862d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 15 Oct 2023 06:56:07 +0200 Subject: [PATCH 109/290] fix #195348 (#195637) --- .../browser/parts/activitybar/activitybarPart.ts | 4 +++- src/vs/workbench/browser/parts/paneCompositeBar.ts | 8 +++++++- src/vs/workbench/common/views.ts | 1 - .../services/views/browser/viewDescriptorService.ts | 4 ---- .../views/test/browser/viewDescriptorService.test.ts | 1 - 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 13f0980b69c..45597e813ba 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -39,6 +39,7 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b import { TitleBarVisibleContext } from 'vs/workbench/common/contextkeys'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect'; export class ActivitybarPart extends Part { @@ -178,6 +179,7 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { @IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IContextKeyService contextKeyService: IContextKeyService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IExtensionBisectService extensionBisectService: IExtensionBisectService, @IConfigurationService private readonly configurationService: IConfigurationService, @IMenuService private readonly menuService: IMenuService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @@ -188,7 +190,7 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { this.fillContextMenuActions(actions, e); options.fillExtraContextMenuActions(actions, e); } - }, part, paneCompositePart, instantiationService, storageService, extensionService, viewDescriptorService, contextKeyService, environmentService); + }, part, paneCompositePart, instantiationService, storageService, extensionService, extensionBisectService, viewDescriptorService, contextKeyService, environmentService); if (showGlobalActivities) { this.globalCompositeBar = this._register(instantiationService.createInstance(GlobalCompositeBar, () => this.getContextMenuActions(), (theme: IColorTheme) => this.options.colors(theme), this.options.activityHoverOptions)); diff --git a/src/vs/workbench/browser/parts/paneCompositeBar.ts b/src/vs/workbench/browser/parts/paneCompositeBar.ts index 13d713ca7bc..a18c34d4dc3 100644 --- a/src/vs/workbench/browser/parts/paneCompositeBar.ts +++ b/src/vs/workbench/browser/parts/paneCompositeBar.ts @@ -30,6 +30,7 @@ import { GestureEvent } from 'vs/base/browser/touch'; import { IPaneCompositePart } from 'vs/workbench/browser/parts/paneCompositePart'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect'; interface IPlaceholderViewContainer { readonly id: string; @@ -96,6 +97,7 @@ export class PaneCompositeBar extends Disposable { @IInstantiationService protected readonly instantiationService: IInstantiationService, @IStorageService private readonly storageService: IStorageService, @IExtensionService private readonly extensionService: IExtensionService, + @IExtensionBisectService private readonly extensionBisectService: IExtensionBisectService, @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, @IContextKeyService protected readonly contextKeyService: IContextKeyService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @@ -217,12 +219,16 @@ export class PaneCompositeBar extends Disposable { this.hasExtensionsRegistered = true; // show/hide/remove composites + const shouldRemoveNotExsitingComposite = !(this.extensionBisectService.isActive + || this.environmentService.disableExtensions === true + || (Array.isArray(this.environmentService.disableExtensions) && this.environmentService.disableExtensions.length > 0)); + for (const { id } of this.cachedViewContainers) { const viewContainer = this.getViewContainer(id); if (viewContainer) { this.showOrHideViewContainer(viewContainer); } else { - if (this.viewDescriptorService.isViewContainerRemovedPermanently(id)) { + if (shouldRemoveNotExsitingComposite) { this.removeComposite(id); } else { this.hideComposite(id); diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 9c886825943..db7f36bbbea 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -609,7 +609,6 @@ export interface IViewDescriptorService { getDefaultViewContainer(location: ViewContainerLocation): ViewContainer | undefined; getViewContainerById(id: string): ViewContainer | null; - isViewContainerRemovedPermanently(id: string): boolean; getDefaultViewContainerLocation(viewContainer: ViewContainer): ViewContainerLocation | null; getViewContainerLocation(viewContainer: ViewContainer): ViewContainerLocation | null; getViewContainersByLocation(location: ViewContainerLocation): ViewContainer[]; diff --git a/src/vs/workbench/services/views/browser/viewDescriptorService.ts b/src/vs/workbench/services/views/browser/viewDescriptorService.ts index 700330bfb96..566d7918551 100644 --- a/src/vs/workbench/services/views/browser/viewDescriptorService.ts +++ b/src/vs/workbench/services/views/browser/viewDescriptorService.ts @@ -378,10 +378,6 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor this.saveViewCustomizations(); } - isViewContainerRemovedPermanently(viewContainerId: string): boolean { - return this.isGeneratedContainerId(viewContainerId) && !this.viewContainersCustomLocations.has(viewContainerId); - } - private onDidChangeDefaultContainer(views: IViewDescriptor[], from: ViewContainer, to: ViewContainer): void { const viewsToMove = views.filter(view => !this.viewDescriptorsCustomLocations.has(view.id) // Move views which are not already moved diff --git a/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts b/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts index 58103b06c38..d47daa9b947 100644 --- a/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts +++ b/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts @@ -516,7 +516,6 @@ suite('ViewDescriptorService', () => { testObject.whenExtensionsRegistered(); assert.deepStrictEqual(testObject.getViewContainerById(generatedViewContainerId), null); - assert.deepStrictEqual(testObject.isViewContainerRemovedPermanently(generatedViewContainerId), true); const actual = JSON.parse(storageService.get('views.customizations', StorageScope.PROFILE)!); assert.deepStrictEqual(actual, { viewContainerLocations: {}, viewLocations: {}, viewContainerBadgeEnablementStates: {} }); From 2fdc60de8f2426495903f18b373e68438dc4d3c7 Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Sun, 15 Oct 2023 17:36:44 +0200 Subject: [PATCH 110/290] zen mode show tabs --- src/vs/workbench/browser/layout.ts | 6 +-- .../parts/editor/editorTitleControl.ts | 2 +- .../browser/workbench.contribution.ts | 39 ++++++++++++++----- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 91394f798dc..e21aabd3fb2 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -1232,8 +1232,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.state.runtime.zenMode.transitionDisposables.add(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off'))); } - if (config.hideTabs && this.editorGroupService.partOptions.showTabs === 'multiple') { - this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: 'single' })); + if (config.showTabs !== this.editorGroupService.partOptions.showTabs) { + this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: config.showTabs })); } if (config.silentNotifications && zenModeExitInfo.handleNotificationsDoNotDisturbMode) { @@ -2305,7 +2305,7 @@ type ZenModeConfiguration = { hideActivityBar: boolean; hideLineNumbers: boolean; hideStatusBar: boolean; - hideTabs: boolean; + showTabs: 'multiple' | 'single' | 'none'; restore: boolean; silentNotifications: boolean; }; diff --git a/src/vs/workbench/browser/parts/editor/editorTitleControl.ts b/src/vs/workbench/browser/parts/editor/editorTitleControl.ts index 38ea136a2a0..6330c3e814a 100644 --- a/src/vs/workbench/browser/parts/editor/editorTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorTitleControl.ts @@ -78,7 +78,7 @@ export class EditorTitleControl extends Themable { private createBreadcrumbsControl(): BreadcrumbsControlFactory | undefined { if (this.groupsView.partOptions.showTabs !== 'multiple') { - return undefined; // single tabs have breadcrumbs inlined + return undefined; // Single tabs have breadcrumbs inlined. No tabs have no breadcrumbs. } // Breadcrumbs container diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 6cc79eea671..c3b83193950 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -41,7 +41,12 @@ const registry = Registry.as(ConfigurationExtensions.Con 'workbench.editor.showTabs': { 'type': 'string', 'enum': ['multiple', 'single', 'none'], - 'description': localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."), + 'enumDescriptions': [ + localize('workbench.editor.showTabs.multiple', "Each editor is displayed as a tab in the editor title area."), + localize('workbench.editor.showTabs.single', "The active editor is displayed as a single large tab in the editor title area."), + localize('workbench.editor.showTabs.none', "The editor title area is not displayed."), + ], + 'description': localize('showEditorTabs', "Controls whether opened editors should show as individual tabs, one single large tab or if the title area should not be shown."), 'default': 'multiple' }, 'workbench.editor.wrapTabs': { @@ -187,7 +192,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'workbench.editor.pinnedTabsOnSeparateRow': { 'type': 'boolean', 'default': false, - 'markdownDescription': localize('workbench.editor.pinnedTabsOnSeparateRow', "When enabled, displays pinned tabs in a separate row above all other tabs. This value is ignored when `#workbench.editor.showTabs#` is disabled."), + 'markdownDescription': localize('workbench.editor.pinnedTabsOnSeparateRow', "When enabled, displays pinned tabs in a separate row above all other tabs. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."), }, 'workbench.editor.preventPinnedEditorClose': { 'type': 'string', @@ -722,10 +727,16 @@ const registry = Registry.as(ConfigurationExtensions.Con 'default': true, 'description': localize('zenMode.centerLayout', "Controls whether turning on Zen Mode also centers the layout.") }, - 'zenMode.hideTabs': { - 'type': 'boolean', - 'default': true, - 'description': localize('zenMode.hideTabs', "Controls whether turning on Zen Mode also hides workbench tabs.") + 'zenMode.showTabs': { + 'type': 'string', + 'enum': ['multiple', 'single', 'none'], + 'description': localize('zenMode.showTabs', "Controls whether turning on Zen Mode should show muötiple editor tabs, a single editor tab or hide the editor title area completely."), + 'enumDescriptions': [ + localize('zenMode.showTabs.multiple', "Each editor is displayed as a tab in the editor title area."), + localize('zenMode.showTabs.single', "The active editor is displayed as a single large tab in the editor title area."), + localize('zenMode.showTabs.none', "The editor title area is not displayed."), + ], + 'default': 'multiple' }, 'zenMode.hideStatusBar': { 'type': 'boolean', @@ -770,9 +781,19 @@ Registry.as(Extensions.ConfigurationMigration) Registry.as(Extensions.ConfigurationMigration) .registerConfigurationMigrations([{ key: 'workbench.editor.showTabs', migrateFn: (value: any) => { - const result: ConfigurationKeyValuePairs = [['workbench.editor.showTabs', { value: value }]]; - if (value === false) { - result.push(['workbench.editor.showTabs', { value: 'single' }]); + if (typeof value === 'boolean') { + value = value ? 'multiple' : 'single'; + } + return [['workbench.editor.showTabs', { value: value }]]; + } + }]); + +Registry.as(Extensions.ConfigurationMigration) + .registerConfigurationMigrations([{ + key: 'zenMode.hideTabs', migrateFn: (value: any) => { + const result: ConfigurationKeyValuePairs = [['zenMode.hideTabs', { value: undefined }]]; + if (value === true) { + result.push(['zenMode.showTabs', { value: 'single' }]); } return result; } From df912eeb56acfb3b6a2fd519451168228bb4edee Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Sun, 15 Oct 2023 17:48:13 +0200 Subject: [PATCH 111/290] contextkey has --- src/vs/workbench/browser/actions/layoutActions.ts | 4 ++-- src/vs/workbench/browser/parts/editor/editor.contribution.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 7dd8459f9aa..d4387fb9ea5 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -470,7 +470,7 @@ export class ToggleStatusbarVisibilityAction extends Action2 { registerAction2(ToggleStatusbarVisibilityAction); -// --- Bse Class Toggle Boolean Setting Action +// --- Base Class Toggle Boolean Setting Action abstract class BaseToggleBooleanSettingAction extends Action2 { @@ -524,7 +524,7 @@ export class ToggleSeparatePinnedTabsAction extends BaseToggleBooleanSettingActi original: 'Separate Pinned Editor Tabs' }, category: Categories.View, - precondition: ContextKeyExpr.has('config.workbench.editor.showTabs'), + precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple'), f1: true }); } diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 7289ba1aca6..18cbd10b7d3 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -355,7 +355,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '2_split', order: 20 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 }); -MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleTabsVisibilityAction.ID, title: localize('toggleTabs', "Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.showTabs') }, group: '3_config', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleTabsVisibilityAction.ID, title: localize('toggleTabs', "Editor Tabs"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '3_config', order: 10 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleSeparatePinnedTabsAction.ID, title: localize('toggleSeparatePinnedEditorTabs', "Separate Pinned Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.pinnedTabsOnSeparateRow') }, when: EditorPinnedAndUnpinnedTabsContext, group: '3_config', order: 20 }); // Editor Title Context Menu From e859dc6a999d5b5b6cf26a09e07dc5f71ec0bb46 Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Sun, 15 Oct 2023 18:39:33 +0200 Subject: [PATCH 112/290] :lipstick: --- src/vs/workbench/browser/workbench.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index c3b83193950..c6c287adb4d 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -730,7 +730,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'zenMode.showTabs': { 'type': 'string', 'enum': ['multiple', 'single', 'none'], - 'description': localize('zenMode.showTabs', "Controls whether turning on Zen Mode should show muötiple editor tabs, a single editor tab or hide the editor title area completely."), + 'description': localize('zenMode.showTabs', "Controls whether turning on Zen Mode should show multiple editor tabs, a single editor tab or hide the editor title area completely."), 'enumDescriptions': [ localize('zenMode.showTabs.multiple', "Each editor is displayed as a tab in the editor title area."), localize('zenMode.showTabs.single', "The active editor is displayed as a single large tab in the editor title area."), From bdb0647c4549e17eb6e0152397dc92274a6f65b3 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 16 Oct 2023 00:00:44 -0700 Subject: [PATCH 113/290] Add a minimum chat response render rate (#195667) This rate guessing isn't perfect. We usually start slow and finish faster. I think that's gotten worse either due to work the extension does or latency in invoking the model. --- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 31d1e0eb7ed..2cb8c08dace 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -181,11 +181,13 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer Date: Mon, 16 Oct 2023 07:08:57 +0200 Subject: [PATCH 114/290] voice - tweak the in-progress animation --- .../actions/media/voiceChatActions.css | 74 ++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css b/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css index b081c2c8d2f..4c5f41831a2 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css @@ -3,12 +3,80 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover, -.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover { - animation: none; /* stop the running voice recording animation for showing another codicon to stop */ +/* + * Stop the running animation, we only use it as a hint to apply CSS rules. + */ +.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled), +.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled) { + animation: none; } +/* + * Clear styles and replace icon to "stop" when hovering over it. + */ .monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::before, .monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::before { content: "\ead7"; /* use `debug-stop` icon unicode for hovering over running voice recording */ + background-color: inherit; + border-radius: 0; + color: inherit; + outline: none; +} + +/* + * Remove ::after element to improve "stop" visuals when hovering over it. + */ +.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::after, +.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::after { + display: none; +} + +/* + * Show a "microphone" icon when recording is in progress that: + * - uses z-index:1 and applies a background color to draw over the glowing animation (below) + * - emphasizes activity by drawing with badge colors + */ +.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::before, +.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::before { + content: "\ec12"; + z-index: 1; + border-radius: 50%; + background-color: var(--vscode-input-background); + color: var(--vscode-activityBarBadge-background); + outline: 1px solid var(--vscode-activityBarBadge-background); +} + +/* + * Draw an ::after element for the glowing effect over the "microphone" icon that: + * - uses badge colors to emphasize activity + * - uses a "pulseAnimation" to indicate activity + */ +.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::after, +.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::after { + content: ""; + position: absolute; + top: 50%; + left: 50%; + width: 18px; + height: 18px; + background-color: var(--vscode-activityBarBadge-background); + border-radius: 50%; + animation: pulseAnimation 1s infinite; + transform: translate(-50%, -50%) scale(0); + opacity: 0; +} + +@keyframes pulseAnimation { + 0% { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + } + 50% { + transform: translate(-50%, -50%) scale(1.3); + opacity: 0.5; + } + 100% { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + } } From 0424b2fd95e58f3fa236b8ccfc036575da02a223 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2023 08:21:15 +0200 Subject: [PATCH 115/290] voice - show in-progress placeholder --- src/vs/workbench/contrib/chat/browser/chat.ts | 2 ++ .../contrib/chat/browser/chatWidget.ts | 8 +++++ .../browser/contrib/chatInputEditorContrib.ts | 31 ++++++++++++------ .../contrib/chat/common/chatViewModel.ts | 21 ++++++++++-- .../actions/voiceChatActions.ts | 32 ++++++++++++++++--- .../browser/inlineChatController.ts | 23 ++++++++++--- 6 files changed, 97 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chat.ts b/src/vs/workbench/contrib/chat/browser/chat.ts index 5d3b85c4c7f..0748748b943 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.ts @@ -97,6 +97,8 @@ export interface IChatWidget { getFocus(): ChatTreeItem | undefined; updateInput(query?: string): void; acceptInput(query?: string): void; + setInputPlaceholder(placeholder: string): void; + resetInputPlaceholder(): void; focusLastMessage(): void; focusInput(): void; hasInputFocus(): boolean; diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index d9849c4a269..3df91a83aa5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -471,6 +471,14 @@ export class ChatWidget extends Disposable implements IChatWidget { this.tree.domFocus(); } + setInputPlaceholder(placeholder: string): void { + this.viewModel?.setInputPlaceholder(placeholder); + } + + resetInputPlaceholder(): void { + this.viewModel?.resetInputPlaceholder(); + } + updateInput(value = ''): void { this.inputPart.setValue(value); } diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index bb7a7b77e79..cb000e55f38 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -5,7 +5,7 @@ import { raceCancellation } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -43,10 +43,12 @@ const variableTextDecorationType = 'chat-variable-text'; class InputEditorDecorations extends Disposable { - private _previouslyUsedSlashCommands = new Set(); - public readonly id = 'inputEditorDecorations'; + private readonly previouslyUsedSlashCommands = new Set(); + + private readonly viewModelDisposables = this._register(new MutableDisposable()); + constructor( private readonly widget: IChatWidget, @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -64,14 +66,25 @@ class InputEditorDecorations extends Disposable { this.updateInputEditorDecorations(); this._register(this.widget.inputEditor.onDidChangeModelContent(() => this.updateInputEditorDecorations())); this._register(this.widget.onDidChangeViewModel(() => { - this._previouslyUsedSlashCommands.clear(); + this.registerViewModelListeners(); + this.previouslyUsedSlashCommands.clear(); this.updateInputEditorDecorations(); })); this._register(this.chatService.onDidSubmitSlashCommand((e) => { - if (e.sessionId === this.widget.viewModel?.sessionId && !this._previouslyUsedSlashCommands.has(e.slashCommand)) { - this._previouslyUsedSlashCommands.add(e.slashCommand); + if (e.sessionId === this.widget.viewModel?.sessionId && !this.previouslyUsedSlashCommands.has(e.slashCommand)) { + this.previouslyUsedSlashCommands.add(e.slashCommand); } })); + + this.registerViewModelListeners(); + } + + private registerViewModelListeners(): void { + this.viewModelDisposables.value = this.widget.viewModel?.onDidChange(e => { + if (e?.kind === 'changePlaceholder') { + this.updateInputEditorDecorations(); + } + }); } private updateRegisteredDecorationTypes() { @@ -114,11 +127,11 @@ class InputEditorDecorations extends Disposable { } if (!inputValue) { - const extensionPlaceholder = this.widget.viewModel?.inputPlaceholder; + const viewModelPlaceholder = this.widget.viewModel?.inputPlaceholder; const defaultPlaceholder = slashCommands?.length ? localize('interactive.input.placeholderWithCommands', "Ask a question or type '@' or '/'") : localize('interactive.input.placeholderNoCommands', "Ask a question"); - const placeholder = extensionPlaceholder ?? defaultPlaceholder; + const placeholder = viewModelPlaceholder ?? defaultPlaceholder; const decoration: IDecorationOptions[] = [ { range: { @@ -170,7 +183,7 @@ class InputEditorDecorations extends Disposable { const onlySlashCommandAndWhitespace = slashCommandPart && parsedRequest.every(p => p instanceof ChatRequestTextPart && !p.text.trim().length || p instanceof ChatRequestSlashCommandPart); if (onlySlashCommandAndWhitespace) { // Command reference with no other text - show the placeholder - const isFollowupSlashCommand = this._previouslyUsedSlashCommands.has(slashCommandPart.slashCommand.command); + const isFollowupSlashCommand = this.previouslyUsedSlashCommands.has(slashCommandPart.slashCommand.command); const shouldRenderFollowupPlaceholder = isFollowupSlashCommand && slashCommandPart.slashCommand.followupPlaceholder; if (shouldRenderFollowupPlaceholder || slashCommandPart.slashCommand.detail) { placeholderDecoration = [{ diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index 4918996175f..365303eaf7b 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -28,12 +28,16 @@ export function isWelcomeVM(item: unknown): item is IChatWelcomeMessageViewModel return !!item && typeof item === 'object' && 'content' in item; } -export type IChatViewModelChangeEvent = IChatAddRequestEvent | null; +export type IChatViewModelChangeEvent = IChatAddRequestEvent | IChangePlaceholderEvent | null; export interface IChatAddRequestEvent { kind: 'addRequest'; } +export interface IChangePlaceholderEvent { + kind: 'changePlaceholder'; +} + export interface IChatViewModel { readonly initState: ChatModelInitState; readonly providerId: string; @@ -43,6 +47,8 @@ export interface IChatViewModel { readonly requestInProgress: boolean; readonly inputPlaceholder?: string; getItems(): (IChatRequestViewModel | IChatResponseViewModel | IChatWelcomeMessageViewModel)[]; + setInputPlaceholder(text: string): void; + resetInputPlaceholder(): void; } export interface IChatRequestViewModel { @@ -109,8 +115,19 @@ export class ChatViewModel extends Disposable implements IChatViewModel { private readonly _items: (ChatRequestViewModel | ChatResponseViewModel)[] = []; + private _inputPlaceholder: string | undefined = undefined; get inputPlaceholder(): string | undefined { - return this._model.inputPlaceholder; + return this._inputPlaceholder ?? this._model.inputPlaceholder; + } + + setInputPlaceholder(text: string): void { + this._inputPlaceholder = text; + this._onDidChange.fire({ kind: 'changePlaceholder' }); + } + + resetInputPlaceholder(): void { + this._inputPlaceholder = undefined; + this._onDidChange.fire({ kind: 'changePlaceholder' }); } get sessionId() { diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index 033340c786f..100d11d79b8 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -54,6 +54,9 @@ interface IVoiceChatSessionController { focusInput(): void; acceptInput(): void; updateInput(text: string): void; + + setInputPlaceholder(text: string): void; + clearInputPlaceholder(): void; } class VoiceChatSessionControllerFactory { @@ -157,7 +160,9 @@ class VoiceChatSessionControllerFactory { onDidCancelInput: Event.filter(viewsService.onDidChangeViewVisibility, e => e.id === chatContributionService.getViewIdForProvider(chatView.providerId)), focusInput: () => chatView.focusInput(), acceptInput: () => chatView.acceptInput(), - updateInput: text => chatView.updateInput(text) + updateInput: text => chatView.updateInput(text), + setInputPlaceholder: text => chatView.setInputPlaceholder(text), + clearInputPlaceholder: () => chatView.resetInputPlaceholder() }; } @@ -168,7 +173,9 @@ class VoiceChatSessionControllerFactory { onDidCancelInput: quickChatService.onDidClose, focusInput: () => quickChat.focusInput(), acceptInput: () => quickChat.acceptInput(), - updateInput: text => quickChat.updateInput(text) + updateInput: text => quickChat.updateInput(text), + setInputPlaceholder: text => quickChat.setInputPlaceholder(text), + clearInputPlaceholder: () => quickChat.resetInputPlaceholder() }; } @@ -184,7 +191,9 @@ class VoiceChatSessionControllerFactory { ), focusInput: () => inlineChat.focus(), acceptInput: () => inlineChat.acceptInput(), - updateInput: text => inlineChat.updateInput(text) + updateInput: text => inlineChat.updateInput(text), + setInputPlaceholder: text => inlineChat.setPlaceholder(text), + clearInputPlaceholder: () => inlineChat.resetPlaceholder() }; } } @@ -254,7 +263,7 @@ class VoiceChatSessions { switch (status) { case SpeechToTextStatus.Started: - this.onDidSpeechToTextSessionStart(controller); + this.onDidSpeechToTextSessionStart(controller, session.disposables); break; case SpeechToTextStatus.Recognizing: if (text) { @@ -276,7 +285,7 @@ class VoiceChatSessions { })); } - private onDidSpeechToTextSessionStart(controller: IVoiceChatSessionController): void { + private onDidSpeechToTextSessionStart(controller: IVoiceChatSessionController, disposables: DisposableStore): void { this.voiceChatGettingReadyKey.set(false); this.voiceChatInProgressKey.set(true); @@ -294,6 +303,17 @@ class VoiceChatSessions { this.voiceChatInEditorInProgressKey.set(true); break; } + + let dotCount = 0; + + const updatePlaceholder = () => { + dotCount = (dotCount + 1) % 4; + controller.setInputPlaceholder(`${localize('listening', "I'm listening")}${'.'.repeat(dotCount)}`); + placeholderScheduler.schedule(); + }; + + const placeholderScheduler = disposables.add(new RunOnceScheduler(updatePlaceholder, 500)); + updatePlaceholder(); } stop(voiceChatSessionId = this.voiceChatSessionIds, context?: VoiceChatSessionContext): void { @@ -305,6 +325,8 @@ class VoiceChatSessions { return; } + this.currentVoiceChatSession.controller.clearInputPlaceholder(); + this.currentVoiceChatSession.disposables.dispose(); this.currentVoiceChatSession = undefined; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 3c999c339c8..68555b96521 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -271,7 +271,7 @@ export class InlineChatController implements IEditorContribution { this._showWidget(true, options.position); this._zone.value.widget.updateInfo(localize('welcome.1', "AI-generated code may be incorrect")); - this._zone.value.widget.placeholder = this._getPlaceholderText(); + this._updatePlaceholder(); if (!session) { const createSessionCts = new CancellationTokenSource(); @@ -346,7 +346,7 @@ export class InlineChatController implements IEditorContribution { updateWholeRangeDecoration(); this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []); - this._zone.value.widget.placeholder = this._getPlaceholderText(); + this._updatePlaceholder(); this._zone.value.widget.updateInfo(this._activeSession.session.message ?? localize('welcome.1', "AI-generated code may be incorrect")); this._zone.value.widget.preferredExpansionState = this._activeSession.lastExpansionState; this._zone.value.widget.value = this._activeSession.lastInput?.value ?? this._zone.value.widget.value; @@ -409,8 +409,23 @@ export class InlineChatController implements IEditorContribution { } } + private _placeholder: string | undefined = undefined; + setPlaceholder(text: string): void { + this._placeholder = text; + this._updatePlaceholder(); + } + + resetPlaceholder(): void { + this._placeholder = undefined; + this._updatePlaceholder(); + } + + private _updatePlaceholder(): void { + this._zone.value.widget.placeholder = this._getPlaceholderText(); + } + private _getPlaceholderText(): string { - let result = this._activeSession?.session.placeholder ?? localize('default.placeholder', "Ask a question"); + let result = this._placeholder ?? this._activeSession?.session.placeholder ?? localize('default.placeholder', "Ask a question"); if (InlineChatController._promptHistory.length > 0) { const kb1 = this._keybindingService.lookupKeybinding('inlineChat.previousFromHistory')?.getLabel(); const kb2 = this._keybindingService.lookupKeybinding('inlineChat.nextFromHistory')?.getLabel(); @@ -427,7 +442,7 @@ export class InlineChatController implements IEditorContribution { assertType(this._activeSession); assertType(this._strategy); - this._zone.value.widget.placeholder = this._getPlaceholderText(); + this._updatePlaceholder(); if (options.message) { this.updateInput(options.message); From ea26a7e221b9b3b770f04138c8978423daecfd80 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2023 09:02:17 +0200 Subject: [PATCH 116/290] fix #195345 (#195664) --- .../workbench/browser/parts/compositeBar.ts | 41 ++++--------------- .../browser/parts/paneCompositeBar.ts | 22 +++++----- .../views/browser/viewDescriptorService.ts | 4 +- 3 files changed, 21 insertions(+), 46 deletions(-) diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 03766f49ad1..04403ef1a22 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -186,9 +186,8 @@ export class CompositeBar extends Widget implements ICompositeBar { } setCompositeBarItems(items: ICompositeBarItem[]): void { - if (this.model.setItems(items)) { - this.updateCompositeSwitcher(); - } + this.model.setItems(items); + this.updateCompositeSwitcher(); } getPinnedComposites(): ICompositeBarItem[] { @@ -681,37 +680,11 @@ class CompositeBarModel { this.setItems(items); } - setItems(items: ICompositeBarItem[]): boolean { - const result: ICompositeBarModelItem[] = []; - let hasChanges: boolean = false; - if (!this.items || this.items.length === 0) { - this._items = items.map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.visible)); - hasChanges = true; - } else { - const existingItems = this.items; - for (let index = 0; index < items.length; index++) { - const newItem = items[index]; - const existingItem = existingItems.filter(({ id }) => id === newItem.id)[0]; - if (existingItem) { - if ( - existingItem.pinned !== newItem.pinned || - index !== existingItems.indexOf(existingItem) - ) { - existingItem.pinned = newItem.pinned; - result.push(existingItem); - hasChanges = true; - } else { - result.push(existingItem); - } - } else { - result.push(this.createCompositeBarItem(newItem.id, newItem.name, newItem.order, newItem.pinned, newItem.visible)); - hasChanges = true; - } - } - this._items = result; - } - - return hasChanges; + setItems(items: ICompositeBarItem[]): void { + this._items = []; + this._items = items + .map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.visible)) + .sort((a, b) => (a.order ?? items.length) - (b.order ?? items.length)); } get visibleItems(): ICompositeBarModelItem[] { diff --git a/src/vs/workbench/browser/parts/paneCompositeBar.ts b/src/vs/workbench/browser/parts/paneCompositeBar.ts index a18c34d4dc3..aa080683cc6 100644 --- a/src/vs/workbench/browser/parts/paneCompositeBar.ts +++ b/src/vs/workbench/browser/parts/paneCompositeBar.ts @@ -477,6 +477,7 @@ export class PaneCompositeBar extends Disposable { private onDidPinnedViewContainersStorageValueChange(e: IProfileStorageValueChangeEvent): void { if (this.pinnedViewContainersValue !== this.getStoredPinnedViewContainersValue() /* This checks if current window changed the value or not */) { + this._placeholderViewContainersValue = undefined; this._pinnedViewContainersValue = undefined; this._cachedViewContainers = undefined; @@ -489,19 +490,20 @@ export class PaneCompositeBar extends Disposable { name: cachedViewContainer.name, order: cachedViewContainer.order, pinned: cachedViewContainer.pinned, - visible: !!compositeItems.find(({ id }) => id === cachedViewContainer.id) + visible: cachedViewContainer.visible, }); } - for (let index = 0; index < compositeItems.length; index++) { - // Add items currently exists but does not exist in new. - if (!newCompositeItems.some(({ id }) => id === compositeItems[index].id)) { - const viewContainer = this.viewDescriptorService.getViewContainerById(compositeItems[index].id); - newCompositeItems.splice(index, 0, { - ...compositeItems[index], - pinned: true, - visible: true, - order: viewContainer?.order, + for (const viewContainer of this.getViewContainers()) { + // Add missing view containers + if (!newCompositeItems.some(({ id }) => id === viewContainer.id)) { + const compositeItem = compositeItems.find(({ id }) => id === viewContainer.id); + newCompositeItems.push({ + id: viewContainer.id, + name: typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.value, + order: viewContainer.order, + pinned: e.external ? true : compositeItem?.pinned ?? true, + visible: e.external ? !this.shouldBeHidden(viewContainer) : compositeItem?.visible ?? true, }); } } diff --git a/src/vs/workbench/services/views/browser/viewDescriptorService.ts b/src/vs/workbench/services/views/browser/viewDescriptorService.ts index 566d7918551..05d70551deb 100644 --- a/src/vs/workbench/services/views/browser/viewDescriptorService.ts +++ b/src/vs/workbench/services/views/browser/viewDescriptorService.ts @@ -105,9 +105,9 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor this._onDidChangeViewContainers.fire({ added: [{ container: viewContainer, location: this.getViewContainerLocation(viewContainer) }], removed: [] }); })); - this._register(this.viewContainersRegistry.onDidDeregister(({ viewContainer }) => { + this._register(this.viewContainersRegistry.onDidDeregister(({ viewContainer, viewContainerLocation }) => { this.onDidDeregisterViewContainer(viewContainer); - this._onDidChangeViewContainers.fire({ removed: [{ container: viewContainer, location: this.getViewContainerLocation(viewContainer) }], added: [] }); + this._onDidChangeViewContainers.fire({ removed: [{ container: viewContainer, location: viewContainerLocation }], added: [] }); })); this._register(this.storageService.onDidChangeValue(StorageScope.PROFILE, ViewDescriptorService.VIEWS_CUSTOMIZATIONS, this._register(new DisposableStore()))(() => this.onDidStorageChange())); From 4cd1d0e7c7d54bf8ac501092aa9f804cacfacbd9 Mon Sep 17 00:00:00 2001 From: Yuto Liyosa <75252297+MrYuto@users.noreply.github.com> Date: Mon, 16 Oct 2023 10:32:54 +0330 Subject: [PATCH 117/290] Make `OpenDisassemblyViewAction` an `Action2` (#195623) Fix #195387 --- .../contrib/debug/browser/debugEditorActions.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts index 48d3a26ef76..415a2df0083 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts @@ -7,7 +7,7 @@ import { getDomNodePagePosition } from 'vs/base/browser/dom'; import { Action } from 'vs/base/common/actions'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { EditorAction, EditorAction2, IActionOptions, registerEditorAction } from 'vs/editor/browser/editorExtensions'; +import { EditorAction, IActionOptions, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { Position } from 'vs/editor/common/core/position'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -196,9 +196,9 @@ class EditBreakpointAction extends EditorAction { } } -class OpenDisassemblyViewAction extends EditorAction2 { +class OpenDisassemblyViewAction extends Action2 { - public static readonly ID = 'editor.debug.action.openDisassemblyView'; + public static readonly ID = 'debug.action.openDisassemblyView'; constructor() { super({ @@ -230,11 +230,9 @@ class OpenDisassemblyViewAction extends EditorAction2 { }); } - runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: any[]): void { - if (editor.hasModel()) { - const editorService = accessor.get(IEditorService); - editorService.openEditor(DisassemblyViewInput.instance, { pinned: true, revealIfOpened: true }); - } + run(accessor: ServicesAccessor): void { + const editorService = accessor.get(IEditorService); + editorService.openEditor(DisassemblyViewInput.instance, { pinned: true, revealIfOpened: true }); } } From 7bed4ce3e9f5059b5fc638c348f064edabcce5d2 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 16 Oct 2023 00:03:21 -0700 Subject: [PATCH 118/290] Inline and document more chatAgents2 API (#195640) * Inline and document more chatAgents2 API * More docs --- .../api/common/extHostChatAgents2.ts | 4 +- .../api/common/extHostTypeConverters.ts | 7 +- src/vs/workbench/api/common/extHostTypes.ts | 4 +- .../contrib/chat/common/chatService.ts | 4 +- .../vscode.proposed.chatAgents2.d.ts | 106 +++++++++++++++++- .../vscode.proposed.chatAgents2Additions.d.ts | 5 + ...scode.proposed.interactiveUserActions.d.ts | 4 +- 7 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index c1dd23a6965..22849d610cf 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -78,7 +78,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { slashCommand }, { history: context.history.map(typeConvert.ChatMessage.to) }, - new Progress(p => { + new Progress(p => { throwIfDone(); const convertedProgress = typeConvert.ChatResponseProgress.from(p); this._proxy.$handleProgressChunk(requestId, convertedProgress); @@ -332,7 +332,7 @@ class ExtHostChatAgent { } satisfies vscode.ChatAgent2; } - invoke(request: vscode.ChatAgentRequest, context: vscode.ChatAgentContext, progress: Progress, token: CancellationToken): vscode.ProviderResult { + invoke(request: vscode.ChatAgentRequest, context: vscode.ChatAgentContext, progress: Progress, token: CancellationToken): vscode.ProviderResult { return this._callback(request, context, progress, token); } } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index df2f59b8a84..b3ba3306276 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2302,13 +2302,16 @@ export namespace InteractiveEditorResponseFeedbackKind { } export namespace ChatResponseProgress { - export function from(progress: vscode.InteractiveProgress): extHostProtocol.IChatResponseProgressDto { + export function from(progress: vscode.InteractiveProgress | vscode.ChatAgentProgress): extHostProtocol.IChatResponseProgressDto { if ('placeholder' in progress && 'resolvedContent' in progress) { return { placeholder: progress.placeholder }; } else if ('responseId' in progress) { return { requestId: progress.responseId }; } else if ('content' in progress) { - return { content: typeof progress.content === 'string' ? progress.content : MarkdownString.from(progress.content) }; + return { + content: 'markdownContent' in progress ? progress.markdownContent : + (typeof progress.content === 'string' ? progress.content : MarkdownString.from(progress.content)) + }; } else if ('documents' in progress) { return { documents: progress.documents.map(d => ({ diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index f92f0b4fc77..850cbec1dbd 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4083,8 +4083,8 @@ export class InteractiveWindowInput { //#region Interactive session export enum InteractiveSessionVoteDirection { - Up = 1, - Down = 2 + Down = 0, + Up = 1 } export enum InteractiveSessionCopyKind { diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index b9d1fe9af4a..356cbe6ab58 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -164,8 +164,8 @@ export type IChatFollowup = IChatReplyFollowup | IChatResponseCommandFollowup; // Name has to match the one in vscode.d.ts for some reason export enum InteractiveSessionVoteDirection { - Up = 1, - Down = 2 + Down = 0, + Up = 1 } export interface IChatVoteAction { diff --git a/src/vscode-dts/vscode.proposed.chatAgents2.d.ts b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts index 879832237ec..5454588d439 100644 --- a/src/vscode-dts/vscode.proposed.chatAgents2.d.ts +++ b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts @@ -146,8 +146,110 @@ declare module 'vscode' { variables: Record; } - // TODO@API InteractiveProgress is a lot to inline... - export type ChatAgentHandler = (request: ChatAgentRequest, context: ChatAgentContext, progress: Progress, token: CancellationToken) => ProviderResult; + // TODO@API should these each be prefixed ChatAgentProgress*? + export type ChatAgentProgress = + | ChatAgentContent + | ChatAgentTask + | ChatAgentFileTree + | ChatAgentUsedContext + | ChatAgentContentReference + | ChatAgentInlineContentReference; + + /** + * Indicates a piece of content that was used by the chat agent while processing the request. Will be displayed to the user. + */ + export interface ChatAgentContentReference { + /** + * The resource that was referenced. + */ + reference: Uri | Location; + } + + /** + * A reference to a piece of content that will be rendered inline with the markdown content. + */ + export interface ChatAgentInlineContentReference { + /** + * The resource being referenced. + */ + inlineReference: Uri | Location; + + /** + * An alternate title for the resource. + */ + title?: string; + } + + /** + * A piece of the chat response's content. Will be merged with other progress pieces as needed, and rendered as markdown. + */ + export interface ChatAgentContent { + /** + * The content as a string of markdown source. + */ + content: string; + } + + /** + * Represents a piece of the chat response's content that is resolved asynchronously. It is rendered immediately with a placeholder, + * which is replaced once the full content is available. + */ + export interface ChatAgentTask { + /** + * The markdown string to be rendered immediately. + */ + placeholder: string; + + /** + * A Thenable resolving to the real content. The placeholder will be replaced with this content once it's available. + */ + resolvedContent: Thenable; + } + + /** + * Represents a tree, such as a file and directory structure, rendered in the chat response. + */ + export interface ChatAgentFileTree { + /** + * The root node of the tree. + */ + treeData: ChatAgentFileTreeData; + } + + /** + * Represents a node in a chat response tree. + */ + export interface ChatAgentFileTreeData { + /** + * A human-readable string describing this node. + */ + label: string; + + /** + * A Uri for this node, opened when it's clicked. + */ + uri: Uri; + + /** + * The children of this node. + */ + children?: ChatAgentFileTreeData[]; + } + + export interface ChatAgentDocumentContext { + uri: Uri; + version: number; + ranges: Range[]; + } + + /** + * Document references that should be used by the MappedEditsProvider. + */ + export interface ChatAgentUsedContext { + documents: ChatAgentDocumentContext[]; + } + + export type ChatAgentHandler = (request: ChatAgentRequest, context: ChatAgentContext, progress: Progress, token: CancellationToken) => ProviderResult; export namespace chat { diff --git a/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts b/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts index 3e132347354..4b98979813c 100644 --- a/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts +++ b/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts @@ -10,6 +10,11 @@ declare module 'vscode' { readonly action: InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction; } + export interface ChatAgentContent { + // TODO@API This is an awkward way to describe this but this is temporary until inline references are fully supported and adopted + markdownContent: MarkdownString; + } + export interface ChatAgent2 { // TODO@API We need this- can't handle telemetry on the vscode side yet diff --git a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts index e018235d609..b0b662decc9 100644 --- a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts +++ b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts @@ -6,8 +6,8 @@ declare module 'vscode' { export enum InteractiveSessionVoteDirection { - Up = 1, - Down = 2 + Down = 0, + Up = 1 } export interface InteractiveSessionVoteAction { From cd1294fe9773ea9896d76d953d0eae2d00244207 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 15 Oct 2023 08:59:58 +0200 Subject: [PATCH 119/290] aux window - track last active window and use --- .../electron-main/auxiliaryWindow.ts | 12 +++++++++- .../electron-main/auxiliaryWindows.ts | 2 ++ .../auxiliaryWindowsMainService.ts | 7 ++++++ .../electron-main/nativeHostMainService.ts | 9 ++++---- .../platform/windows/electron-main/windows.ts | 23 +++++++++++++++++++ .../electron-main/windowsMainService.ts | 4 ++-- 6 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts index ea6de58c285..b2715f1b555 100644 --- a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts +++ b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts @@ -15,6 +15,8 @@ export interface IAuxiliaryWindow { readonly id: number; readonly win: BrowserWindow | null; + readonly lastFocusTime: number; + focus(options?: { force: boolean }): void; } @@ -42,6 +44,9 @@ export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow { return this.win; } + private _lastFocusTime = Date.now(); // window is shown on creation so take current time + get lastFocusTime(): number { return this._lastFocusTime; } + constructor( private readonly contents: WebContents, @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService @@ -61,11 +66,16 @@ export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow { private registerWindowListeners(window: BrowserWindow): void { - // Window close + // Window Close window.on('closed', () => { this._onDidClose.fire(); this.dispose(); }); + + // Window Focus + window.on('focus', () => { + this._lastFocusTime = Date.now(); + }); } } diff --git a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows.ts b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows.ts index f0ffd309451..8effe598041 100644 --- a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows.ts +++ b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows.ts @@ -17,5 +17,7 @@ export interface IAuxiliaryWindowsMainService { registerWindow(webContents: WebContents): void; getWindowById(windowId: number): IAuxiliaryWindow | undefined; + getFocusedWindow(): IAuxiliaryWindow | undefined; + getLastActiveWindow(): IAuxiliaryWindow | undefined; } diff --git a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts index bf00fba42fc..e7fe0c93d04 100644 --- a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts +++ b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts @@ -48,4 +48,11 @@ export class AuxiliaryWindowsMainService implements IAuxiliaryWindowsMainService return undefined; } + + getLastActiveWindow(): IAuxiliaryWindow | undefined { + const windows = Array.from(this.windows.values()); + const maxLastFocusTime = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); + + return windows.find(window => window.lastFocusTime === maxLastFocusTime); + } } diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index e6e84e247c2..9c295fe285d 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -25,7 +25,7 @@ import { ISerializableCommandAction } from 'vs/platform/action/common/action'; import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleMainService, IRelaunchOptions } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { ILogService } from 'vs/platform/log/common/log'; import { ICommonNativeHostService, IOSProperties, IOSStatistics } from 'vs/platform/native/common/native'; @@ -34,7 +34,7 @@ import { IPartsSplash } from 'vs/platform/theme/common/themeService'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { ICodeWindow } from 'vs/platform/window/electron-main/window'; import { IColorScheme, IOpenedWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IWindowOpenable } from 'vs/platform/window/common/window'; -import { IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; +import { getFocusedWindow, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; import { isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -61,7 +61,8 @@ export class NativeHostMainService extends Disposable implements INativeHostMain @ILogService private readonly logService: ILogService, @IProductService private readonly productService: IProductService, @IThemeMainService private readonly themeMainService: IThemeMainService, - @IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService + @IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService, + @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); } @@ -804,6 +805,6 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } private focusedWindow(): ICodeWindow | IAuxiliaryWindow | undefined { - return this.windowsMainService.getFocusedWindow() ?? this.auxiliaryWindowsMainService.getFocusedWindow(); + return this.instantiationService.invokeFunction(getFocusedWindow); } } diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 41972e7c713..828b0896200 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -16,6 +16,8 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { join } from 'vs/base/common/path'; +import { IAuxiliaryWindow } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow'; +import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows'; export const IWindowsMainService = createDecorator('windowsMainService'); @@ -157,3 +159,24 @@ export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowSt return options; } + +export function getFocusedWindow(accessor: ServicesAccessor): ICodeWindow | IAuxiliaryWindow | undefined { + const windowsMainService = accessor.get(IWindowsMainService); + const auxiliaryWindowsMainService = accessor.get(IAuxiliaryWindowsMainService); + + // By: Electron focused window + const focusedWindow = windowsMainService.getFocusedWindow() ?? auxiliaryWindowsMainService.getFocusedWindow(); + if (focusedWindow) { + return focusedWindow; + } + + // By: Last active window + const mainLastActiveWindow = windowsMainService.getLastActiveWindow(); + const auxiliaryLastActiveWindow = auxiliaryWindowsMainService.getLastActiveWindow(); + + if (mainLastActiveWindow && auxiliaryLastActiveWindow) { + return mainLastActiveWindow.lastFocusTime < auxiliaryLastActiveWindow.lastFocusTime ? auxiliaryLastActiveWindow : mainLastActiveWindow; + } + + return mainLastActiveWindow ?? auxiliaryLastActiveWindow; +} diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index 8a3e4b35ae1..de555640a8f 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -1620,9 +1620,9 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic } private doGetLastActiveWindow(windows: ICodeWindow[]): ICodeWindow | undefined { - const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); + const maxLastFocusTime = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); - return windows.find(window => window.lastFocusTime === lastFocusedDate); + return windows.find(window => window.lastFocusTime === maxLastFocusTime); } sendToFocused(channel: string, ...args: any[]): void { From caf5a3c9a2087635a708ffe35554b7b7fd356b88 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 15 Oct 2023 09:22:30 +0200 Subject: [PATCH 120/290] aux window - introduce and adopt `EditorInputCapabilities.AuxWindowUnsupported` --- .../browser/parts/editor/editorPanes.ts | 22 ++++++++++++++++--- src/vs/workbench/common/editor.ts | 8 ++++++- .../customEditor/browser/customEditorInput.ts | 1 + .../extensions/common/extensionsInput.ts | 2 +- .../browser/interactiveEditorInput.ts | 1 + .../notebook/common/notebookEditorInput.ts | 2 +- .../browser/webviewEditorInput.ts | 2 +- 7 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorPanes.ts b/src/vs/workbench/browser/parts/editor/editorPanes.ts index 69911cb3d1b..6bc385910a1 100644 --- a/src/vs/workbench/browser/parts/editor/editorPanes.ts +++ b/src/vs/workbench/browser/parts/editor/editorPanes.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { IAction } from 'vs/base/common/actions'; +import { IAction, toAction } from 'vs/base/common/actions'; import { Emitter } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { EditorExtensions, EditorInputCapabilities, IEditorOpenContext, IVisibleEditorPane, isEditorOpenError } from 'vs/workbench/common/editor'; +import { EditorExtensions, EditorInputCapabilities, IEditorOpenContext, IVisibleEditorPane, createEditorOpenError, isEditorOpenError } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { Dimension, show, hide, IDomNodePagePosition, isAncestor, getWindow, getActiveWindow } from 'vs/base/browser/dom'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -128,7 +128,23 @@ export class EditorPanes extends Disposable { async openEditor(editor: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise { try { - return await this.doOpenEditor(this.getEditorPaneDescriptor(editor), editor, options, context); + + // Assert the `EditorInputCapabilities.AuxWindowUnsupported` condition + // TODO@bpasero revisit this once all editors can support aux windows + if (getWindow(this.editorPanesParent) !== window && editor.hasCapability(EditorInputCapabilities.AuxWindowUnsupported)) { + return await this.doShowError(createEditorOpenError(localize('editorUnsupportedInAuxWindow', "This type of editor cannot be opened in floating windows yet."), [ + toAction({ + id: 'workbench.editor.action.closeEditor', label: localize('openFolder', "Close Editor"), run: async () => { + return this.groupView.closeEditor(editor); + } + }) + ], { forceMessage: true, forceSeverity: Severity.Warning }), editor, options, context); + } + + // Open editor normally + else { + return await this.doOpenEditor(this.getEditorPaneDescriptor(editor), editor, options, context); + } } catch (error) { // First check if caller instructed us to ignore error handling diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 41664fd79f8..5cef907363e 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -751,7 +751,13 @@ export const enum EditorInputCapabilities { * Signals that the editor cannot be in a dirty state * and may still have unsaved changes */ - Scratchpad = 1 << 9 + Scratchpad = 1 << 9, + + /** + * Signals that the editor does not support opening in + * auxiliary windows yet. + */ + AuxWindowUnsupported = 1 << 10 } export type IUntypedEditorInput = IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput | IResourceDiffEditorInput | IResourceSideBySideEditorInput | IResourceMergeEditorInput; diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index 964a6a0443b..4e677142d69 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -135,6 +135,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { let capabilities = EditorInputCapabilities.None; capabilities |= EditorInputCapabilities.CanDropIntoEditor; + capabilities |= EditorInputCapabilities.AuxWindowUnsupported; if (!this.customEditorService.getCustomEditorCapabilities(this.viewType)?.supportsMultipleEditorsPerDocument) { capabilities |= EditorInputCapabilities.Singleton; diff --git a/src/vs/workbench/contrib/extensions/common/extensionsInput.ts b/src/vs/workbench/contrib/extensions/common/extensionsInput.ts index b5c0ed689b5..180c12ab35b 100644 --- a/src/vs/workbench/contrib/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/contrib/extensions/common/extensionsInput.ts @@ -28,7 +28,7 @@ export class ExtensionsInput extends EditorInput { } override get capabilities(): EditorInputCapabilities { - return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton; + return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton | EditorInputCapabilities.AuxWindowUnsupported; } override get resource() { diff --git a/src/vs/workbench/contrib/interactive/browser/interactiveEditorInput.ts b/src/vs/workbench/contrib/interactive/browser/interactiveEditorInput.ts index aece1b21e47..534443553ba 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactiveEditorInput.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactiveEditorInput.ts @@ -132,6 +132,7 @@ export class InteractiveEditorInput extends EditorInput implements ICompositeNot override get capabilities(): EditorInputCapabilities { return EditorInputCapabilities.Untitled | EditorInputCapabilities.Readonly + | EditorInputCapabilities.AuxWindowUnsupported | EditorInputCapabilities.Scratchpad; } diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts index 0524f62bde4..1ac7010369c 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorInput.ts @@ -111,7 +111,7 @@ export class NotebookEditorInput extends AbstractResourceEditorInput { } override get capabilities(): EditorInputCapabilities { - let capabilities = EditorInputCapabilities.None; + let capabilities = EditorInputCapabilities.AuxWindowUnsupported; if (this.resource.scheme === Schemas.untitled) { capabilities |= EditorInputCapabilities.Untitled; diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts index 42e9345171b..4d5ae275604 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts @@ -30,7 +30,7 @@ export class WebviewInput extends EditorInput { } public override get capabilities(): EditorInputCapabilities { - return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton | EditorInputCapabilities.CanDropIntoEditor; + return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton | EditorInputCapabilities.CanDropIntoEditor | EditorInputCapabilities.AuxWindowUnsupported; } private readonly _resourceId = generateUuid(); From 56b72511af88e82464006a785bfb7b7913ce3724 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 15 Oct 2023 09:29:13 +0200 Subject: [PATCH 121/290] aux window - :lipstick: method names --- .../electron-main/nativeHostMainService.ts | 21 ++++++++++++------- .../platform/windows/electron-main/windows.ts | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 9c295fe285d..b25b5e92ecd 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -34,7 +34,7 @@ import { IPartsSplash } from 'vs/platform/theme/common/themeService'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { ICodeWindow } from 'vs/platform/window/electron-main/window'; import { IColorScheme, IOpenedWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IWindowOpenable } from 'vs/platform/window/common/window'; -import { getFocusedWindow, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; +import { getFocusedOrLastActiveWindow, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; import { isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -361,19 +361,19 @@ export class NativeHostMainService extends Disposable implements INativeHostMain //#region Dialog async showMessageBox(windowId: number | undefined, options: MessageBoxOptions): Promise { - const window = this.focusedWindow() ?? this.codeWindowById(windowId); + const window = this.getTargetWindow(windowId); return this.dialogMainService.showMessageBox(options, window?.win ?? undefined); } async showSaveDialog(windowId: number | undefined, options: SaveDialogOptions): Promise { - const window = this.focusedWindow() ?? this.codeWindowById(windowId); + const window = this.getTargetWindow(windowId); return this.dialogMainService.showSaveDialog(options, window?.win ?? undefined); } async showOpenDialog(windowId: number | undefined, options: OpenDialogOptions): Promise { - const window = this.focusedWindow() ?? this.codeWindowById(windowId); + const window = this.getTargetWindow(windowId); return this.dialogMainService.showOpenDialog(options, window?.win ?? undefined); } @@ -732,13 +732,13 @@ export class NativeHostMainService extends Disposable implements INativeHostMain //#region Development async openDevTools(windowId: number | undefined, options?: OpenDevToolsOptions): Promise { - const window = this.focusedWindow() ?? this.codeWindowById(windowId); + const window = this.getTargetWindow(windowId); window?.win?.webContents.openDevTools(options); } async toggleDevTools(windowId: number | undefined): Promise { - const window = this.focusedWindow() ?? this.codeWindowById(windowId); + const window = this.getTargetWindow(windowId); window?.win?.webContents.toggleDevTools(); } @@ -804,7 +804,12 @@ export class NativeHostMainService extends Disposable implements INativeHostMain return this.auxiliaryWindowsMainService.getWindowById(windowId); } - private focusedWindow(): ICodeWindow | IAuxiliaryWindow | undefined { - return this.instantiationService.invokeFunction(getFocusedWindow); + private getTargetWindow(fallbackWindowId: number | undefined): ICodeWindow | IAuxiliaryWindow | undefined { + let window = this.instantiationService.invokeFunction(getFocusedOrLastActiveWindow); + if (!window) { + window = this.windowById(fallbackWindowId); + } + + return window; } } diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 828b0896200..5620c87103a 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -160,7 +160,7 @@ export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowSt return options; } -export function getFocusedWindow(accessor: ServicesAccessor): ICodeWindow | IAuxiliaryWindow | undefined { +export function getFocusedOrLastActiveWindow(accessor: ServicesAccessor): ICodeWindow | IAuxiliaryWindow | undefined { const windowsMainService = accessor.get(IWindowsMainService); const auxiliaryWindowsMainService = accessor.get(IAuxiliaryWindowsMainService); From fe14520d0fac6e4b224fef11305cbe0c173e1162 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 15 Oct 2023 20:02:21 +0200 Subject: [PATCH 122/290] aux window - use `moveEditor` --- src/vs/workbench/browser/parts/editor/editorActions.ts | 10 +++------- .../contrib/preferences/browser/settingsEditor2.ts | 3 +-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 2abc360ac74..23d44d4f4db 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -2441,17 +2441,13 @@ export class ExperimentalMoveEditorIntoNewWindowAction extends Action2 { const editorService = accessor.get(IEditorService); const editorGroupService = accessor.get(IEditorGroupsService); - const activeEditor = editorService.activeEditor; - if (!activeEditor) { + const activeEditorPane = editorService.activeEditorPane; + if (!activeEditorPane) { return; } const auxiliaryEditorPart = editorGroupService.createAuxiliaryEditorPart(); - await auxiliaryEditorPart.activeGroup.openEditor(activeEditor, { - pinned: true, - viewState: activeEditor.toUntyped({ preserveViewState: editorGroupService.activeGroup.id })?.options?.viewState, - }); - await editorGroupService.activeGroup.closeEditor(activeEditor); + activeEditorPane.group.moveEditor(activeEditorPane.input, auxiliaryEditorPart.activeGroup); } } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 0a977149e08..68435481031 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -10,7 +10,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Button } from 'vs/base/browser/ui/button/button'; import { ITreeElement } from 'vs/base/browser/ui/tree/tree'; import { Action } from 'vs/base/common/actions'; -import { Delayer, IntervalTimer, ThrottledDelayer, timeout } from 'vs/base/common/async'; +import { Delayer, IntervalTimer, ThrottledDelayer } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { fromNow } from 'vs/base/common/date'; import { isCancellationError } from 'vs/base/common/errors'; @@ -360,7 +360,6 @@ export class SettingsEditor2 extends EditorPane { override async setInput(input: SettingsEditor2Input, options: ISettingsEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { this.inSettingsEditorContextKey.set(true); await super.setInput(input, options, context, token); - await timeout(0); // Force setInput to be async if (!this.input) { return; } From ed0871da2debc9d609e5969eb5dcac1a21fe8f70 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2023 08:56:00 +0200 Subject: [PATCH 123/290] aux window - reuse code in `getLastFocused` method --- .../electron-main/auxiliaryWindowsMainService.ts | 7 ++----- src/vs/platform/windows/electron-main/windows.ts | 16 ++++++++++++++++ .../windows/electron-main/windowsMainService.ts | 6 ++---- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts index e7fe0c93d04..a85937cf5da 100644 --- a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts +++ b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService.ts @@ -9,7 +9,7 @@ import { FileAccess } from 'vs/base/common/network'; import { AuxiliaryWindow, IAuxiliaryWindow } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow'; import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { defaultBrowserWindowOptions } from 'vs/platform/windows/electron-main/windows'; +import { defaultBrowserWindowOptions, getLastFocused } from 'vs/platform/windows/electron-main/windows'; export class AuxiliaryWindowsMainService implements IAuxiliaryWindowsMainService { @@ -50,9 +50,6 @@ export class AuxiliaryWindowsMainService implements IAuxiliaryWindowsMainService } getLastActiveWindow(): IAuxiliaryWindow | undefined { - const windows = Array.from(this.windows.values()); - const maxLastFocusTime = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); - - return windows.find(window => window.lastFocusTime === maxLastFocusTime); + return getLastFocused(Array.from(this.windows.values())); } } diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 5620c87103a..bc30770d0b4 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -180,3 +180,19 @@ export function getFocusedOrLastActiveWindow(accessor: ServicesAccessor): ICodeW return mainLastActiveWindow ?? auxiliaryLastActiveWindow; } + +export function getLastFocused(windows: ICodeWindow[]): ICodeWindow | undefined; +export function getLastFocused(windows: IAuxiliaryWindow[]): IAuxiliaryWindow | undefined; +export function getLastFocused(windows: ICodeWindow[] | IAuxiliaryWindow[]): ICodeWindow | IAuxiliaryWindow | undefined { + let lastFocusedWindow: ICodeWindow | IAuxiliaryWindow | undefined = undefined; + let maxLastFocusTime = Number.MIN_VALUE; + + for (const window of windows) { + if (window.lastFocusTime > maxLastFocusTime) { + maxLastFocusTime = window.lastFocusTime; + lastFocusedWindow = window; + } + } + + return lastFocusedWindow; +} diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index de555640a8f..89b2e26c645 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -39,7 +39,7 @@ import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { IStateService } from 'vs/platform/state/node/state'; import { IAddFoldersRequest, INativeOpenFileRequest, INativeWindowConfiguration, IOpenEmptyWindowOptions, IPath, IPathsToWaitFor, isFileToOpen, isFolderToOpen, isWorkspaceToOpen, IWindowOpenable, IWindowSettings } from 'vs/platform/window/common/window'; import { CodeWindow } from 'vs/platform/windows/electron-main/windowImpl'; -import { IOpenConfiguration, IOpenEmptyConfiguration, IWindowsCountChangedEvent, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; +import { IOpenConfiguration, IOpenEmptyConfiguration, IWindowsCountChangedEvent, IWindowsMainService, OpenContext, getLastFocused } from 'vs/platform/windows/electron-main/windows'; import { findWindowOnExtensionDevelopmentPath, findWindowOnFile, findWindowOnWorkspaceOrFolder } from 'vs/platform/windows/electron-main/windowsFinder'; import { IWindowState, WindowsStateHandler } from 'vs/platform/windows/electron-main/windowsStateHandler'; import { IRecent } from 'vs/platform/workspaces/common/workspaces'; @@ -1620,9 +1620,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic } private doGetLastActiveWindow(windows: ICodeWindow[]): ICodeWindow | undefined { - const maxLastFocusTime = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); - - return windows.find(window => window.lastFocusTime === maxLastFocusTime); + return getLastFocused(windows); } sendToFocused(channel: string, ...args: any[]): void { From d169c087c16f5acde437c8e95ef90153e04aa9be Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 16 Oct 2023 11:33:20 +0200 Subject: [PATCH 124/290] Update distro (#195679) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 860e50402fa..312b8260986 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.84.0", - "distro": "f69d4735763562c6fd1d2a56596fe808865081ed", + "distro": "8b7aeb202ebde81e55354c06a62ca5384c77771d", "author": { "name": "Microsoft Corporation" }, From 90aee6d79caa71c02d378c01053983eb00f94bf8 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2023 12:16:59 +0200 Subject: [PATCH 125/290] voice - more tweaks to icon animation (#195681) * voice - more tweaks to icon animation * more tweaks --- .../lib/stylelint/vscode-known-variables.json | 6 +- .../actions/media/voiceChatActions.css | 98 +++++++------------ .../actions/voiceChatActions.ts | 16 +++ 3 files changed, 56 insertions(+), 64 deletions(-) diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 1a512c67bd4..6a99e81b5a4 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -706,7 +706,9 @@ "--vscode-widget-border", "--vscode-widget-shadow", "--vscode-window-activeBorder", - "--vscode-window-inactiveBorder" + "--vscode-window-inactiveBorder", + "--vscode-voiceRecording-background", + "--vscode-voiceRecording-dimmedBackground" ], "others": [ "--background-dark", @@ -780,4 +782,4 @@ "--z-index-notebook-sticky-scroll", "--zoom-factor" ] -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css b/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css index 4c5f41831a2..d12f2d06eb2 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css @@ -4,79 +4,53 @@ *--------------------------------------------------------------------------------------------*/ /* - * Stop the running animation, we only use it as a hint to apply CSS rules. + * Show a "microphone" icon when recording is in progress that glows via outline. */ .monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled), .monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled) { - animation: none; -} - -/* - * Clear styles and replace icon to "stop" when hovering over it. - */ -.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::before, -.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::before { - content: "\ead7"; /* use `debug-stop` icon unicode for hovering over running voice recording */ - background-color: inherit; - border-radius: 0; - color: inherit; - outline: none; -} - -/* - * Remove ::after element to improve "stop" visuals when hovering over it. - */ -.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::after, -.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::after { - display: none; -} - -/* - * Show a "microphone" icon when recording is in progress that: - * - uses z-index:1 and applies a background color to draw over the glowing animation (below) - * - emphasizes activity by drawing with badge colors - */ -.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::before, -.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::before { - content: "\ec12"; - z-index: 1; - border-radius: 50%; - background-color: var(--vscode-input-background); - color: var(--vscode-activityBarBadge-background); - outline: 1px solid var(--vscode-activityBarBadge-background); -} - -/* - * Draw an ::after element for the glowing effect over the "microphone" icon that: - * - uses badge colors to emphasize activity - * - uses a "pulseAnimation" to indicate activity - */ -.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::after, -.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::after { - content: ""; - position: absolute; - top: 50%; - left: 50%; - width: 18px; - height: 18px; - background-color: var(--vscode-activityBarBadge-background); - border-radius: 50%; + color: var(--vscode-voiceRecording-background); + outline: 1px solid var(--vscode-voiceRecording-background); + outline-offset: -1px; animation: pulseAnimation 1s infinite; - transform: translate(-50%, -50%) scale(0); - opacity: 0; + border-radius: 50%; } @keyframes pulseAnimation { 0% { - transform: translate(-50%, -50%) scale(1); - opacity: 1; + outline-width: 1px; } 50% { - transform: translate(-50%, -50%) scale(1.3); - opacity: 0.5; + outline-width: 3px; + outline-color: var(--vscode-voiceRecording-dimmedBackground); } 100% { - transform: translate(-50%, -50%) scale(1); - opacity: 1; + outline-width: 1px; } } + +/* + * Replace with "microphone" icon. + */ +.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::before, +.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled)::before { + content: "\ec12"; +} + +/* + * Clear animation styles when hovering. + */ +.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover, +.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover { + color: inherit; + outline: none; + animation: none; + border-radius: 5px; +} + +/* + * Replace with "stop" icon when hovering. + */ +.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::before, +.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover::before { + content: "\ead7"; /* use `debug-stop` icon unicode for hovering over running voice recording */ +} diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index 100d11d79b8..d99b19e6e1c 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -33,6 +33,8 @@ import { isExecuteActionContext } from 'vs/workbench/contrib/chat/browser/action import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { ISpeechService, SpeechToTextStatus } from 'vs/workbench/contrib/speech/common/speechService'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { registerColor, transparent } from 'vs/platform/theme/common/colorRegistry'; +import { ACTIVITY_BAR_BADGE_BACKGROUND } from 'vs/workbench/common/theme'; const CONTEXT_VOICE_CHAT_GETTING_READY = new RawContextKey('voiceChatGettingReady', false, { type: 'boolean', description: localize('voiceChatGettingReady', "True when getting ready for receiving voice input from the microphone for voice chat.") }); const CONTEXT_VOICE_CHAT_IN_PROGRESS = new RawContextKey('voiceChatInProgress', false, { type: 'boolean', description: localize('voiceChatInProgress', "True when voice recording from microphone is in progress for voice chat.") }); @@ -59,6 +61,20 @@ interface IVoiceChatSessionController { clearInputPlaceholder(): void; } +export const VOICE_RECORDING_BACKGROUND = registerColor('voiceRecording.background', { + dark: ACTIVITY_BAR_BADGE_BACKGROUND, + light: ACTIVITY_BAR_BADGE_BACKGROUND, + hcDark: ACTIVITY_BAR_BADGE_BACKGROUND, + hcLight: ACTIVITY_BAR_BADGE_BACKGROUND +}, localize('voiceRecording.background', "Background color for voice recording icon when recording.")); + +export const VOICE_RECORDING_BACKGROUND_DIMMED = registerColor('voiceRecording.dimmedBackground', { + dark: transparent(ACTIVITY_BAR_BADGE_BACKGROUND, 0.4), + light: transparent(ACTIVITY_BAR_BADGE_BACKGROUND, 0.4), + hcDark: ACTIVITY_BAR_BADGE_BACKGROUND, + hcLight: ACTIVITY_BAR_BADGE_BACKGROUND +}, localize('voiceRecording.dimmedBackground', "Dimmed background color for voice recording icon when recording.")); + class VoiceChatSessionControllerFactory { static create(accessor: ServicesAccessor, context: 'inline'): Promise; From 586a7bf2cecc4e17c39aee4939a02bbfb015d955 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2023 13:07:17 +0200 Subject: [PATCH 126/290] fix #195680 (#195687) --- src/vs/workbench/browser/parts/views/viewPaneContainer.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 0a785719598..24a3b7993d9 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -547,6 +547,11 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { this.updateTitleArea(); this.updateViewHeaders(); } + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(LayoutSettings.ACTIVITY_BAR_LOCATION)) { + this.updateViewHeaders(); + } + })); }); this._register(this.viewContainerModel.onDidChangeActiveViewDescriptors(() => this._onTitleAreaUpdate.fire())); From 9905225b1ac83292f6a4ed08debfe29cad5ece4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 16 Oct 2023 13:28:09 +0200 Subject: [PATCH 127/290] Remove win32-ia32 target (#195559) * remove win32-ia32 * update distro --- build/azure-pipelines/common/createAsset.js | 13 +++--- build/azure-pipelines/common/createAsset.ts | 11 ++--- build/azure-pipelines/product-build.yml | 31 +------------ .../azure-pipelines/win32/cli-build-win32.yml | 17 ------- .../win32/product-build-win32-cli-sign.yml | 4 -- .../win32/product-build-win32-test.yml | 9 ---- build/checksums/electron.txt | 4 -- build/gulpfile.cli.js | 4 +- build/gulpfile.reh.js | 5 +- build/gulpfile.scan.js | 1 - build/gulpfile.vscode.js | 2 - build/gulpfile.vscode.win32.js | 15 ++---- build/win32/code.iss | 20 +------- build/win32/explorer-appx-fetcher.js | 7 +-- build/win32/explorer-appx-fetcher.ts | 6 +-- package.json | 2 +- product.json | 2 - src/main.js | 3 -- src/vs/base/common/product.ts | 1 - .../common/extensionGalleryService.ts | 7 +-- .../common/extensionManagement.ts | 17 +------ .../common/extensionGalleryService.test.ts | 46 +------------------ .../test/common/extensionManagement.test.ts | 4 +- .../platform/extensions/common/extensions.ts | 1 - .../electron-main/updateService.win32.ts | 6 +-- .../test/electron-sandbox/extension.test.ts | 2 +- src/vs/workbench/electron-sandbox/window.ts | 19 -------- .../services/search/node/rawSearchService.ts | 2 +- 28 files changed, 33 insertions(+), 228 deletions(-) diff --git a/build/azure-pipelines/common/createAsset.js b/build/azure-pipelines/common/createAsset.js index c748d30ac40..5128f607b6a 100644 --- a/build/azure-pipelines/common/createAsset.js +++ b/build/azure-pipelines/common/createAsset.js @@ -21,14 +21,13 @@ function getPlatform(product, os, arch, type) { case 'win32': switch (product) { case 'client': { - const asset = arch === 'ia32' ? 'win32' : `win32-${arch}`; switch (type) { case 'archive': - return `${asset}-archive`; + return `win32-${arch}-archive`; case 'setup': - return asset; + return `win32-${arch}`; case 'user-setup': - return `${asset}-user`; + return `win32-${arch}-user`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -37,12 +36,12 @@ function getPlatform(product, os, arch, type) { if (arch === 'arm64') { throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } - return arch === 'ia32' ? 'server-win32' : `server-win32-${arch}`; + return `server-win32-${arch}`; case 'web': if (arch === 'arm64') { throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } - return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; + return `server-win32-${arch}-web`; case 'cli': return `cli-win32-${arch}`; default: @@ -241,4 +240,4 @@ main().then(() => { console.error(err); process.exit(1); }); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlQXNzZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjcmVhdGVBc3NldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7O0FBRWhHLHlCQUF5QjtBQUV6QixpQ0FBaUM7QUFDakMsc0RBQXdJO0FBQ3hJLDZCQUE2QjtBQUM3QiwwQ0FBNkM7QUFDN0MsOENBQXlEO0FBQ3pELG1DQUFnQztBQWFoQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO0lBQy9CLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztJQUMzRSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDbEIsQ0FBQztBQUVELHdGQUF3RjtBQUN4RixTQUFTLFdBQVcsQ0FBQyxPQUFlLEVBQUUsRUFBVSxFQUFFLElBQVksRUFBRSxJQUFZO0lBQzNFLFFBQVEsRUFBRSxFQUFFLENBQUM7UUFDWixLQUFLLE9BQU87WUFDWCxRQUFRLE9BQU8sRUFBRSxDQUFDO2dCQUNqQixLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUM7b0JBQ2YsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLElBQUksRUFBRSxDQUFDO29CQUMxRCxRQUFRLElBQUksRUFBRSxDQUFDO3dCQUNkLEtBQUssU0FBUzs0QkFDYixPQUFPLEdBQUcsS0FBSyxVQUFVLENBQUM7d0JBQzNCLEtBQUssT0FBTzs0QkFDWCxPQUFPLEtBQUssQ0FBQzt3QkFDZCxLQUFLLFlBQVk7NEJBQ2hCLE9BQU8sR0FBRyxLQUFLLE9BQU8sQ0FBQzt3QkFDeEI7NEJBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDcEUsQ0FBQztnQkFDRixDQUFDO2dCQUNELEtBQUssUUFBUTtvQkFDWixJQUFJLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQzt3QkFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDbkUsQ0FBQztvQkFDRCxPQUFPLElBQUksS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLElBQUksRUFBRSxDQUFDO2dCQUNsRSxLQUFLLEtBQUs7b0JBQ1QsSUFBSSxJQUFJLEtBQUssT0FBTyxFQUFFLENBQUM7d0JBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsaUJBQWlCLE9BQU8sSUFBSSxFQUFFLElBQUksSUFBSSxJQUFJLElBQUksRUFBRSxDQUFDLENBQUM7b0JBQ25FLENBQUM7b0JBQ0QsT0FBTyxJQUFJLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLElBQUksTUFBTSxDQUFDO2dCQUMxRSxLQUFLLEtBQUs7b0JBQ1QsT0FBTyxhQUFhLElBQUksRUFBRSxDQUFDO2dCQUM1QjtvQkFDQyxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQ3BFLENBQUM7UUFDRixLQUFLLFFBQVE7WUFDWixRQUFRLE9BQU8sRUFBRSxDQUFDO2dCQUNqQixLQUFLLFFBQVE7b0JBQ1osT0FBTyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7Z0JBQ2hDLEtBQUssS0FBSztvQkFDVCxPQUFPLGlCQUFpQixJQUFJLE1BQU0sQ0FBQztnQkFDcEMsS0FBSyxLQUFLO29CQUNULE9BQU8sY0FBYyxJQUFJLEVBQUUsQ0FBQztnQkFDN0I7b0JBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0YsS0FBSyxPQUFPO1lBQ1gsUUFBUSxJQUFJLEVBQUUsQ0FBQztnQkFDZCxLQUFLLE1BQU07b0JBQ1YsT0FBTyxjQUFjLElBQUksRUFBRSxDQUFDO2dCQUM3QixLQUFLLGtCQUFrQjtvQkFDdEIsUUFBUSxPQUFPLEVBQUUsQ0FBQzt3QkFDakIsS0FBSyxRQUFROzRCQUNaLE9BQU8sU0FBUyxJQUFJLEVBQUUsQ0FBQzt3QkFDeEIsS0FBSyxRQUFROzRCQUNaLE9BQU8sZ0JBQWdCLElBQUksRUFBRSxDQUFDO3dCQUMvQixLQUFLLEtBQUs7NEJBQ1QsT0FBTyxJQUFJLEtBQUssWUFBWSxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLElBQUksTUFBTSxDQUFDO3dCQUM5RTs0QkFDQyxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUNwRSxDQUFDO2dCQUNGLEtBQUssYUFBYTtvQkFDakIsT0FBTyxhQUFhLElBQUksRUFBRSxDQUFDO2dCQUM1QixLQUFLLGFBQWE7b0JBQ2pCLE9BQU8sYUFBYSxJQUFJLEVBQUUsQ0FBQztnQkFDNUIsS0FBSyxLQUFLO29CQUNULE9BQU8sYUFBYSxJQUFJLEVBQUUsQ0FBQztnQkFDNUI7b0JBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0YsS0FBSyxRQUFRO1lBQ1osUUFBUSxPQUFPLEVBQUUsQ0FBQztnQkFDakIsS0FBSyxRQUFRO29CQUNaLElBQUksSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO3dCQUNwQixPQUFPLFFBQVEsQ0FBQztvQkFDakIsQ0FBQztvQkFDRCxPQUFPLFVBQVUsSUFBSSxFQUFFLENBQUM7Z0JBQ3pCLEtBQUssUUFBUTtvQkFDWixJQUFJLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQzt3QkFDcEIsT0FBTyxlQUFlLENBQUM7b0JBQ3hCLENBQUM7b0JBQ0QsT0FBTyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7Z0JBQ2hDLEtBQUssS0FBSztvQkFDVCxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQzt3QkFDcEIsT0FBTyxtQkFBbUIsQ0FBQztvQkFDNUIsQ0FBQztvQkFDRCxPQUFPLGlCQUFpQixJQUFJLE1BQU0sQ0FBQztnQkFDcEMsS0FBSyxLQUFLO29CQUNULE9BQU8sY0FBYyxJQUFJLEVBQUUsQ0FBQztnQkFDN0I7b0JBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0Y7WUFDQyxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7QUFDRixDQUFDO0FBRUQsOEVBQThFO0FBQzlFLFNBQVMsV0FBVyxDQUFDLElBQVk7SUFDaEMsUUFBUSxJQUFJLEVBQUUsQ0FBQztRQUNkLEtBQUssWUFBWTtZQUNoQixPQUFPLE9BQU8sQ0FBQztRQUNoQixLQUFLLGFBQWEsQ0FBQztRQUNuQixLQUFLLGFBQWE7WUFDakIsT0FBTyxTQUFTLENBQUM7UUFDbEI7WUFDQyxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7QUFDRixDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsUUFBZ0IsRUFBRSxNQUFnQjtJQUNyRCxPQUFPLElBQUksT0FBTyxDQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ25DLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFM0MsTUFBTTthQUNKLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7YUFDdEMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7YUFDZCxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QyxDQUFDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLE1BQU0sQ0FBQyxJQUFZO0lBQzNCLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFakMsSUFBSSxPQUFPLE1BQU0sS0FBSyxXQUFXLEVBQUUsQ0FBQztRQUNuQyxNQUFNLElBQUksS0FBSyxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUM7QUFDZixDQUFDO0FBRUQsS0FBSyxVQUFVLElBQUk7SUFDbEIsTUFBTSxDQUFDLEVBQUUsQUFBRCxFQUFHLE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLGVBQWUsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztJQUNsRix3Q0FBd0M7SUFDeEMsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ2pFLE1BQU0sSUFBSSxHQUFHLFdBQVcsQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMxQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUN6QyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUU3QyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFFakMsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLE9BQU8sQ0FBVyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0csTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztJQUV2QixPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUUzQixNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDN0MsTUFBTSxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUFFLFVBQVUsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRTdHLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQy9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBRW5DLE1BQU0sUUFBUSxHQUFHLE1BQU0sR0FBRyxHQUFHLEdBQUcsUUFBUSxDQUFDO0lBRXpDLE1BQU0sc0JBQXNCLEdBQTJCLEVBQUUsWUFBWSxFQUFFLEVBQUUsZUFBZSxFQUFFLHFDQUFzQixDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLGNBQWMsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksRUFBRSxFQUFFLENBQUM7SUFFOUssTUFBTSxVQUFVLEdBQUcsSUFBSSxpQ0FBc0IsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFFLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUUsQ0FBQyxDQUFDO0lBQ3JKLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxnQ0FBaUIsQ0FBQyxzQ0FBc0MsRUFBRSxVQUFVLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztJQUM1SCxNQUFNLGVBQWUsR0FBRyxpQkFBaUIsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RSxNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUMsa0JBQWtCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFaEUsTUFBTSxXQUFXLEdBQW1DO1FBQ25ELGVBQWUsRUFBRTtZQUNoQixlQUFlLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUM7WUFDdEMsc0JBQXNCLEVBQUUseUJBQXlCLFFBQVEsR0FBRztZQUM1RCxnQkFBZ0IsRUFBRSwwQkFBMEI7U0FDNUM7S0FDRCxDQUFDO0lBRUYsTUFBTSxjQUFjLEdBQW9CLEVBQUUsQ0FBQztJQUUzQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDL0IsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1FBRTdDLElBQUksTUFBTSxJQUFBLGFBQUssRUFBQyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQzVDLE1BQU0sSUFBSSxLQUFLLENBQUMsUUFBUSxPQUFPLEtBQUssUUFBUSx3Q0FBd0MsQ0FBQyxDQUFDO1FBQ3ZGLENBQUM7YUFBTSxDQUFDO1lBQ1AsTUFBTSxJQUFBLGFBQUssRUFBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7Z0JBQzdCLE9BQU8sQ0FBQyxHQUFHLENBQUMsNkNBQTZDLE9BQU8sTUFBTSxDQUFDLENBQUM7Z0JBQ3hFLE1BQU0sVUFBVSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUM7Z0JBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsOENBQThDLENBQUMsQ0FBQztZQUM3RCxDQUFDLENBQUMsQ0FBQztRQUNKLENBQUM7SUFDRixDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFTixNQUFNLHNCQUFzQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDO0lBRWpHLElBQUksc0JBQXNCLEVBQUUsQ0FBQztRQUM1QixNQUFNLGtCQUFrQixHQUFHLElBQUksaUNBQXNCLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsQ0FBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEJBQTBCLENBQUUsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixDQUFFLENBQUMsQ0FBQztRQUN4TCxNQUFNLHlCQUF5QixHQUFHLElBQUksZ0NBQWlCLENBQUMsMkNBQTJDLEVBQUUsa0JBQWtCLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztRQUNqSixNQUFNLHVCQUF1QixHQUFHLHlCQUF5QixDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RGLE1BQU0sa0JBQWtCLEdBQUcsdUJBQXVCLENBQUMsa0JBQWtCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFaEYsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFO1lBQy9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0NBQXdDLENBQUMsQ0FBQztZQUV0RCxJQUFJLE1BQU0sSUFBQSxhQUFLLEVBQUMsR0FBRyxFQUFFLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDO2dCQUNwRCxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLEtBQUssUUFBUSx3Q0FBd0MsQ0FBQyxDQUFDO1lBQ2hHLENBQUM7aUJBQU0sQ0FBQztnQkFDUCxNQUFNLElBQUEsYUFBSyxFQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtvQkFDN0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzREFBc0QsT0FBTyxNQUFNLENBQUMsQ0FBQztvQkFDakYsTUFBTSxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxDQUFDO29CQUMzRCxPQUFPLENBQUMsR0FBRyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7Z0JBQ3RFLENBQUMsQ0FBQyxDQUFDO1lBQ0osQ0FBQztRQUNGLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxNQUFNLGNBQWMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDaEUsTUFBTSxzQkFBc0IsR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxVQUFVLENBQTRCLENBQUM7SUFFeEgsSUFBSSxzQkFBc0IsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDekMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO0lBQ2pELENBQUM7U0FBTSxJQUFJLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQztRQUNuRixPQUFPLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2RCxPQUFPLENBQUMsR0FBRyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7SUFDbEQsQ0FBQztTQUFNLENBQUM7UUFDUCw0Q0FBNEM7UUFDNUMsTUFBTSxzQkFBc0IsQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDekMsQ0FBQztJQUVELE1BQU0sUUFBUSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsSUFBSSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7SUFDMUUsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQzVDLE1BQU0sV0FBVyxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLFFBQVEsRUFBRSxDQUFDO0lBRXBFLE1BQU0sS0FBSyxHQUFVO1FBQ3BCLFFBQVE7UUFDUixJQUFJO1FBQ0osR0FBRyxFQUFFLFFBQVE7UUFDYixJQUFJLEVBQUUsUUFBUTtRQUNkLFdBQVc7UUFDWCxVQUFVO1FBQ1YsSUFBSTtLQUNKLENBQUM7SUFFRixtRUFBbUU7SUFDbkUsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDNUIsS0FBSyxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQztJQUNqQyxDQUFDO0lBRUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFFekQsTUFBTSxNQUFNLEdBQUcsSUFBSSxxQkFBWSxDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUUsRUFBRSxjQUFjLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUNySCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUM7SUFDckUsTUFBTSxJQUFBLGFBQUssRUFBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUU3RixPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQzFCLENBQUM7QUFFRCxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO0lBQ2hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLENBQUMsQ0FBQztJQUMxQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2pCLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRTtJQUNSLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbkIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNqQixDQUFDLENBQUMsQ0FBQyJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlQXNzZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjcmVhdGVBc3NldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7O0FBRWhHLHlCQUF5QjtBQUV6QixpQ0FBaUM7QUFDakMsc0RBQXdJO0FBQ3hJLDZCQUE2QjtBQUM3QiwwQ0FBNkM7QUFDN0MsOENBQXlEO0FBQ3pELG1DQUFnQztBQWFoQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO0lBQy9CLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztJQUMzRSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDbEIsQ0FBQztBQUVELHdGQUF3RjtBQUN4RixTQUFTLFdBQVcsQ0FBQyxPQUFlLEVBQUUsRUFBVSxFQUFFLElBQVksRUFBRSxJQUFZO0lBQzNFLFFBQVEsRUFBRSxFQUFFLENBQUM7UUFDWixLQUFLLE9BQU87WUFDWCxRQUFRLE9BQU8sRUFBRSxDQUFDO2dCQUNqQixLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUM7b0JBQ2YsUUFBUSxJQUFJLEVBQUUsQ0FBQzt3QkFDZCxLQUFLLFNBQVM7NEJBQ2IsT0FBTyxTQUFTLElBQUksVUFBVSxDQUFDO3dCQUNoQyxLQUFLLE9BQU87NEJBQ1gsT0FBTyxTQUFTLElBQUksRUFBRSxDQUFDO3dCQUN4QixLQUFLLFlBQVk7NEJBQ2hCLE9BQU8sU0FBUyxJQUFJLE9BQU8sQ0FBQzt3QkFDN0I7NEJBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDcEUsQ0FBQztnQkFDRixDQUFDO2dCQUNELEtBQUssUUFBUTtvQkFDWixJQUFJLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQzt3QkFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDbkUsQ0FBQztvQkFDRCxPQUFPLGdCQUFnQixJQUFJLEVBQUUsQ0FBQztnQkFDL0IsS0FBSyxLQUFLO29CQUNULElBQUksSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO3dCQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUNuRSxDQUFDO29CQUNELE9BQU8sZ0JBQWdCLElBQUksTUFBTSxDQUFDO2dCQUNuQyxLQUFLLEtBQUs7b0JBQ1QsT0FBTyxhQUFhLElBQUksRUFBRSxDQUFDO2dCQUM1QjtvQkFDQyxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQ3BFLENBQUM7UUFDRixLQUFLLFFBQVE7WUFDWixRQUFRLE9BQU8sRUFBRSxDQUFDO2dCQUNqQixLQUFLLFFBQVE7b0JBQ1osT0FBTyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7Z0JBQ2hDLEtBQUssS0FBSztvQkFDVCxPQUFPLGlCQUFpQixJQUFJLE1BQU0sQ0FBQztnQkFDcEMsS0FBSyxLQUFLO29CQUNULE9BQU8sY0FBYyxJQUFJLEVBQUUsQ0FBQztnQkFDN0I7b0JBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0YsS0FBSyxPQUFPO1lBQ1gsUUFBUSxJQUFJLEVBQUUsQ0FBQztnQkFDZCxLQUFLLE1BQU07b0JBQ1YsT0FBTyxjQUFjLElBQUksRUFBRSxDQUFDO2dCQUM3QixLQUFLLGtCQUFrQjtvQkFDdEIsUUFBUSxPQUFPLEVBQUUsQ0FBQzt3QkFDakIsS0FBSyxRQUFROzRCQUNaLE9BQU8sU0FBUyxJQUFJLEVBQUUsQ0FBQzt3QkFDeEIsS0FBSyxRQUFROzRCQUNaLE9BQU8sZ0JBQWdCLElBQUksRUFBRSxDQUFDO3dCQUMvQixLQUFLLEtBQUs7NEJBQ1QsT0FBTyxJQUFJLEtBQUssWUFBWSxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLElBQUksTUFBTSxDQUFDO3dCQUM5RTs0QkFDQyxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUNwRSxDQUFDO2dCQUNGLEtBQUssYUFBYTtvQkFDakIsT0FBTyxhQUFhLElBQUksRUFBRSxDQUFDO2dCQUM1QixLQUFLLGFBQWE7b0JBQ2pCLE9BQU8sYUFBYSxJQUFJLEVBQUUsQ0FBQztnQkFDNUIsS0FBSyxLQUFLO29CQUNULE9BQU8sYUFBYSxJQUFJLEVBQUUsQ0FBQztnQkFDNUI7b0JBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0YsS0FBSyxRQUFRO1lBQ1osUUFBUSxPQUFPLEVBQUUsQ0FBQztnQkFDakIsS0FBSyxRQUFRO29CQUNaLElBQUksSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO3dCQUNwQixPQUFPLFFBQVEsQ0FBQztvQkFDakIsQ0FBQztvQkFDRCxPQUFPLFVBQVUsSUFBSSxFQUFFLENBQUM7Z0JBQ3pCLEtBQUssUUFBUTtvQkFDWixJQUFJLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQzt3QkFDcEIsT0FBTyxlQUFlLENBQUM7b0JBQ3hCLENBQUM7b0JBQ0QsT0FBTyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7Z0JBQ2hDLEtBQUssS0FBSztvQkFDVCxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQzt3QkFDcEIsT0FBTyxtQkFBbUIsQ0FBQztvQkFDNUIsQ0FBQztvQkFDRCxPQUFPLGlCQUFpQixJQUFJLE1BQU0sQ0FBQztnQkFDcEMsS0FBSyxLQUFLO29CQUNULE9BQU8sY0FBYyxJQUFJLEVBQUUsQ0FBQztnQkFDN0I7b0JBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsT0FBTyxJQUFJLEVBQUUsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNwRSxDQUFDO1FBQ0Y7WUFDQyxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLElBQUksRUFBRSxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7QUFDRixDQUFDO0FBRUQsOEVBQThFO0FBQzlFLFNBQVMsV0FBVyxDQUFDLElBQVk7SUFDaEMsUUFBUSxJQUFJLEVBQUUsQ0FBQztRQUNkLEtBQUssWUFBWTtZQUNoQixPQUFPLE9BQU8sQ0FBQztRQUNoQixLQUFLLGFBQWEsQ0FBQztRQUNuQixLQUFLLGFBQWE7WUFDakIsT0FBTyxTQUFTLENBQUM7UUFDbEI7WUFDQyxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7QUFDRixDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsUUFBZ0IsRUFBRSxNQUFnQjtJQUNyRCxPQUFPLElBQUksT0FBTyxDQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ25DLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFM0MsTUFBTTthQUNKLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7YUFDdEMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7YUFDZCxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QyxDQUFDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLE1BQU0sQ0FBQyxJQUFZO0lBQzNCLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFakMsSUFBSSxPQUFPLE1BQU0sS0FBSyxXQUFXLEVBQUUsQ0FBQztRQUNuQyxNQUFNLElBQUksS0FBSyxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUM7QUFDZixDQUFDO0FBRUQsS0FBSyxVQUFVLElBQUk7SUFDbEIsTUFBTSxDQUFDLEVBQUUsQUFBRCxFQUFHLE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLGVBQWUsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztJQUNsRix3Q0FBd0M7SUFDeEMsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ2pFLE1BQU0sSUFBSSxHQUFHLFdBQVcsQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMxQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUN6QyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUU3QyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFFakMsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLE9BQU8sQ0FBVyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0csTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztJQUV2QixPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUUzQixNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDN0MsTUFBTSxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUFFLFVBQVUsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRTdHLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQy9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBRW5DLE1BQU0sUUFBUSxHQUFHLE1BQU0sR0FBRyxHQUFHLEdBQUcsUUFBUSxDQUFDO0lBRXpDLE1BQU0sc0JBQXNCLEdBQTJCLEVBQUUsWUFBWSxFQUFFLEVBQUUsZUFBZSxFQUFFLHFDQUFzQixDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLGNBQWMsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksRUFBRSxFQUFFLENBQUM7SUFFOUssTUFBTSxVQUFVLEdBQUcsSUFBSSxpQ0FBc0IsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFFLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUUsQ0FBQyxDQUFDO0lBQ3JKLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxnQ0FBaUIsQ0FBQyxzQ0FBc0MsRUFBRSxVQUFVLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztJQUM1SCxNQUFNLGVBQWUsR0FBRyxpQkFBaUIsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RSxNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUMsa0JBQWtCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFaEUsTUFBTSxXQUFXLEdBQW1DO1FBQ25ELGVBQWUsRUFBRTtZQUNoQixlQUFlLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUM7WUFDdEMsc0JBQXNCLEVBQUUseUJBQXlCLFFBQVEsR0FBRztZQUM1RCxnQkFBZ0IsRUFBRSwwQkFBMEI7U0FDNUM7S0FDRCxDQUFDO0lBRUYsTUFBTSxjQUFjLEdBQW9CLEVBQUUsQ0FBQztJQUUzQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDL0IsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1FBRTdDLElBQUksTUFBTSxJQUFBLGFBQUssRUFBQyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQzVDLE1BQU0sSUFBSSxLQUFLLENBQUMsUUFBUSxPQUFPLEtBQUssUUFBUSx3Q0FBd0MsQ0FBQyxDQUFDO1FBQ3ZGLENBQUM7YUFBTSxDQUFDO1lBQ1AsTUFBTSxJQUFBLGFBQUssRUFBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7Z0JBQzdCLE9BQU8sQ0FBQyxHQUFHLENBQUMsNkNBQTZDLE9BQU8sTUFBTSxDQUFDLENBQUM7Z0JBQ3hFLE1BQU0sVUFBVSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUM7Z0JBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsOENBQThDLENBQUMsQ0FBQztZQUM3RCxDQUFDLENBQUMsQ0FBQztRQUNKLENBQUM7SUFDRixDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFTixNQUFNLHNCQUFzQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDO0lBRWpHLElBQUksc0JBQXNCLEVBQUUsQ0FBQztRQUM1QixNQUFNLGtCQUFrQixHQUFHLElBQUksaUNBQXNCLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsQ0FBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEJBQTBCLENBQUUsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixDQUFFLENBQUMsQ0FBQztRQUN4TCxNQUFNLHlCQUF5QixHQUFHLElBQUksZ0NBQWlCLENBQUMsMkNBQTJDLEVBQUUsa0JBQWtCLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztRQUNqSixNQUFNLHVCQUF1QixHQUFHLHlCQUF5QixDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RGLE1BQU0sa0JBQWtCLEdBQUcsdUJBQXVCLENBQUMsa0JBQWtCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFaEYsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFO1lBQy9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0NBQXdDLENBQUMsQ0FBQztZQUV0RCxJQUFJLE1BQU0sSUFBQSxhQUFLLEVBQUMsR0FBRyxFQUFFLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDO2dCQUNwRCxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLEtBQUssUUFBUSx3Q0FBd0MsQ0FBQyxDQUFDO1lBQ2hHLENBQUM7aUJBQU0sQ0FBQztnQkFDUCxNQUFNLElBQUEsYUFBSyxFQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtvQkFDN0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzREFBc0QsT0FBTyxNQUFNLENBQUMsQ0FBQztvQkFDakYsTUFBTSxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxDQUFDO29CQUMzRCxPQUFPLENBQUMsR0FBRyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7Z0JBQ3RFLENBQUMsQ0FBQyxDQUFDO1lBQ0osQ0FBQztRQUNGLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxNQUFNLGNBQWMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDaEUsTUFBTSxzQkFBc0IsR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxVQUFVLENBQTRCLENBQUM7SUFFeEgsSUFBSSxzQkFBc0IsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDekMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO0lBQ2pELENBQUM7U0FBTSxJQUFJLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQztRQUNuRixPQUFPLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2RCxPQUFPLENBQUMsR0FBRyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7SUFDbEQsQ0FBQztTQUFNLENBQUM7UUFDUCw0Q0FBNEM7UUFDNUMsTUFBTSxzQkFBc0IsQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDekMsQ0FBQztJQUVELE1BQU0sUUFBUSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsSUFBSSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7SUFDMUUsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQzVDLE1BQU0sV0FBVyxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLFFBQVEsRUFBRSxDQUFDO0lBRXBFLE1BQU0sS0FBSyxHQUFVO1FBQ3BCLFFBQVE7UUFDUixJQUFJO1FBQ0osR0FBRyxFQUFFLFFBQVE7UUFDYixJQUFJLEVBQUUsUUFBUTtRQUNkLFdBQVc7UUFDWCxVQUFVO1FBQ1YsSUFBSTtLQUNKLENBQUM7SUFFRixtRUFBbUU7SUFDbkUsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDNUIsS0FBSyxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQztJQUNqQyxDQUFDO0lBRUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFFekQsTUFBTSxNQUFNLEdBQUcsSUFBSSxxQkFBWSxDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUUsRUFBRSxjQUFjLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUNySCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUM7SUFDckUsTUFBTSxJQUFBLGFBQUssRUFBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUU3RixPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQzFCLENBQUM7QUFFRCxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO0lBQ2hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLENBQUMsQ0FBQztJQUMxQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2pCLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRTtJQUNSLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbkIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNqQixDQUFDLENBQUMsQ0FBQyJ9 \ No newline at end of file diff --git a/build/azure-pipelines/common/createAsset.ts b/build/azure-pipelines/common/createAsset.ts index 97c90ab40e2..ee08d4ae6a5 100644 --- a/build/azure-pipelines/common/createAsset.ts +++ b/build/azure-pipelines/common/createAsset.ts @@ -34,14 +34,13 @@ function getPlatform(product: string, os: string, arch: string, type: string): s case 'win32': switch (product) { case 'client': { - const asset = arch === 'ia32' ? 'win32' : `win32-${arch}`; switch (type) { case 'archive': - return `${asset}-archive`; + return `win32-${arch}-archive`; case 'setup': - return asset; + return `win32-${arch}`; case 'user-setup': - return `${asset}-user`; + return `win32-${arch}-user`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -50,12 +49,12 @@ function getPlatform(product: string, os: string, arch: string, type: string): s if (arch === 'arm64') { throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } - return arch === 'ia32' ? 'server-win32' : `server-win32-${arch}`; + return `server-win32-${arch}`; case 'web': if (arch === 'arm64') { throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } - return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; + return `server-win32-${arch}-web`; case 'cli': return `cli-win32-${arch}`; default: diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 383fa1576bc..1b4c2b1bb41 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -32,10 +32,6 @@ parameters: displayName: "🎯 Windows x64" type: boolean default: true - - name: VSCODE_BUILD_WIN32_32BIT - displayName: "🎯 Windows ia32" - type: boolean - default: true - name: VSCODE_BUILD_WIN32_ARM64 displayName: "🎯 Windows arm64" type: boolean @@ -107,7 +103,7 @@ variables: - name: VSCODE_QUALITY value: ${{ parameters.VSCODE_QUALITY }} - name: VSCODE_BUILD_STAGE_WINDOWS - value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} + value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_LINUX value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_ALPINE @@ -252,15 +248,6 @@ stages: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} - - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true)) }}: - - job: CLIWindowsX86 - pool: 1es-windows-2019-x64 - steps: - - template: ./win32/cli-build-win32.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_WIN32_32BIT: ${{ parameters.VSCODE_BUILD_WIN32_32BIT }} - - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows dependsOn: @@ -334,22 +321,6 @@ stages: parameters: VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }} VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} - VSCODE_BUILD_WIN32_32BIT: ${{ parameters.VSCODE_BUILD_WIN32_32BIT }} - - - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true)) }}: - - job: Windows32 - timeoutInMinutes: 120 - variables: - VSCODE_ARCH: ia32 - steps: - - template: win32/product-build-win32.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_ARCH: ia32 - VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: true - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}: - job: WindowsARM64 diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml index 8cc72d8938b..c31ec561eb3 100644 --- a/build/azure-pipelines/win32/cli-build-win32.yml +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -2,9 +2,6 @@ parameters: - name: VSCODE_BUILD_WIN32 type: boolean default: false - - name: VSCODE_BUILD_WIN32_32BIT - type: boolean - default: false - name: VSCODE_BUILD_WIN32_ARM64 type: boolean default: false @@ -44,8 +41,6 @@ steps: - x86_64-pc-windows-msvc - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - aarch64-pc-windows-msvc - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: - - i686-pc-windows-msvc - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - template: ../cli/cli-compile-and-publish.yml @@ -70,15 +65,3 @@ steps: OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static/lib OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static/include RUSTFLAGS: "-C target-feature=+crt-static" - - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: - - template: ../cli/cli-compile-and-publish.yml - parameters: - VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - VSCODE_CLI_TARGET: i686-pc-windows-msvc - VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_ia32_cli - VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} - VSCODE_CLI_ENV: - OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static/lib - OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static/include - RUSTFLAGS: "-C target-feature=+crt-static" diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml index a1c5562c64c..f350c1a9b29 100644 --- a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -3,8 +3,6 @@ parameters: type: boolean - name: VSCODE_BUILD_WIN32_ARM64 type: boolean - - name: VSCODE_BUILD_WIN32_32BIT - type: boolean steps: - task: NodeTool@0 @@ -52,5 +50,3 @@ steps: - unsigned_vscode_cli_win32_x64_cli - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - unsigned_vscode_cli_win32_arm64_cli - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: - - unsigned_vscode_cli_win32_ia32_cli diff --git a/build/azure-pipelines/win32/product-build-win32-test.yml b/build/azure-pipelines/win32/product-build-win32-test.yml index 3a24e95657a..cc9867ef4fc 100644 --- a/build/azure-pipelines/win32/product-build-win32-test.yml +++ b/build/azure-pipelines/win32/product-build-win32-test.yml @@ -35,17 +35,14 @@ steps: - powershell: .\scripts\test.bat --build --tfs "Unit Tests" displayName: Run unit tests (Electron) timeoutInMinutes: 15 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - powershell: yarn test-node --build displayName: Run unit tests (node.js) timeoutInMinutes: 15 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - powershell: yarn test-browser-no-install --sequential --build --browser chromium --tfs "Browser Unit Tests" displayName: Run unit tests (Browser, Chromium) timeoutInMinutes: 20 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - powershell: | @@ -100,7 +97,6 @@ steps: exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } displayName: Run integration tests (Electron) timeoutInMinutes: 20 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - powershell: | . build/azure-pipelines/win32/exec.ps1 @@ -109,7 +105,6 @@ steps: exec { .\scripts\test-web-integration.bat --browser firefox } displayName: Run integration tests (Browser, Firefox) timeoutInMinutes: 20 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - powershell: | . build/azure-pipelines/win32/exec.ps1 @@ -122,7 +117,6 @@ steps: exec { .\scripts\test-remote-integration.bat } displayName: Run integration tests (Remote) timeoutInMinutes: 20 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - ${{ if eq(parameters.VSCODE_RUN_SMOKE_TESTS, true) }}: - powershell: .\build\azure-pipelines\win32\listprocesses.bat @@ -145,14 +139,12 @@ steps: - powershell: yarn smoketest-no-compile --tracing --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" displayName: Run smoke tests (Electron) timeoutInMinutes: 20 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - powershell: yarn smoketest-no-compile --web --tracing --headless env: VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH)-web displayName: Run smoke tests (Browser, Chromium) timeoutInMinutes: 20 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - powershell: yarn gulp compile-extension:vscode-test-resolver displayName: Compile test resolver extension @@ -163,7 +155,6 @@ steps: VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH) displayName: Run smoke tests (Remote) timeoutInMinutes: 20 - continueOnError: ${{ eq(parameters.VSCODE_ARCH, 'ia32') }} - powershell: .\build\azure-pipelines\win32\listprocesses.bat displayName: Diagnostics after smoke test run diff --git a/build/checksums/electron.txt b/build/checksums/electron.txt index b4af222afdc..ff618fd4cc4 100644 --- a/build/checksums/electron.txt +++ b/build/checksums/electron.txt @@ -11,9 +11,6 @@ fbb6e06417b1741b94d59a6de5dcf3262bfb3fc98cffbcad475296c42d1cbe94 *electron-v25.8 8860faaaabcc15a531733dd164c858a1cc1bffefdbba7ec54f7687db796f93f3 *electron-v25.8.4-win32-arm64-pdb.zip e909628b4c984b3472c58b3897214e59f55ce69bee99229cdf1451a281865176 *electron-v25.8.4-win32-arm64-symbols.zip 1355293a73da3e5d3f06a6c95c81a5124c4f26be2ec1035ccfcfeccd4c766f5d *electron-v25.8.4-win32-arm64.zip -597cbfd2b9d542a289296d792ed9be40c3e97499207675766265a710454f76f5 *electron-v25.8.4-win32-ia32-pdb.zip -3a0ee0d1435382cfdf727ed70e6c8edd233363dcdadde5c1c6ec170fff243a99 *electron-v25.8.4-win32-ia32-symbols.zip -13efcbfc4a0a62339b4450c5d71d14230978e25eb410dcc7d3408b413391eead *electron-v25.8.4-win32-ia32.zip fef9e5ec4d146e6b310137140cee2a1172964e7584540088b1bc7fd1df15f1ff *electron-v25.8.4-win32-x64-pdb.zip 1227ec90ae2fb30e01d4c6814af1adae983b78ea832dea0520caaa8a05ac0390 *electron-v25.8.4-win32-x64-symbols.zip 0bbe72439cab1e72dee5fb850fdb1b17ea16fef61aa3dae93c562687737084f1 *electron-v25.8.4-win32-x64.zip @@ -23,5 +20,4 @@ bd52d57ff97fb56ac01a3482af905d04f0d4e9c13c53858c6d9f99957eca82da *ffmpeg-v25.8.4 9b3d09177fa1e63e2a6beecfa70aeec30aeb5c1873ff21128a68051c4e23f95d *ffmpeg-v25.8.4-linux-armv7l.zip edc7b1c9f1a0733f109a2c0375a4e40c5bfe0bf28b7f06dcc76e1ada0aa2f125 *ffmpeg-v25.8.4-linux-x64.zip 84ec373f124f628ce7d8964e000e79cd1448acec05b92417207baecf9b0f039a *ffmpeg-v25.8.4-win32-arm64.zip -ce6b46e5395f0f715ff694399580eded7e976c0dd8668304e4b087967fea711f *ffmpeg-v25.8.4-win32-ia32.zip 7506346ff7a98377eca26464370a7c5a8c44d010d5c46a8357fa107980582fac *ffmpeg-v25.8.4-win32-x64.zip diff --git a/build/gulpfile.cli.js b/build/gulpfile.cli.js index 2ed09314fc5..86646fdb274 100644 --- a/build/gulpfile.cli.js +++ b/build/gulpfile.cli.js @@ -30,9 +30,7 @@ const platformOpensslDirName = process.platform === 'win32' ? ( process.arch === 'arm64' ? 'arm64-windows-static-md' - : process.arch === 'ia32' - ? 'x86-windows-static-md' - : 'x64-windows-static-md') + : 'x64-windows-static-md') : process.platform === 'darwin' ? ( process.arch === 'arm64' ? 'arm64-osx' diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 592157f8d76..7f485a072c0 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -38,7 +38,6 @@ const REMOTE_FOLDER = path.join(REPO_ROOT, 'remote'); // Targets const BUILD_TARGETS = [ - { platform: 'win32', arch: 'ia32' }, { platform: 'win32', arch: 'x64' }, { platform: 'darwin', arch: 'x64' }, { platform: 'darwin', arch: 'arm64' }, @@ -185,9 +184,7 @@ function nodejs(platform, arch) { const untar = require('gulp-untar'); const crypto = require('crypto'); - if (arch === 'ia32') { - arch = 'x86'; - } else if (arch === 'armhf') { + if (arch === 'armhf') { arch = 'armv7l'; } else if (arch === 'alpine') { platform = 'alpine'; diff --git a/build/gulpfile.scan.js b/build/gulpfile.scan.js index 9e5b511b48f..6f8144b0954 100644 --- a/build/gulpfile.scan.js +++ b/build/gulpfile.scan.js @@ -18,7 +18,6 @@ const { existsSync, readdirSync } = require('fs'); const root = path.dirname(__dirname); const BUILD_TARGETS = [ - { platform: 'win32', arch: 'ia32' }, { platform: 'win32', arch: 'x64' }, { platform: 'win32', arch: 'arm64' }, { platform: 'darwin', arch: null, opts: { stats: true } }, diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 4095f0f7419..2d2451c28e8 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -423,12 +423,10 @@ function patchWin32DependenciesTask(destinationFolderName) { const buildRoot = path.dirname(root); const BUILD_TARGETS = [ - { platform: 'win32', arch: 'ia32' }, { platform: 'win32', arch: 'x64' }, { platform: 'win32', arch: 'arm64' }, { platform: 'darwin', arch: 'x64', opts: { stats: true } }, { platform: 'darwin', arch: 'arm64', opts: { stats: true } }, - { platform: 'linux', arch: 'ia32' }, { platform: 'linux', arch: 'x64' }, { platform: 'linux', arch: 'armhf' }, { platform: 'linux', arch: 'arm64' }, diff --git a/build/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js index 674eb41a503..5adfdfbfe18 100644 --- a/build/gulpfile.vscode.win32.js +++ b/build/gulpfile.vscode.win32.js @@ -70,7 +70,6 @@ function buildWin32Setup(arch, target) { } return cb => { - const ia32AppId = target === 'system' ? product.win32AppId : product.win32UserAppId; const x64AppId = target === 'system' ? product.win32x64AppId : product.win32x64UserAppId; const arm64AppId = target === 'system' ? product.win32arm64AppId : product.win32arm64UserAppId; @@ -101,12 +100,11 @@ function buildWin32Setup(arch, target) { TunnelApplicationName: product.tunnelApplicationName, ApplicationName: product.applicationName, Arch: arch, - AppId: { 'ia32': ia32AppId, 'x64': x64AppId, 'arm64': arm64AppId }[arch], - IncompatibleTargetAppId: { 'ia32': product.win32AppId, 'x64': product.win32x64AppId, 'arm64': product.win32arm64AppId }[arch], - IncompatibleArchAppId: { 'ia32': x64AppId, 'x64': ia32AppId, 'arm64': ia32AppId }[arch], + AppId: { 'x64': x64AppId, 'arm64': arm64AppId }[arch], + IncompatibleTargetAppId: { 'x64': product.win32x64AppId, 'arm64': product.win32arm64AppId }[arch], AppUserId: product.win32AppUserModelId, - ArchitecturesAllowed: { 'ia32': '', 'x64': 'x64', 'arm64': 'arm64' }[arch], - ArchitecturesInstallIn64BitMode: { 'ia32': '', 'x64': 'x64', 'arm64': 'arm64' }[arch], + ArchitecturesAllowed: { 'x64': 'x64', 'arm64': 'arm64' }[arch], + ArchitecturesInstallIn64BitMode: { 'x64': 'x64', 'arm64': 'arm64' }[arch], SourceDir: sourcePath, RepoDir: repoPath, OutputDir: outputPath, @@ -116,7 +114,7 @@ function buildWin32Setup(arch, target) { }; if (quality === 'insider') { - definitions['AppxPackage'] = `code_insiders_explorer_${arch === 'ia32' ? 'x86' : arch}.appx`; + definitions['AppxPackage'] = `code_insiders_explorer_${arch}.appx`; definitions['AppxPackageFullname'] = `Microsoft.${product.win32RegValueName}_1.0.0.0_neutral__8wekyb3d8bbwe`; } @@ -133,10 +131,8 @@ function defineWin32SetupTasks(arch, target) { gulp.task(task.define(`vscode-win32-${arch}-${target}-setup`, task.series(cleanTask, buildWin32Setup(arch, target)))); } -defineWin32SetupTasks('ia32', 'system'); defineWin32SetupTasks('x64', 'system'); defineWin32SetupTasks('arm64', 'system'); -defineWin32SetupTasks('ia32', 'user'); defineWin32SetupTasks('x64', 'user'); defineWin32SetupTasks('arm64', 'user'); @@ -160,6 +156,5 @@ function updateIcon(executablePath) { }; } -gulp.task(task.define('vscode-win32-ia32-inno-updater', task.series(copyInnoUpdater('ia32'), updateIcon(path.join(buildPath('ia32'), 'tools', 'inno_updater.exe'))))); gulp.task(task.define('vscode-win32-x64-inno-updater', task.series(copyInnoUpdater('x64'), updateIcon(path.join(buildPath('x64'), 'tools', 'inno_updater.exe'))))); gulp.task(task.define('vscode-win32-arm64-inno-updater', task.series(copyInnoUpdater('arm64'), updateIcon(path.join(buildPath('arm64'), 'tools', 'inno_updater.exe'))))); diff --git a/build/win32/code.iss b/build/win32/code.iss index 5f53bc3375d..cca821e647d 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -1327,7 +1327,7 @@ begin #endif #if "user" == InstallTarget - #if "ia32" == Arch || "arm64" == Arch + #if "arm64" == Arch #define IncompatibleArchRootKey "HKLM32" #else #define IncompatibleArchRootKey "HKLM64" @@ -1344,24 +1344,6 @@ begin end; #endif - if Result and IsWin64 then begin - RegKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + copy('{#IncompatibleArchAppId}', 2, 38) + '_is1'; - - if '{#Arch}' = 'ia32' then begin - Result := not RegKeyExists({#Uninstall64RootKey}, RegKey); - ThisArch := '32'; - AltArch := '64'; - end else begin - Result := not RegKeyExists({#Uninstall32RootKey}, RegKey); - ThisArch := '64'; - AltArch := '32'; - end; - - if not Result and not WizardSilent() then begin - MsgBox('Please uninstall the ' + AltArch + '-bit version of {#NameShort} before installing this ' + ThisArch + '-bit version. Uninstalling will not delete settings.', mbInformation, MB_OK); - end; - end; - end; function WizardNotSilent(): Boolean; diff --git a/build/win32/explorer-appx-fetcher.js b/build/win32/explorer-appx-fetcher.js index 6db84b26496..ffc6c24b7dd 100644 --- a/build/win32/explorer-appx-fetcher.js +++ b/build/win32/explorer-appx-fetcher.js @@ -38,13 +38,10 @@ async function downloadExplorerAppx(outDir, quality = 'stable', targetArch = 'x6 } exports.downloadExplorerAppx = downloadExplorerAppx; async function main(outputDir) { - let arch = process.env['VSCODE_ARCH']; + const arch = process.env['VSCODE_ARCH']; if (!outputDir) { throw new Error('Required build env not set'); } - if (arch === 'ia32') { - arch = 'x86'; - } const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); await downloadExplorerAppx(outputDir, product.quality, arch); } @@ -54,4 +51,4 @@ if (require.main === module) { process.exit(1); }); } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwbG9yZXItYXBweC1mZXRjaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZXhwbG9yZXItYXBweC1mZXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Z0dBR2dHO0FBRWhHLFlBQVksQ0FBQzs7O0FBRWIseUJBQXlCO0FBQ3pCLCtCQUErQjtBQUMvQix1Q0FBdUM7QUFDdkMsNkJBQTZCO0FBQzdCLHVDQUFpRDtBQUVqRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztBQUVuRCxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsdUJBQXVCLENBQUMsQ0FBQztBQUVsQyxLQUFLLFVBQVUsb0JBQW9CLENBQUMsTUFBYyxFQUFFLFVBQWtCLFFBQVEsRUFBRSxhQUFxQixLQUFLO0lBQ2hILE1BQU0sY0FBYyxHQUFHLE9BQU8sS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3hFLE1BQU0sUUFBUSxHQUFHLEdBQUcsY0FBYyxhQUFhLFVBQVUsTUFBTSxDQUFDO0lBRWhFLElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLGVBQWUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNoRSxPQUFPO0lBQ1IsQ0FBQztJQUVELElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztRQUNsQyxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVELENBQUMsQ0FBQyxlQUFlLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDN0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFBLHNCQUFnQixFQUFDO1FBQ3ZDLFNBQVMsRUFBRSxJQUFJO1FBQ2YsT0FBTyxFQUFFLE9BQU87UUFDaEIsWUFBWSxFQUFFLFFBQVE7UUFDdEIsd0JBQXdCLEVBQUUsSUFBSTtRQUM5QixhQUFhLEVBQUU7WUFDZCxNQUFNLEVBQUUseUVBQXlFO1lBQ2pGLFNBQVMsRUFBRSxPQUFPO1lBQ2xCLGNBQWMsRUFBRSxRQUFRO1NBQ3hCO0tBQ0QsQ0FBQyxDQUFDO0lBRUgsQ0FBQyxDQUFDLGtCQUFrQixRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sT0FBTyxDQUFDLFFBQVEsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUMzRCxDQUFDO0FBM0JELG9EQTJCQztBQUVELEtBQUssVUFBVSxJQUFJLENBQUMsU0FBa0I7SUFDckMsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUV0QyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDaEIsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxJQUFJLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztRQUNyQixJQUFJLEdBQUcsS0FBSyxDQUFDO0lBQ2QsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxjQUFjLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLE1BQU0sb0JBQW9CLENBQUMsU0FBUyxFQUFHLE9BQWUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQUVELElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztJQUM3QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRTtRQUNqQyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ25CLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakIsQ0FBQyxDQUFDLENBQUM7QUFDSixDQUFDIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwbG9yZXItYXBweC1mZXRjaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZXhwbG9yZXItYXBweC1mZXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Z0dBR2dHO0FBRWhHLFlBQVksQ0FBQzs7O0FBRWIseUJBQXlCO0FBQ3pCLCtCQUErQjtBQUMvQix1Q0FBdUM7QUFDdkMsNkJBQTZCO0FBQzdCLHVDQUFpRDtBQUVqRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztBQUVuRCxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsdUJBQXVCLENBQUMsQ0FBQztBQUVsQyxLQUFLLFVBQVUsb0JBQW9CLENBQUMsTUFBYyxFQUFFLFVBQWtCLFFBQVEsRUFBRSxhQUFxQixLQUFLO0lBQ2hILE1BQU0sY0FBYyxHQUFHLE9BQU8sS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3hFLE1BQU0sUUFBUSxHQUFHLEdBQUcsY0FBYyxhQUFhLFVBQVUsTUFBTSxDQUFDO0lBRWhFLElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLGVBQWUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNoRSxPQUFPO0lBQ1IsQ0FBQztJQUVELElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztRQUNsQyxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVELENBQUMsQ0FBQyxlQUFlLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDN0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFBLHNCQUFnQixFQUFDO1FBQ3ZDLFNBQVMsRUFBRSxJQUFJO1FBQ2YsT0FBTyxFQUFFLE9BQU87UUFDaEIsWUFBWSxFQUFFLFFBQVE7UUFDdEIsd0JBQXdCLEVBQUUsSUFBSTtRQUM5QixhQUFhLEVBQUU7WUFDZCxNQUFNLEVBQUUseUVBQXlFO1lBQ2pGLFNBQVMsRUFBRSxPQUFPO1lBQ2xCLGNBQWMsRUFBRSxRQUFRO1NBQ3hCO0tBQ0QsQ0FBQyxDQUFDO0lBRUgsQ0FBQyxDQUFDLGtCQUFrQixRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sT0FBTyxDQUFDLFFBQVEsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUMzRCxDQUFDO0FBM0JELG9EQTJCQztBQUVELEtBQUssVUFBVSxJQUFJLENBQUMsU0FBa0I7SUFDckMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUV4QyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDaEIsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsY0FBYyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNyRixNQUFNLG9CQUFvQixDQUFDLFNBQVMsRUFBRyxPQUFlLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQ3ZFLENBQUM7QUFFRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7SUFDN0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7UUFDakMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pCLENBQUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyJ9 \ No newline at end of file diff --git a/build/win32/explorer-appx-fetcher.ts b/build/win32/explorer-appx-fetcher.ts index 5d9acb6fb13..89fbb57c064 100644 --- a/build/win32/explorer-appx-fetcher.ts +++ b/build/win32/explorer-appx-fetcher.ts @@ -45,16 +45,12 @@ export async function downloadExplorerAppx(outDir: string, quality: string = 'st } async function main(outputDir?: string): Promise { - let arch = process.env['VSCODE_ARCH']; + const arch = process.env['VSCODE_ARCH']; if (!outputDir) { throw new Error('Required build env not set'); } - if (arch === 'ia32') { - arch = 'x86'; - } - const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); await downloadExplorerAppx(outputDir, (product as any).quality, arch); } diff --git a/package.json b/package.json index 312b8260986..ddadb5e812f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.84.0", - "distro": "8b7aeb202ebde81e55354c06a62ca5384c77771d", + "distro": "ace645d011b7e53ba51e8d5ff153c47e3773b3d8", "author": { "name": "Microsoft Corporation" }, diff --git a/product.json b/product.json index d4ff5cd56e8..f44b078d728 100644 --- a/product.json +++ b/product.json @@ -16,10 +16,8 @@ "win32DirName": "Microsoft Code OSS", "win32NameVersion": "Microsoft Code OSS", "win32RegValueName": "CodeOSS", - "win32AppId": "{{E34003BB-9E10-4501-8C11-BE3FAA83F23F}", "win32x64AppId": "{{D77B7E06-80BA-4137-BCF4-654B95CCEBC5}", "win32arm64AppId": "{{D1ACE434-89C5-48D1-88D3-E2991DF85475}", - "win32UserAppId": "{{C6065F05-9603-4FC4-8101-B9781A25D88E}", "win32x64UserAppId": "{{CC6B787D-37A0-49E8-AE24-8559A032BE0C}", "win32arm64UserAppId": "{{3AEBF0C8-F733-4AD4-BADE-FDB816D53D7B}", "win32AppUserModelId": "Microsoft.CodeOSS", diff --git a/src/main.js b/src/main.js index 887623540eb..7087474bcee 100644 --- a/src/main.js +++ b/src/main.js @@ -411,9 +411,6 @@ function configureCrashReporter() { if (uuidPattern.test(crashReporterId)) { if (isWindows) { switch (process.arch) { - case 'ia32': - submitURL = appCenter['win32-ia32']; - break; case 'x64': submitURL = appCenter['win32-x64']; break; diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index 3a935977ec4..256259e3072 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -224,7 +224,6 @@ export interface IFilePathCondition extends IExtensionRecommendationCondition { export type IFileContentCondition = (IFileLanguageCondition | IFilePathCondition) & { readonly contentPattern: string }; export interface IAppCenterConfiguration { - readonly 'win32-ia32': string; readonly 'win32-x64': string; readonly 'linux-x64': string; readonly 'darwin': string; diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 9d6e9c4739a..a468c400719 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -15,7 +15,7 @@ import { URI } from 'vs/base/common/uri'; import { IHeaders, IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { getFallbackTargetPlarforms, getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo, ISearchPrefferedResults } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo, ISearchPrefferedResults } from 'vs/platform/extensionManagement/common/extensionManagement'; import { adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, getGalleryExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; @@ -471,7 +471,6 @@ function getAllTargetPlatforms(rawGalleryExtension: IRawGalleryExtension): Targe export function sortExtensionVersions(versions: IRawGalleryExtensionVersion[], preferredTargetPlatform: TargetPlatform): IRawGalleryExtensionVersion[] { /* It is expected that versions from Marketplace are sorted by version. So we are just sorting by preferred targetPlatform */ - const fallbackTargetPlatforms = getFallbackTargetPlarforms(preferredTargetPlatform); for (let index = 0; index < versions.length; index++) { const version = versions[index]; if (version.version === versions[index - 1]?.version) { @@ -481,10 +480,6 @@ export function sortExtensionVersions(versions: IRawGalleryExtensionVersion[], p if (versionTargetPlatform === preferredTargetPlatform) { while (insertionIndex > 0 && versions[insertionIndex - 1].version === version.version) { insertionIndex--; } } - /* put it after version with preferred targetPlatform or at the beginning */ - else if (fallbackTargetPlatforms.includes(versionTargetPlatform)) { - while (insertionIndex > 0 && versions[insertionIndex - 1].version === version.version && getTargetPlatformForExtensionVersion(versions[insertionIndex - 1]) !== preferredTargetPlatform) { insertionIndex--; } - } if (insertionIndex !== index) { versions.splice(index, 1); versions.splice(insertionIndex, 0, version); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index dc4c1ccc02c..ba729ddf9a5 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -23,7 +23,6 @@ export const EXTENSION_INSTALL_DEP_PACK_CONTEXT = 'dependecyOrPackExtensionInsta export function TargetPlatformToString(targetPlatform: TargetPlatform) { switch (targetPlatform) { case TargetPlatform.WIN32_X64: return 'Windows 64 bit'; - case TargetPlatform.WIN32_IA32: return 'Windows 32 bit'; case TargetPlatform.WIN32_ARM64: return 'Windows ARM'; case TargetPlatform.LINUX_X64: return 'Linux 64 bit'; @@ -47,7 +46,6 @@ export function TargetPlatformToString(targetPlatform: TargetPlatform) { export function toTargetPlatform(targetPlatform: string): TargetPlatform { switch (targetPlatform) { case TargetPlatform.WIN32_X64: return TargetPlatform.WIN32_X64; - case TargetPlatform.WIN32_IA32: return TargetPlatform.WIN32_IA32; case TargetPlatform.WIN32_ARM64: return TargetPlatform.WIN32_ARM64; case TargetPlatform.LINUX_X64: return TargetPlatform.LINUX_X64; @@ -73,9 +71,6 @@ export function getTargetPlatform(platform: Platform | 'alpine', arch: string | if (arch === 'x64') { return TargetPlatform.WIN32_X64; } - if (arch === 'ia32') { - return TargetPlatform.WIN32_IA32; - } if (arch === 'arm64') { return TargetPlatform.WIN32_ARM64; } @@ -146,17 +141,7 @@ export function isTargetPlatformCompatible(extensionTargetPlatform: TargetPlatfo return true; } - // Fallback - const fallbackTargetPlatforms = getFallbackTargetPlarforms(productTargetPlatform); - return fallbackTargetPlatforms.includes(extensionTargetPlatform); -} - -export function getFallbackTargetPlarforms(targetPlatform: TargetPlatform): TargetPlatform[] { - switch (targetPlatform) { - case TargetPlatform.WIN32_X64: return [TargetPlatform.WIN32_IA32]; - case TargetPlatform.WIN32_ARM64: return [TargetPlatform.WIN32_IA32]; - } - return []; + return false; } export interface IGalleryExtensionProperties { diff --git a/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts b/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts index a471a929653..cebafab4714 100644 --- a/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts +++ b/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts @@ -71,13 +71,6 @@ suite('Extension Gallery Service', () => { assert.deepStrictEqual(actual, expected); }); - test('sorting single extension version with fallback target platform', async () => { - const actual = [aExtensionVersion('1.1.2', TargetPlatform.WIN32_IA32)]; - const expected = [...actual]; - sortExtensionVersions(actual, TargetPlatform.WIN32_X64); - assert.deepStrictEqual(actual, expected); - }); - test('sorting single extension version with not compatible target platform', async () => { const actual = [aExtensionVersion('1.1.2', TargetPlatform.DARWIN_ARM64)]; const expected = [...actual]; @@ -85,41 +78,6 @@ suite('Extension Gallery Service', () => { assert.deepStrictEqual(actual, expected); }); - test('sorting single extension version with multiple target platforms and preferred at first', async () => { - const actual = [aExtensionVersion('1.1.2', TargetPlatform.WIN32_X64), aExtensionVersion('1.1.2', TargetPlatform.WIN32_IA32), aExtensionVersion('1.1.2')]; - const expected = [...actual]; - sortExtensionVersions(actual, TargetPlatform.WIN32_X64); - assert.deepStrictEqual(actual, expected); - }); - - test('sorting single extension version with multiple target platforms and preferred at first with no fallbacks', async () => { - const actual = [aExtensionVersion('1.1.2', TargetPlatform.DARWIN_X64), aExtensionVersion('1.1.2'), aExtensionVersion('1.1.2', TargetPlatform.WIN32_IA32)]; - const expected = [...actual]; - sortExtensionVersions(actual, TargetPlatform.DARWIN_X64); - assert.deepStrictEqual(actual, expected); - }); - - test('sorting single extension version with multiple target platforms and preferred at first and fallback at last', async () => { - const actual = [aExtensionVersion('1.1.2', TargetPlatform.WIN32_X64), aExtensionVersion('1.1.2'), aExtensionVersion('1.1.2', TargetPlatform.WIN32_IA32)]; - const expected = [actual[0], actual[2], actual[1]]; - sortExtensionVersions(actual, TargetPlatform.WIN32_X64); - assert.deepStrictEqual(actual, expected); - }); - - test('sorting single extension version with multiple target platforms and preferred is not first', async () => { - const actual = [aExtensionVersion('1.1.2', TargetPlatform.WIN32_IA32), aExtensionVersion('1.1.2', TargetPlatform.WIN32_X64), aExtensionVersion('1.1.2')]; - const expected = [actual[1], actual[0], actual[2]]; - sortExtensionVersions(actual, TargetPlatform.WIN32_X64); - assert.deepStrictEqual(actual, expected); - }); - - test('sorting single extension version with multiple target platforms and preferred is at the end', async () => { - const actual = [aExtensionVersion('1.1.2', TargetPlatform.WIN32_IA32), aExtensionVersion('1.1.2'), aExtensionVersion('1.1.2', TargetPlatform.WIN32_X64)]; - const expected = [actual[2], actual[0], actual[1]]; - sortExtensionVersions(actual, TargetPlatform.WIN32_X64); - assert.deepStrictEqual(actual, expected); - }); - test('sorting multiple extension versions without target platforms', async () => { const actual = [aExtensionVersion('1.2.4'), aExtensionVersion('1.1.3'), aExtensionVersion('1.1.2'), aExtensionVersion('1.1.1')]; const expected = [...actual]; @@ -142,8 +100,8 @@ suite('Extension Gallery Service', () => { }); test('sorting multiple extension versions with target platforms - 3', async () => { - const actual = [aExtensionVersion('1.2.4'), aExtensionVersion('1.1.2'), aExtensionVersion('1.1.1'), aExtensionVersion('1.0.0', TargetPlatform.DARWIN_ARM64), aExtensionVersion('1.0.0', TargetPlatform.WIN32_IA32), aExtensionVersion('1.0.0', TargetPlatform.WIN32_ARM64)]; - const expected = [actual[0], actual[1], actual[2], actual[5], actual[4], actual[3]]; + const actual = [aExtensionVersion('1.2.4'), aExtensionVersion('1.1.2'), aExtensionVersion('1.1.1'), aExtensionVersion('1.0.0', TargetPlatform.DARWIN_ARM64), aExtensionVersion('1.0.0', TargetPlatform.WIN32_ARM64)]; + const expected = [actual[0], actual[1], actual[2], actual[4], actual[3]]; sortExtensionVersions(actual, TargetPlatform.WIN32_ARM64); assert.deepStrictEqual(actual, expected); }); diff --git a/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts b/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts index 9f29115a827..291bb1767e9 100644 --- a/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts +++ b/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts @@ -32,13 +32,13 @@ suite('Extension Identifier Pattern', () => { test('extension key', () => { assert.strictEqual(new ExtensionKey({ id: 'pub.extension-name' }, '1.0.1').toString(), 'pub.extension-name-1.0.1'); assert.strictEqual(new ExtensionKey({ id: 'pub.extension-name' }, '1.0.1', TargetPlatform.UNDEFINED).toString(), 'pub.extension-name-1.0.1'); - assert.strictEqual(new ExtensionKey({ id: 'pub.extension-name' }, '1.0.1', TargetPlatform.WIN32_IA32).toString(), `pub.extension-name-1.0.1-${TargetPlatform.WIN32_IA32}`); + assert.strictEqual(new ExtensionKey({ id: 'pub.extension-name' }, '1.0.1', TargetPlatform.WIN32_X64).toString(), `pub.extension-name-1.0.1-${TargetPlatform.WIN32_X64}`); }); test('extension key parsing', () => { assert.strictEqual(ExtensionKey.parse('pub.extension-name'), null); assert.strictEqual(ExtensionKey.parse('pub.extension-name@1.2.3'), null); assert.strictEqual(ExtensionKey.parse('pub.extension-name-1.0.1')?.toString(), 'pub.extension-name-1.0.1'); - assert.strictEqual(ExtensionKey.parse('pub.extension-name-1.0.1-win32-ia32')?.toString(), 'pub.extension-name-1.0.1-win32-ia32'); + assert.strictEqual(ExtensionKey.parse('pub.extension-name-1.0.1-win32-x64')?.toString(), 'pub.extension-name-1.0.1-win32-x64'); }); }); diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index cfa0e3296f0..222f6b91861 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -290,7 +290,6 @@ export const enum ExtensionType { export const enum TargetPlatform { WIN32_X64 = 'win32-x64', - WIN32_IA32 = 'win32-ia32', WIN32_ARM64 = 'win32-arm64', LINUX_X64 = 'linux-x64', diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 05229473d33..99bf807ce91 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -99,11 +99,7 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun } protected buildUpdateFeedUrl(quality: string): string | undefined { - let platform = 'win32'; - - if (process.arch !== 'ia32') { - platform += `-${process.arch}`; - } + let platform = `win32-${process.arch}`; if (getUpdateType() === UpdateType.Archive) { platform += '-archive'; diff --git a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extension.test.ts b/src/vs/workbench/contrib/extensions/test/electron-sandbox/extension.test.ts index 320aa5f551f..583c9f99be2 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-sandbox/extension.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-sandbox/extension.test.ts @@ -64,7 +64,7 @@ suite('Extension Test', () => { }); test('extension is outdated when local and gallery are on same version but on different target platforms', () => { - const extension = instantiationService.createInstance(Extension, () => ExtensionState.Installed, () => undefined, undefined, aLocalExtension('somext', {}, { targetPlatform: TargetPlatform.WIN32_IA32 }), aGalleryExtension('somext', {}, { targetPlatform: TargetPlatform.WIN32_X64 })); + const extension = instantiationService.createInstance(Extension, () => ExtensionState.Installed, () => undefined, undefined, aLocalExtension('somext', {}, { targetPlatform: TargetPlatform.WIN32_ARM64 }), aGalleryExtension('somext', {}, { targetPlatform: TargetPlatform.WIN32_X64 })); assert.strictEqual(extension.outdated, true); }); diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 9503b73d7c2..89caff6467a 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -723,25 +723,6 @@ export class NativeWindow extends Disposable { } } - // Windows 32-bit warning - if (isWindows && this.environmentService.os.arch === 'ia32') { - const message = localize('windows32eolmessage', "You are running {0} 32-bit, which will soon stop receiving updates on Windows. Consider upgrading to the 64-bit build.", this.productService.nameLong); - - this.notificationService.prompt( - Severity.Warning, - message, - [{ - label: localize('learnMore', "Learn More"), - run: () => this.openerService.open(URI.parse('https://aka.ms/vscode-faq-old-windows')) - }], - { - neverShowAgain: { id: 'windows32eol', isSecondary: true, scope: NeverShowAgainScope.APPLICATION }, - priority: NotificationPriority.URGENT, - sticky: true - } - ); - } - // macOS 10.13 and 10.14 warning if (isMacintosh) { const majorVersion = this.environmentService.os.release.split('.')[0]; diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 608b8f2eb96..0b6ef930d8e 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -81,7 +81,7 @@ export class SearchService implements IRawSearchService { private getPlatformFileLimits(): { readonly maxFileSize: number } { return { - maxFileSize: process.arch === 'ia32' ? 300 * ByteSize.MB : 16 * ByteSize.GB + maxFileSize: 16 * ByteSize.GB }; } From aec38b677f498ecca3b494953d7bea5895947aa7 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 16 Oct 2023 15:28:28 +0200 Subject: [PATCH 128/290] render diff as soon as changes arrive --- src/vs/platform/progress/common/progress.ts | 29 ++++++++++--------- .../browser/inlineChatController.ts | 7 +++-- .../browser/inlineChatStrategies.ts | 16 ++++++++++ 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/progress/common/progress.ts b/src/vs/platform/progress/common/progress.ts index 9b102bd94ff..f6fa371d73d 100644 --- a/src/vs/platform/progress/common/progress.ts +++ b/src/vs/platform/progress/common/progress.ts @@ -111,7 +111,19 @@ export class Progress implements IProgress { static readonly None = Object.freeze>({ report() { } }); - report: (item: T) => void; + private _value?: T; + get value(): T | undefined { return this._value; } + + constructor(private callback: (data: T) => unknown) { + } + + report(item: T) { + this._value = item; + this.callback(this._value); + } +} + +export class AsyncProgress implements IProgress { private _value?: T; get value(): T | undefined { return this._value; } @@ -120,18 +132,9 @@ export class Progress implements IProgress { private _processingAsyncQueue?: boolean; private _drainListener: (() => void) | undefined; - constructor(private callback: (data: T) => unknown, opts?: { async?: boolean }) { - this.report = opts?.async - ? this._reportAsync.bind(this) - : this._reportSync.bind(this); - } + constructor(private callback: (data: T) => unknown) { } - private _reportSync(item: T) { - this._value = item; - this.callback(this._value); - } - - private _reportAsync(item: T) { + report(item: T) { if (!this._asyncQueue) { this._asyncQueue = [item]; } else { @@ -161,7 +164,7 @@ export class Progress implements IProgress { } } - public drain(): Promise { + drain(): Promise { if (this._processingAsyncQueue) { return new Promise(resolve => { const prevListener = this._drainListener; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 68555b96521..5083e62ac4b 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -35,7 +35,7 @@ import { IChatAccessibilityService, IChatWidgetService } from 'vs/workbench/cont import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Lazy } from 'vs/base/common/lazy'; -import { Progress } from 'vs/platform/progress/common/progress'; +import { AsyncProgress } from 'vs/platform/progress/common/progress'; import { generateUuid } from 'vs/base/common/uuid'; import { TextEdit } from 'vs/editor/common/languages'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; @@ -549,7 +549,7 @@ export class InlineChatController implements IEditorContribution { this._chatAccessibilityService.acceptRequest(); const progressEdits: TextEdit[][] = []; - const progress = new Progress(async data => { + const progress = new AsyncProgress(async data => { this._log('received chunk', data, request); if (data.message) { this._zone.value.widget.updateToolbar(false); @@ -567,8 +567,9 @@ export class InlineChatController implements IEditorContribution { } progressEdits.push(data.edits); await this._makeChanges(progressEdits, false); + await this._strategy?.renderProgressChanges(); } - }, { async: true }); + }); const task = this._activeSession.provider.provideResponse(this._activeSession.session, request, progress, requestCts.token); this._log('request started', this._activeSession.provider.debugName, this._activeSession.session, request); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index f14ad6adf0c..13708d316d5 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -41,6 +41,8 @@ export abstract class EditModeStrategy { abstract undoChanges(response: EditResponse): Promise; + abstract renderProgressChanges(): Promise; + abstract renderChanges(response: EditResponse): Promise; abstract hasFocus(): boolean; @@ -123,6 +125,10 @@ export class PreviewStrategy extends EditModeStrategy { // nothing to do } + override async renderProgressChanges(): Promise { + // nothing to do + } + override async renderChanges(response: EditResponse): Promise { if (response.allLocalEdits.length > 0) { const allEditOperation = response.allLocalEdits.map(edits => edits.map(TextEdit.asEditOperation)); @@ -316,6 +322,10 @@ export class LiveStrategy extends EditModeStrategy { LiveStrategy._undoModelUntil(textModelN, response.modelAltVersionId); } + override async renderProgressChanges(): Promise { + // nothing to do + } + override async renderChanges(response: EditResponse) { this._inlineDiffDecorations.update(); @@ -401,6 +411,12 @@ export class LivePreviewStrategy extends LiveStrategy { super.dispose(); } + override async renderProgressChanges(): Promise { + if (!this._diffZone.value.isVisible) { + this._diffZone.value.show(); + } + } + override async renderChanges(response: EditResponse) { this._updateSummaryMessage(); From 771b0baf6cc0a8d456f12b01957e32b2dc682ce1 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 16 Oct 2023 16:37:07 +0200 Subject: [PATCH 129/290] better warning when overwriting content widget --- src/vs/editor/browser/widget/codeEditorWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index dd1275d834c..0c5283dba72 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1446,7 +1446,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE }; if (this._contentWidgets.hasOwnProperty(widget.getId())) { - console.warn('Overwriting a content widget with the same id.'); + console.warn('Overwriting a content widget with the same id:' + widget.getId()); } this._contentWidgets[widget.getId()] = widgetData; From a4cf93cffff765c96e47ed5ebf41cc3e899ade77 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 16 Oct 2023 16:41:39 +0200 Subject: [PATCH 130/290] don't show background decoration when just whitespace fixes https://github.com/microsoft/vscode-copilot/issues/1958 --- .../inlineChat/browser/inlineChatController.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 5083e62ac4b..a5a31233e66 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -40,6 +40,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { TextEdit } from 'vs/editor/common/languages'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { IModelDeltaDecoration } from 'vs/editor/common/model'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', @@ -336,10 +337,16 @@ export class InlineChatController implements IEditorContribution { const wholeRangeDecoration = this._editor.createDecorationsCollection(); const updateWholeRangeDecoration = () => { - wholeRangeDecoration.set([{ - range: this._activeSession!.wholeRange.value, - options: InlineChatController._decoBlock - }]); + + const range = this._activeSession!.wholeRange.value; + const decorations: IModelDeltaDecoration[] = []; + if (!range.isEmpty()) { + decorations.push({ + range, + options: InlineChatController._decoBlock + }); + } + wholeRangeDecoration.set(decorations); }; this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear())); this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration)); From 9e9c4e4bf713e143063414c59c8056b113f0263b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 16 Oct 2023 17:06:08 +0200 Subject: [PATCH 131/290] fix #195500 (#195665) --- src/vs/base/browser/ui/splitview/paneview.ts | 19 +++++++++++++++++++ .../browser/parts/views/media/paneviewlet.css | 8 ++++++++ .../workbench/browser/parts/views/viewPane.ts | 2 +- .../browser/parts/views/viewPaneContainer.ts | 19 +++++++++++++------ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/vs/base/browser/ui/splitview/paneview.ts b/src/vs/base/browser/ui/splitview/paneview.ts index b073d09d0ce..5bc229dcde0 100644 --- a/src/vs/base/browser/ui/splitview/paneview.ts +++ b/src/vs/base/browser/ui/splitview/paneview.ts @@ -58,6 +58,7 @@ export abstract class Pane extends Disposable implements IView { private expandedSize: number | undefined = undefined; private _headerVisible = true; + private _collapsible = true; private _bodyRendered = false; private _minimumBodySize: number; private _maximumBodySize: number; @@ -154,6 +155,10 @@ export abstract class Pane extends Disposable implements IView { } setExpanded(expanded: boolean): boolean { + if (!expanded && !this.collapsible) { + return false; + } + if (this._expanded === !!expanded) { return false; } @@ -198,6 +203,19 @@ export abstract class Pane extends Disposable implements IView { this._onDidChange.fire(undefined); } + get collapsible(): boolean { + return this._collapsible; + } + + set collapsible(collapsible: boolean) { + if (this._collapsible === !!collapsible) { + return; + } + + this._collapsible = !!collapsible; + this.updateHeader(); + } + get orientation(): Orientation { return this._orientation; } @@ -302,6 +320,7 @@ export abstract class Pane extends Disposable implements IView { this.header.style.lineHeight = `${this.headerSize}px`; this.header.classList.toggle('hidden', !this.headerVisible); this.header.classList.toggle('expanded', expanded); + this.header.classList.toggle('not-collapsible', !this.collapsible); this.header.setAttribute('aria-expanded', String(expanded)); this.header.style.color = this.styles.headerForeground ?? ''; diff --git a/src/vs/workbench/browser/parts/views/media/paneviewlet.css b/src/vs/workbench/browser/parts/views/media/paneviewlet.css index 3037583c587..76ff020a432 100644 --- a/src/vs/workbench/browser/parts/views/media/paneviewlet.css +++ b/src/vs/workbench/browser/parts/views/media/paneviewlet.css @@ -15,6 +15,14 @@ position: relative; } +.monaco-pane-view .pane > .pane-header.not-collapsible .twisty-container { + display: none; +} + +.monaco-pane-view .pane > .pane-header.not-collapsible .title { + margin-left: 8px; +} + .monaco-pane-view .pane > .pane-header > .actions.show-always, .monaco-pane-view .pane.expanded > .pane-header > .actions.show-expanded { display: initial; diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index 0f4390cc8b0..7331134d3c3 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -425,7 +425,7 @@ export abstract class ViewPane extends Pane implements IView { protected renderHeader(container: HTMLElement): void { this.headerContainer = container; - this.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded())))); + this.twistiesContainer = append(container, $(`.twisty-container${ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded()))}`)); this.renderHeaderTitle(container, this.title); diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 24a3b7993d9..b744ee98eed 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -1062,13 +1062,20 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { this.paneItems[0].pane.setExpanded(true); } this.paneItems[0].pane.headerVisible = false; + this.paneItems[0].pane.collapsible = true; } else { - this.paneItems.forEach(i => { - i.pane.headerVisible = true; - if (i.pane === this.lastMergedCollapsedPane) { - i.pane.setExpanded(false); - } - }); + if (this.paneItems.length === 1) { + this.paneItems[0].pane.setExpanded(true); + this.paneItems[0].pane.collapsible = false; + } else { + this.paneItems.forEach(i => { + i.pane.headerVisible = true; + i.pane.collapsible = true; + if (i.pane === this.lastMergedCollapsedPane) { + i.pane.setExpanded(false); + } + }); + } this.lastMergedCollapsedPane = undefined; } } From f58b6e396d3c4eb8549fe2f4e4c7b3de6b37dfba Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 16 Oct 2023 17:12:51 +0200 Subject: [PATCH 132/290] when starting show above selection start, not end --- .../contrib/inlineChat/browser/inlineChatController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index a5a31233e66..69647235a28 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -238,7 +238,7 @@ export class InlineChatController implements IEditorContribution { let widgetPosition: Position; if (initialRender) { - widgetPosition = position ? Position.lift(position) : this._editor.getSelection().getEndPosition().delta(-1); + widgetPosition = position ? Position.lift(position) : this._editor.getSelection().getStartPosition().delta(-1); this._zone.value.setContainerMargins(); this._zone.value.setWidgetMargins(widgetPosition); } else { From cad29a236c8da53771a13bc5d19fc49e0a74fc7d Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 16 Oct 2023 17:22:41 +0200 Subject: [PATCH 133/290] use session position once there is one --- .../contrib/inlineChat/browser/inlineChatController.ts | 1 + .../contrib/inlineChat/browser/inlineChatStrategies.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 69647235a28..57b125fbf74 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -252,6 +252,7 @@ export class InlineChatController implements IEditorContribution { } if (this._activeSession) { this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.wholeRange.value); + widgetPosition = this._strategy?.getWidgetPosition() ?? widgetPosition; } this._zone.value.show(widgetPosition); } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 13708d316d5..95480e8fb06 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -454,7 +454,7 @@ export class LivePreviewStrategy extends LiveStrategy { if (this._session.lastTextModelChanges.length) { return this._session.wholeRange.value.getStartPosition().delta(-1); } - return; + return this._session.wholeRange.value.getStartPosition().delta(-1); } } From 9b7dca4b83a7967e3b3b50a3546ae460be474a2e Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 08:44:12 -0700 Subject: [PATCH 134/290] fix #195288 --- .../contrib/accessibility/browser/accessibleView.ts | 6 +++--- .../codeEditor/browser/accessibility/accessibility.css | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 751f8aa7bd0..f6ff169956a 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -38,7 +38,7 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { AccessibilityVerbositySettingId, AccessibilityWorkbenchSettingId, AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; +import { AccessibilityVerbositySettingId, AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; @@ -215,8 +215,8 @@ export class AccessibleView extends Disposable { this._accessibleViewVerbosityEnabled.set(this._configurationService.getValue(this._currentProvider.verbositySettingKey)); this._updateToolbar(this._currentProvider.actions, this._currentProvider.options.type); } - if (e.affectsConfiguration(AccessibilityWorkbenchSettingId.HideAccessibleView)) { - this._container.classList.toggle('hide', this._configurationService.getValue(AccessibilityWorkbenchSettingId.HideAccessibleView)); + if (e.affectsConfiguration('accessibility.hideAccessibleView')) { + this._container.classList.toggle('hide', this._configurationService.getValue('accessibility.hideAccessibleView')); } })); this._register(this._editorWidget.onDidDispose(() => this._resetContextKeys())); diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css index 8b7c1096017..c8404f83e9c 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css @@ -54,7 +54,5 @@ } .accessible-view.hide { - position: fixed; - top: -2000px; - left:-2000px; + opacity: 0; } From 7818968defdefc611e2edbbfdfcfa445fa4851cc Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 08:56:54 -0700 Subject: [PATCH 135/290] fix #195612 --- src/vs/platform/accessibility/common/accessibility.ts | 1 - .../workbench/browser/parts/editor/editorAutoSave.ts | 5 +---- .../browser/accessibility.contribution.ts | 2 +- .../browser/accessibleNotificationService.ts | 9 ++++++--- .../contrib/files/test/browser/editorAutoSave.test.ts | 2 +- .../test/browser/bufferContentTracker.test.ts | 2 +- .../workbench/services/editor/browser/editorService.ts | 10 ++-------- src/vs/workbench/test/browser/workbenchTestServices.ts | 2 +- 8 files changed, 13 insertions(+), 20 deletions(-) rename src/vs/{platform => workbench/contrib}/accessibility/browser/accessibleNotificationService.ts (87%) diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index 78b0ff84ee5..db150f594fe 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -56,7 +56,6 @@ export const IAccessibleNotificationService = createDecorator this._notifySaved(e.reason === SaveReason.EXPLICIT))); } notify(event: AccessibleNotificationEvent): void { @@ -31,7 +35,7 @@ export class AccessibleNotificationService extends Disposable implements IAccess } } - notifySaved(userGesture: boolean): void { + private _notifySaved(userGesture: boolean): void { const { audioCue, alertMessage } = this._events.get(AccessibleNotificationEvent.Save)!; const alertSetting: NotificationSetting = this._configurationService.getValue('accessibility.alert.save'); if (this._shouldNotify(alertSetting, userGesture)) { @@ -55,5 +59,4 @@ export class TestAccessibleNotificationService extends Disposable implements IAc declare readonly _serviceBrand: undefined; notify(event: AccessibleNotificationEvent): void { } - notifySaved(userGesture: boolean): void { } } diff --git a/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts b/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts index 185bab56c8e..1c157e3c74d 100644 --- a/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts @@ -24,7 +24,7 @@ import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices'; import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; -import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; +import { TestAccessibleNotificationService } from 'vs/workbench/contrib/accessibility/browser/accessibleNotificationService'; suite('EditorAutoSave', () => { diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index cfe91ea6d7d..bc717d3d81a 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -7,7 +7,6 @@ import * as assert from 'assert'; import { importAMDNodeModule } from 'vs/amdX'; import { isWindows } from 'vs/base/common/platform'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; -import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -22,6 +21,7 @@ import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilitie import { ITerminalLogService } from 'vs/platform/terminal/common/terminal'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; +import { TestAccessibleNotificationService } from 'vs/workbench/contrib/accessibility/browser/accessibleNotificationService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { writeP } from 'vs/workbench/contrib/terminal/browser/terminalTestHelpers'; import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal'; diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 3f8e21a8300..f3e96358a17 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -33,7 +33,6 @@ import { IWorkspaceTrustRequestService, WorkspaceTrustUriResponse } from 'vs/pla import { IHostService } from 'vs/workbench/services/host/browser/host'; import { findGroup } from 'vs/workbench/services/editor/common/editorGroupFinder'; import { ITextEditorService } from 'vs/workbench/services/textfile/common/textEditorService'; -import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; export class EditorService extends Disposable implements EditorServiceImpl { @@ -71,8 +70,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { @IEditorResolverService private readonly editorResolverService: IEditorResolverService, @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, @IHostService private readonly hostService: IHostService, - @ITextEditorService private readonly textEditorService: ITextEditorService, - @IAccessibleNotificationService private readonly accessibleNotificationService: IAccessibleNotificationService + @ITextEditorService private readonly textEditorService: ITextEditorService ) { super(); @@ -974,12 +972,8 @@ export class EditorService extends Disposable implements EditorServiceImpl { } } } - const success = saveResults.every(result => !!result); - if (success) { - this.accessibleNotificationService.notifySaved(options?.reason === SaveReason.EXPLICIT); - } return { - success, + success: saveResults.every(result => !!result), editors: coalesce(saveResults) }; } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index ba78acae038..c7b26d65a40 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -166,7 +166,7 @@ import { IHoverOptions, IHoverService, IHoverWidget } from 'vs/workbench/service import { IRemoteExtensionsScannerService } from 'vs/platform/remote/common/remoteExtensionsScanner'; import { IRemoteSocketFactoryService, RemoteSocketFactoryService } from 'vs/platform/remote/common/remoteSocketFactoryService'; import { EditorParts } from 'vs/workbench/browser/parts/editor/editorParts'; -import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService'; +import { TestAccessibleNotificationService } from 'vs/workbench/contrib/accessibility/browser/accessibleNotificationService'; export function createFileEditorInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined, undefined, undefined, undefined, undefined); From 95d56452416c311e2d7c6edcad7baf9d4812685a Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 16 Oct 2023 18:30:03 +0200 Subject: [PATCH 136/290] fixup AsyncProgress changes --- src/vs/platform/progress/test/common/progress.test.ts | 4 ++-- src/vs/workbench/api/common/extHostChatProvider.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/progress/test/common/progress.test.ts b/src/vs/platform/progress/test/common/progress.test.ts index c352772c277..638f7d59524 100644 --- a/src/vs/platform/progress/test/common/progress.test.ts +++ b/src/vs/platform/progress/test/common/progress.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; -import { Progress } from 'vs/platform/progress/common/progress'; +import { AsyncProgress } from 'vs/platform/progress/common/progress'; suite('Progress', () => { test('multiple report calls are processed in sequence', async () => { @@ -28,7 +28,7 @@ suite('Progress', () => { } executionOrder.push(`end ${value}`); }; - const progress = new Progress(executor, { async: true }); + const progress = new AsyncProgress(executor); progress.report(1); progress.report(2); diff --git a/src/vs/workbench/api/common/extHostChatProvider.ts b/src/vs/workbench/api/common/extHostChatProvider.ts index fa819c6bec3..e8137e11e3e 100644 --- a/src/vs/workbench/api/common/extHostChatProvider.ts +++ b/src/vs/workbench/api/common/extHostChatProvider.ts @@ -9,7 +9,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostChatProviderShape, IMainContext, MainContext, MainThreadChatProviderShape } from 'vs/workbench/api/common/extHost.protocol'; import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; import type * as vscode from 'vscode'; -import { Progress } from 'vs/platform/progress/common/progress'; +import { AsyncProgress } from 'vs/platform/progress/common/progress'; import { IChatMessage, IChatResponseFragment } from 'vs/workbench/contrib/chat/common/chatProvider'; import { ExtensionIdentifier, ExtensionIdentifierMap } from 'vs/platform/extensions/common/extensions'; import { DeferredAsyncIterableObject } from 'vs/base/common/async'; @@ -119,13 +119,13 @@ export class ExtHostChatProvider implements ExtHostChatProviderShape { if (!data) { return; } - const progress = new Progress(async fragment => { + const progress = new AsyncProgress(async fragment => { if (token.isCancellationRequested) { this._logService.warn(`[CHAT](${data.extension.value}) CANNOT send progress because the REQUEST IS CANCELLED`); return; } await this._proxy.$handleProgressChunk(requestId, { index: fragment.index, part: fragment.part }); - }, { async: true }); + }); return data.provider.provideChatResponse(messages.map(typeConvert.ChatMessage.to), options, progress, token); } From 7814938843805efcfd4d86b4cdb03991da161e7f Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 09:33:07 -0700 Subject: [PATCH 137/290] add pointer events none --- .../contrib/codeEditor/browser/accessibility/accessibility.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css index c8404f83e9c..217f1a63287 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css @@ -55,4 +55,5 @@ .accessible-view.hide { opacity: 0; + pointer-events: none; } From 2c3cdaa637d3bcb54341768321edd67ad5fefb51 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 09:35:17 -0700 Subject: [PATCH 138/290] set initial value --- .../workbench/contrib/accessibility/browser/accessibleView.ts | 3 +++ .../contrib/codeEditor/browser/accessibility/accessibility.css | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index f6ff169956a..a684f0808d9 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -170,6 +170,9 @@ export class AccessibleView extends Disposable { this._container = document.createElement('div'); this._container.classList.add('accessible-view'); + if (this._configurationService.getValue('accessibility.hideAccessibleView')) { + this._container.classList.add('hide'); + } const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { contributions: EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeActionController.ID) }; diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css index 217f1a63287..5839e9f9aec 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css @@ -54,6 +54,6 @@ } .accessible-view.hide { - opacity: 0; + visibility: hidden; pointer-events: none; } From bc60ac32587491400860d8fe8dd73c0d9b2d83b9 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 09:37:18 -0700 Subject: [PATCH 139/290] use visibility none instead, use enum --- .../contrib/accessibility/browser/accessibleView.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index a684f0808d9..8a7d668a8a8 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -38,7 +38,7 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { AccessibilityVerbositySettingId, AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; +import { AccessibilityVerbositySettingId, AccessibilityWorkbenchSettingId, AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; @@ -170,7 +170,7 @@ export class AccessibleView extends Disposable { this._container = document.createElement('div'); this._container.classList.add('accessible-view'); - if (this._configurationService.getValue('accessibility.hideAccessibleView')) { + if (this._configurationService.getValue(AccessibilityWorkbenchSettingId.HideAccessibleView)) { this._container.classList.add('hide'); } const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { @@ -218,8 +218,8 @@ export class AccessibleView extends Disposable { this._accessibleViewVerbosityEnabled.set(this._configurationService.getValue(this._currentProvider.verbositySettingKey)); this._updateToolbar(this._currentProvider.actions, this._currentProvider.options.type); } - if (e.affectsConfiguration('accessibility.hideAccessibleView')) { - this._container.classList.toggle('hide', this._configurationService.getValue('accessibility.hideAccessibleView')); + if (e.affectsConfiguration(AccessibilityWorkbenchSettingId.HideAccessibleView)) { + this._container.classList.toggle('hide', this._configurationService.getValue(AccessibilityWorkbenchSettingId.HideAccessibleView)); } })); this._register(this._editorWidget.onDidDispose(() => this._resetContextKeys())); From 243a46dadd6e36f66b95cd7747b7b493dc030f06 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 16 Oct 2023 18:41:54 +0200 Subject: [PATCH 140/290] lazy UI parts for preview --- .../inlineChat/browser/inlineChatWidget.ts | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index a03c1f0c7dc..d3360338d41 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -46,7 +46,6 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { ExpansionState } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; -import { IdleValue } from 'vs/base/common/async'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { IMenuWorkbenchButtonBarOptions, MenuWorkbenchButtonBar } from 'vs/platform/actions/browser/buttonbar'; import { SlashCommandContentWidget } from 'vs/workbench/contrib/chat/browser/chatSlashCommandContentWidget'; @@ -56,6 +55,7 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { assertType } from 'vs/base/common/types'; import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer'; +import { Lazy } from 'vs/base/common/lazy'; const defaultAriaLabel = localize('aria-label', "Inline Chat Input"); @@ -172,11 +172,11 @@ export class InlineChatWidget { private readonly _progressBar: ProgressBar; - private readonly _previewDiffEditor: IdleValue; + private readonly _previewDiffEditor: Lazy; private readonly _previewDiffModel = this._store.add(new MutableDisposable()); private readonly _previewCreateTitle: ResourceLabel; - private readonly _previewCreateEditor: IdleValue; + private readonly _previewCreateEditor: Lazy; private readonly _previewCreateModel = this._store.add(new MutableDisposable()); private readonly _onDidChangeHeight = this._store.add(new MicrotaskEmitter()); @@ -361,13 +361,13 @@ export class InlineChatWidget { this._store.add(feedbackToolbar); // preview editors - this._previewDiffEditor = this._store.add(new IdleValue(() => this._store.add(_instantiationService.createInstance(EmbeddedDiffEditorWidget, this._elements.previewDiff, { + this._previewDiffEditor = new Lazy(() => this._store.add(_instantiationService.createInstance(EmbeddedDiffEditorWidget, this._elements.previewDiff, { ..._previewEditorEditorOptions, onlyShowAccessibleDiffViewer: this._accessibilityService.isScreenReaderOptimized(), - }, { modifiedEditor: codeEditorWidgetOptions, originalEditor: codeEditorWidgetOptions }, parentEditor)))); + }, { modifiedEditor: codeEditorWidgetOptions, originalEditor: codeEditorWidgetOptions }, parentEditor))); this._previewCreateTitle = this._store.add(_instantiationService.createInstance(ResourceLabel, this._elements.previewCreateTitle, { supportIcons: true })); - this._previewCreateEditor = this._store.add(new IdleValue(() => this._store.add(_instantiationService.createInstance(EmbeddedCodeEditorWidget, this._elements.previewCreate, _previewEditorEditorOptions, codeEditorWidgetOptions, parentEditor)))); + this._previewCreateEditor = new Lazy(() => this._store.add(_instantiationService.createInstance(EmbeddedCodeEditorWidget, this._elements.previewCreate, _previewEditorEditorOptions, codeEditorWidgetOptions, parentEditor))); this._elements.message.tabIndex = 0; this._elements.message.ariaLabel = this._accessibleViewService.getOpenAriaHint(AccessibilityVerbositySettingId.InlineChat); @@ -427,13 +427,17 @@ export class InlineChatWidget { this._inputEditor.layout(new Dimension(innerEditorWidth, this._inputEditor.getContentHeight())); this._elements.placeholder.style.width = `${innerEditorWidth /* input-padding*/}px`; - const previewDiffDim = new Dimension(dim.width, Math.min(300, Math.max(0, this._previewDiffEditor.value.getContentHeight()))); - this._previewDiffEditor.value.layout(previewDiffDim); - this._elements.previewDiff.style.height = `${previewDiffDim.height}px`; + if (this._previewDiffEditor.hasValue) { + const previewDiffDim = new Dimension(dim.width, Math.min(300, Math.max(0, this._previewDiffEditor.value.getContentHeight()))); + this._previewDiffEditor.value.layout(previewDiffDim); + this._elements.previewDiff.style.height = `${previewDiffDim.height}px`; + } - const previewCreateDim = new Dimension(dim.width, Math.min(300, Math.max(0, this._previewCreateEditor.value.getContentHeight()))); - this._previewCreateEditor.value.layout(previewCreateDim); - this._elements.previewCreate.style.height = `${previewCreateDim.height}px`; + if (this._previewCreateEditor.hasValue) { + const previewCreateDim = new Dimension(dim.width, Math.min(300, Math.max(0, this._previewCreateEditor.value.getContentHeight()))); + this._previewCreateEditor.value.layout(previewCreateDim); + this._elements.previewCreate.style.height = `${previewCreateDim.height}px`; + } const lineHeight = this.parentEditor.getOption(EditorOption.lineHeight); const editorHeight = this.parentEditor.getLayoutInfo().height; @@ -450,9 +454,9 @@ export class InlineChatWidget { const base = getTotalHeight(this._elements.progress) + getTotalHeight(this._elements.status); const editorHeight = this._inputEditor.getContentHeight() + 12 /* padding and border */; const markdownMessageHeight = getTotalHeight(this._elements.markdownMessage); - const previewDiffHeight = this._previewDiffEditor.value.getModel() ? 12 + Math.min(300, Math.max(0, this._previewDiffEditor.value.getContentHeight())) : 0; + const previewDiffHeight = this._previewDiffEditor.hasValue && this._previewDiffEditor.value.getModel() ? 12 + Math.min(300, Math.max(0, this._previewDiffEditor.value.getContentHeight())) : 0; const previewCreateTitleHeight = getTotalHeight(this._elements.previewCreateTitle); - const previewCreateHeight = this._previewCreateEditor.value.getModel() ? 18 + Math.min(300, Math.max(0, this._previewCreateEditor.value.getContentHeight())) : 0; + const previewCreateHeight = this._previewCreateEditor.hasValue && this._previewCreateEditor.value.getModel() ? 18 + Math.min(300, Math.max(0, this._previewCreateEditor.value.getContentHeight())) : 0; return base + editorHeight + markdownMessageHeight + previewDiffHeight + previewCreateTitleHeight + previewCreateHeight + 18 /* padding */ + 8 /*shadow*/; } @@ -673,7 +677,9 @@ export class InlineChatWidget { hideEditsPreview() { this._elements.previewDiff.classList.add('hidden'); - this._previewDiffEditor.value.setModel(null); + if (this._previewDiffEditor.hasValue) { + this._previewDiffEditor.value.setModel(null); + } this._previewDiffModel.clear(); this._onDidChangeHeight.fire(); } @@ -695,7 +701,9 @@ export class InlineChatWidget { hideCreatePreview() { this._elements.previewCreateTitle.classList.add('hidden'); this._elements.previewCreate.classList.add('hidden'); - this._previewCreateEditor.value.setModel(null); + if (this._previewCreateEditor.hasValue) { + this._previewCreateEditor.value.setModel(null); + } this._previewCreateTitle.element.clear(); this._onDidChangeHeight.fire(); } From 3cdcf0abffefffa46fc553a8afd4bdba90b4e4fe Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Mon, 16 Oct 2023 10:13:02 -0700 Subject: [PATCH 141/290] Use `.value` since the type had changed from `string` to `ILocalizedString` (#195709) Fixes https://github.com/microsoft/vscode/issues/195518 regressed in https://github.com/microsoft/vscode/pull/193544 --- .../contrib/userDataSync/browser/userDataSync.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 5691e410542..a1a584a3a32 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -904,17 +904,17 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo disposables.add(quickPick); const items: Array = []; if (that.userDataSyncService.conflicts.length) { - items.push({ id: showConflictsCommandId, label: `${SYNC_TITLE}: ${that.getShowConflictsTitle().original}` }); + items.push({ id: showConflictsCommandId, label: `${SYNC_TITLE.value}: ${that.getShowConflictsTitle().original}` }); items.push({ type: 'separator' }); } - items.push({ id: configureSyncCommand.id, label: `${SYNC_TITLE}: ${configureSyncCommand.title.original}` }); - items.push({ id: showSyncSettingsCommand.id, label: `${SYNC_TITLE}: ${showSyncSettingsCommand.title.original}` }); - items.push({ id: showSyncedDataCommand.id, label: `${SYNC_TITLE}: ${showSyncedDataCommand.title.original}` }); + items.push({ id: configureSyncCommand.id, label: `${SYNC_TITLE.value}: ${configureSyncCommand.title.original}` }); + items.push({ id: showSyncSettingsCommand.id, label: `${SYNC_TITLE.value}: ${showSyncSettingsCommand.title.original}` }); + items.push({ id: showSyncedDataCommand.id, label: `${SYNC_TITLE.value}: ${showSyncedDataCommand.title.original}` }); items.push({ type: 'separator' }); - items.push({ id: syncNowCommand.id, label: `${SYNC_TITLE}: ${syncNowCommand.title.original}`, description: syncNowCommand.description(that.userDataSyncService) }); + items.push({ id: syncNowCommand.id, label: `${SYNC_TITLE.value}: ${syncNowCommand.title.original}`, description: syncNowCommand.description(that.userDataSyncService) }); if (that.userDataSyncEnablementService.canToggleEnablement()) { const account = that.userDataSyncWorkbenchService.current; - items.push({ id: turnOffSyncCommand.id, label: `${SYNC_TITLE}: ${turnOffSyncCommand.title.original}`, description: account ? `${account.accountName} (${that.authenticationService.getLabel(account.authenticationProviderId)})` : undefined }); + items.push({ id: turnOffSyncCommand.id, label: `${SYNC_TITLE.value}: ${turnOffSyncCommand.title.original}`, description: account ? `${account.accountName} (${that.authenticationService.getLabel(account.authenticationProviderId)})` : undefined }); } quickPick.items = items; disposables.add(quickPick.onDidAccept(() => { From 7cd597f8466cf8fe3dc3eb2859ed8658786a7111 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 10:23:45 -0700 Subject: [PATCH 142/290] add formatting cue --- .../editor/contrib/format/browser/format.ts | 4 +++- .../audioCues/browser/audioCueService.ts | 7 +++++++ .../audioCues/browser/media/format.mp3 | Bin 0 -> 36070 bytes .../browser/accessibleNotificationService.ts | 2 +- .../browser/audioCues.contribution.ts | 18 +++++++++++++++--- 5 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/vs/platform/audioCues/browser/media/format.mp3 diff --git a/src/vs/editor/contrib/format/browser/format.ts b/src/vs/editor/contrib/format/browser/format.ts index 42d8cf3d87f..aa5f7bbbe69 100644 --- a/src/vs/editor/contrib/format/browser/format.ts +++ b/src/vs/editor/contrib/format/browser/format.ts @@ -33,6 +33,7 @@ import { IProgress } from 'vs/platform/progress/common/progress'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry'; import { ILogService } from 'vs/platform/log/common/log'; +import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; export function alertFormattingEdits(edits: ISingleEditOperation[]): void { @@ -332,6 +333,7 @@ export async function formatDocumentWithProvider( token: CancellationToken ): Promise { const workerService = accessor.get(IEditorWorkerService); + const accessibleNotificationService = accessor.get(IAccessibleNotificationService); let model: ITextModel; let cts: CancellationTokenSource; @@ -393,7 +395,7 @@ export async function formatDocumentWithProvider( return null; }); } - + accessibleNotificationService.notify(AccessibleNotificationEvent.Format); return true; } diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 0915165b7c7..2583c4b92a3 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -256,6 +256,7 @@ export class Sound { public static readonly chatResponseReceived4 = Sound.register({ fileName: 'chatResponseReceived4.mp3' }); public static readonly clear = Sound.register({ fileName: 'clear.mp3' }); public static readonly save = Sound.register({ fileName: 'save.mp3' }); + public static readonly format = Sound.register({ fileName: 'format.mp3' }); private constructor(public readonly fileName: string) { } } @@ -433,6 +434,12 @@ export class AudioCue { settingsKey: 'audioCues.save' }); + public static readonly format = AudioCue.register({ + name: localize('audioCues.format', 'Format'), + sound: Sound.format, + settingsKey: 'audioCues.format' + }); + private constructor( public readonly sound: SoundSource, public readonly name: string, diff --git a/src/vs/platform/audioCues/browser/media/format.mp3 b/src/vs/platform/audioCues/browser/media/format.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..6064ba361d0b9d2e8341f720e3e703de5c36d173 GIT binary patch literal 36070 zcmeI4c{Ei2|M>5$mMmi*LkuB=#+sxIX6&+ttYcrxTG3|gBPy~hWnV&x6s3$MOO{Y6 zl`N$YB3s$+cY1%`@6Y*lexE;nzjMC*I^Umpox^>-?%Z>q_xX4|yk2+ieI5D)MJPZk z!Y3^)EC7HDF!J~GcEy?o`D1Oc@;EsqIaO^FV*v01+>d*DTb?+6*u>lzz~cTYO1OV2 z@_$#f|Jn2JiW2dkWByf9P}#5f*B)AB|F0k6a7skruV|6~M6)n9)%qtI?(cIe$p2kY zRaO4`1pm4mf+kVx-#h-QsO(qL`E}3FBmYnK{A5BebOLk&bOLk&bOLk&bOLk&bOLk& zbOLk&bOQgs5CGS!@qgvAkNnpLIsexNc>k}B0QFznZT>q!^}?-(5mZ#+LroN6HElI6 zNAGwT+|KB`DLWSgemXf{YhRLxFgFo;##{RA6(0ow6hFMBC9;}BHG)YkQDP~eluL^6 z!Fg4td0+=z*~`x0c|u&pyC=C}7WH@YJr1v=GNtDGMfgG}gshbM^+O-PRoUvd2ktq6 z9}L`f=tGZHUPTO~)Ca_u;V2xCT1#^{H4<6>uH?jVfA#pa#& z6~y4P40a2!*L(0L*@%>Dy|KDxf6(KTEbM7cPZ5{Gsk^yGMOY*@6!x^tcltqOzn z$I^#}t3mK?G5&6n#G9ci2T9=!#_SZv2o&$Yf4IWFe=GD;xneS{`M)a1t?aYHBG%JP zk$K+~omKbmgSTx3{8yRxAC!80tR%kr+T4}1!dY`GyA>JGqs3x!I2_O!+af0b=;HxZ z8!V~HMohxxjyEw%?ZxPA#Vy@bZs_!-mZN?asQi!5qr1q${U#Z(^&g+VdRj=Vr3+LP# zP?n)Vn4;5n+TNT&nFMvFJ3!j>@{-VLEfFm9qxH`Zi!%VC1NF@4Q8YS{F*!&}qM|&g z$V6M(f${dPai{#cT(S8y761mvkt2XOa>3P*KwGmEp^-{)5)OizCJ5e(xobkqeIoQi z*M<}80pO|_pdN4aC{M?GpPqR8pt=Qevp`(Vb~Vz_<{Cxy7JsB9A*6R0Va5+IqZGvI z2$9+mWoxHbrk#7NyKJmy6T!viqKnSGW1BSPNX6tGj_x|gg7MH3dZ)sQ)d7h)O&q^B z84{-_+`<+Bv~97opD%gvU=`mTx^x~3UUB>!izop%Z4oxYSFNdgY5g&um9l5|qKeTW8?3qq3>($2#6|PQeo?-D&v4@Wp8`eD5yU(NJsc{;U z&|H!v1mD4L3{xn0$0}6|urZ7k12}dVlV&C&f{Ipy-WV~M<@e-S1=W#R&)kKRE3!?6!`4^9crbaq zu&-Z9mvI~;%7Y#o*i(R(S#&edzvXh5UG_!Isp8|UuSW%4DFK(YW%i4y2F1M@@+vYu zBIPkdN~tkb%Js_p$Pq0V%oxvX$maE#YgggSO79tyYQ@xM zTj(=NCZ(ONf1lqpLYd9B#q*_D<%g;D4V?P()#dYB&m_tP7eud6 z@zR8!`G9%f9$WmKSPqEFi@3f4-p5yNYg-$?xhLkJ0bW~cw1JZfg+0y!gCs`ww#(Xb zE+~`-f~rJ9BHCbBMiLZO3>_tqq#@dPI3t7$$b}dH} z{di4}kUl9gw=1gZ@CVna>0U-Cd7^T!J1{lLbaZIrWya!Ln@w@>b z2UDD(iSq!f^7MXpjaTW-GX~Q}(;hP$Pu@YTaIa-#;CPvKNB1Q4R&z~--pD8}4i}~o z$@`}xLn5ZIO3z=OSS@ySJ75_8?Y#N{)pt)7&2N?#AEZnTIP5a^`w^Ua$I>9}PP|Ue z<@ZTPVFh||u+NvTG(7ioa+zCfxv{>MrPd>CuBu~iv?qh@!tsZ$oHlhyA)LI-I{lgP zI^!;4y^}M%Vf%2MvO(WoJ!)(Rw>mLqEm6(@R9~{x(lSvxg((CHXAyq9Q0`xJa0EQz zM(Js)gDZUdKgFlHIEjp%lLe}cjBFjUltH_^;2yK63cAjDiQt@jd-Ffoa+5UF47Ypd`7==@~ggTYRzK7$fXrP94t zb6FF`SrOU9R+D!KIexS3@t6)S+qK5c(H~-1v?PkNC?$40LHGjy*X?c3FQskeBV zI1z9x6|MxmXv%gjqF6WAt*;8xgn_hi`0(dJ^z+o%ybt+VIS0aASo-&5Cur&`=Mp;= zO%DP`7`ie$zdaO)#Uq=jHf);Z5`~xZO;SDqGSH=XJ*_88{LK0o%vG-Fu>on;PUHlm zs3hv+;4$}S0%?85YB6GHJ%Ua$uN+sLx$TL{pUP>I87h)Y4_je@$}3E{ZG8Zra+ub^ z`(%i2iIm}mTp&X=GC8ErMf4!ouBy1yn7T-mvZ7DfX|{)IKAI`m;)&pB^;|u+vC$K$ z%K5PujA}Jb7T-Scu-a`Q5AN!cJIhs%i(ps4wrbP3e5na<9NDOIBQjNsn&gILi!s%R zVu_6W)jDoXq5bXzE?32H<8y?1sY-b`fP0p|gBb=ls|gO}9|KMflUp<%3uC+3`me5^ zxEOe#RN-|UczQ%tr0J=I?8LLJH3mwP8s`V0-QnwJ79J>dMTTQxIH7u*SK#1OS<)Ms zZ!E&tb1~#Y0rgOS)`rWp`+?2%9}L(JNw)k^7Eu)0c{R-!TBsmtNe$YCZcTfvgWrY@ z?RQN)`k}8H(f6J+vy_)HBDBvk>VBUiQ5x z@9VGjq*AZ#$isEsh(MLFT4Or+ID=kbKFuR4n0{0v5`%(F$;*@F@ZGbyF zU2C^^QMtB!SC7(jJN@FR9_319w(zo60@be3!;*Fzz>m;&`my&Q@_H^#i0=aoU!+8o z-o=Vd!=ZqQx*Q5g5YmCrLq;a!bA@ckPdElje=5gCMpW4w!Ja7w9W4l@9-LC;i-+O% zdhdxKCgeAzqepMaR_taDvbiPjc2eq9;?rfJ;L*HE901(xCX_<{;AzNq zwyMSCS=u_jwcJQ#rDBn1#cC-kf-9^dU%jPKb^lJ&?}2c>K-INf9golJ@%IH@>^mzl zr)3aEY#AS0P#E}Jo0vNu?m8P&{e?S_Tfel(>5N&4?~Oda@KX=X8(%k`y8&*lQ2`*3 zFh4Lr`mAc%-%sI$qE!I&A$Ihk9cY4FEVHwzWK$sUL>{2#8BrGi9r&p1IbH5-a$65a zG5}>^;k^!^Vp-%bs4%O2Be)uOy6R+EI9yVgJm&IKIT-*6ICOJ8&<-%mFQqzDRC$LE z2q{kk5b4ys=DU4BuTH_O9gf$t(!a7E>Q%A!v6^{tFzxlr$`1kEtykFuqfBih`pPOS zxLKpdDg&PE^viE&)d?aJZM=enE*&+qimmf4@~8theL;$EY~6Yzc<(`)bwSGURPV}> z2_YsJQ6E~V5LL1?P0o~GXEg7>+K_+P&=3|V0rMVm>&OG;50)n@HV^G;);4mFg_cD5 z@bXAq4>t`P88L{f$m_ay*Oi!2RsizN&T97|x3*+PZ@&l4Pp>_`0phVPr7=1Y#iH)$ z;kLjSKpFvQ87CcP)`0`>N!)-A46jDg0otH|1UE2B-HnrmnJ;DTAj>lXv8R!xNhg3ZZ#^X zh71pnib%;qg2AO)A1f!F(#qUkF5A%@(#3n=JFH zKcW3v^h1y31DT{HH>)=iyDyG_bCFl%kAmYI{0s*c%x^3Uz$&H$*<@KwRfx)Xs+l%S z^Fk_{M5HOs3XTZCM2$`~;lCSR?7!=>1Bk?F;1pb%@MM?hcr3n@0}d^ZAWS&JBE=0E zjiTWB3F)Tx)BEGUZ$Y|XDHVxut*GN+6s!bR+v=G1r{VCxAdS`_y~YcH5?gmf#VpR( zrbZvP-<0o`+a#!#t@U^^@oc3LUH!kVJv&cR4sQS;WRi4aZOOnuHDgs*AHb0(z`K*C z+>e3+?MFBueC_IV_!ocLbn|zaS1@jQ3)@M-RLNU0TEl?5VmRD;_y^d|Ze$;BCtehi z3j?V9P~Z?2CkOyL1~IDkc{xzL7}F>tSqM3-$7zbpvk?Uldm+04t|TU3jHV`Dxf2)j zT1`GdwJ;{aS53&LD-vOo7SVu$NmEE0+3LD| z1k&v)0?=9X1>VHUxxThboiQTGEOn(aPe1R>NI;Lm zp;?+}7!?vP3Qd3zV5DH8sGuG{AD$a!%5cio-zq+&%Eu?WZ0BxWF*yp93JeGa{XH zL!-0Fnf;VbKeT3SV6+X4Pt}XnQtY9=PM=7Y`y?3-$#iC6VF9EdxzHp5xMfKEN0##} zRr@KoCM##nby}5g-VAww*G}G{gZvn~ThL>~2^>(6pp;1(r#*K9X%`fKMcQ0>ch|(K zHn_=cl+bR(dwe{6L;BfP748X~%Q2~p_nS5@_=)@>_##79Jgx|C0XJ2~?T4g5Nf<^z zM+d?UW%B5TOP=NM@P$oD$ z=iu3On_$Y%QEo38F>0m*8;YE_E9xL0`(ngXX@)g%F>DIS%8$5T7T`4_NPA+4i$pBK z=07KE`8{?zb6b)A5&w|S^QpB^(@pwG|$;KR?ZR3W4Q1}yHAK^zcgvC%LG6f->5xJ;LR!A7x z29Ac3NoYu-3qI(o+~;Yi!RzBLhj^LF+Uj9r#CkXPK6uQs$-~p_r@LgTD>Ek2ZiRn2 zs9~m**^X33VFjqX(SwEH*1fgE0W`B)gJhc2nfey*6<*!ClpwA`xR6qyt`bZ6D%d>U z*gvI4{Fs=6JG$typstgU8FDG&n`%#&;#N)WP?E?qa4OdUh~x5aPz-Pt5F~1C-W8oI z-oRWI49vJ2lu>E!?juN6pJEFRW#~U=ICvG@0N1ijZG|$n0>?||A+EYSnhn}pp5XLH zvFNYY!uSt>>8E3&zFY&-dAS-X8cP7~94RH7qd?ik>jReIl8S?N4QEm$?j*7WNdl51 z0G`sqsZegtboDoinoQKHVMUUs#A!}8l-h^8DOL!h54UQVr7`=2PB84~e-(AA_tl+C zp?2-Zu3W!7_sn^H&2MH*?WMiq?vv2Z>}Q9NmA>GY<*er`ko4gc z7eQ6LPD|)d<%nd2-AV1Jw^svP+P??*v)c0>c?D(nF>X4;p9`TWw}&U$A6(BAUd|mW zy-*B-)1a*+yUq=84czE^1#X@rCh>6NHfo3l2eC=@`y(UJlp042x4v?A%TT(%@430F z9+j`Dv?u3IrH-eI!n>;jPuXmY`;QZ05ENE0DbzY7M!jD2` z0zhUJ3x&*jOJgG4{>fAG1!~NiLVs^ipFx3+{14{XJy1KVNxK4!DNES(riG(NR8DxG z8D8D;5h{7KKDV>0`szSdNhV4uv=lS%5!37vWK*@cVs!xEyn7m8Kh#JUC+-J??>6F4+L&XX{1PcHoYS}Pv#0ppZc z$FG<5@w^JYX+`05GhUuMss?8T zf#D8E^m9O2irS!~fCn1VZlEmoG~eo*$R}=>Y)TxTDwM^>Li7yesoh{z-}vJ3?gMg# zX{#_+zGMZ_g|o3t#n++A+>+=7-Ld+wvl}3IDp9e!_Ccc6f->(r2rSCWwHLknI z%IkqMw{D&bzjt#IoLMu{^_A%+HbazhCCD5*el9l#$8 z1P)x(S13(upoGPsi}OXE^a4@5+#T1cLFvmCN~#TSYuLKV#LrP%h#!q84NfAF-anNK zBEx-f52Dr#NC}_#OvCk!I8^UWvrkDyN~Py$Zi?ed$QOysNYVc9$Iq;XYk;4ZxAtOg zB`8bHx+ZTfQPPjNv>1l3bg{S#Z>GI8xxMnzK^R=htVkA&YFSn?LZ;)~@clSHNGeWO zQwet#e+efDjn>wX;3s%x)i>|iw%Re=gI2@+~y z8QLAvko~rIFDdd@p1k68?epH=Z%aK#-NihvM5#2L^w6vt<5u#mEBx?!`t9mmiBQEJ z?+`h4;v4k}5FBDHxOA|>yN5Oemk1Y$JZ;>hXubhA%M7K#71KA}s%_7E-9_|R4&M3H zEr1tcfmQKq;u+CMKm`pMwM6rg)L4LQ9)JReqd0!->$@dC6R7|*@3=^gi`3>=IcuQ#II{ z+I+SF13p~Wk+Tf=$UbElX@wPx*pv#`TrX=cXMW?b<1)v|%X>7y6>YB%mwhq8z92Z& zKBX6Q8+1XPYy^GGX?dio)NphjQoJT9R)FTlaq$6cAK1?F1jF8OV9D&=4D&plWH$x~ zn#2j5CP9E`*B59#e5Hi_(K|MSNkZJ}M{_xgw7RS`^E1 zT^O+uJY!|q8e)?8nVCtl4Z#9`LWR|}+(6h>iW(J{D9%_W?FggeftiIMg^3xi|9AI34_1!+GXI0ztsLy$3AW8yDl#w~l?9C!wp z3Dr%!j0~bpt>qMkL-q!kV$p=Cw8c&DIVn`hD0XIR1qT~9aVwCRtVWtyK>9m zWt`pHFw*$?JIz_C0JGzSvrn(t46u~!1Hr|_v#+#35Pw=w7yRh<9Q+~80sg?4yC!ye zBK1|=g6ws8b5}?NSTO_sk{}D2s*RI@D#CDZ+M90$vI;?)$Wp;kWrYyT5{)1tcoWGe z>dA!;$C-R7mR3)N_xIm_S>KrLPGD_|rpk<3aqJpPx+KkmIvf^P-vMsj_qHprSF+qkf|OCa6TZM0Vbp8EFFBOKTZNj0Tkg%dlKhm!w@7}(heGS< zeKf4+V78Ed)hGE}(=0gGOl!k_lH0VA_HN;SMgiBW@R0ySi*;X=i9SwJvv}TnN&+ZF zzGq1U7s*X{V>JL;vq%Oh3~v1nA2Bf`i`p{RHUB{eH&u2)_`ZEB6ZydgJ#K zpey(L8Pg;DLV&K^FF5Fp-%o(9-0x>hkMIitx^lnZpf`R$0lIR(pD{hcF9hhy{epwu z`27Uv%Kd)E^a#HYpey$a4tnGF6ZpAY?tlBoOSG``cdWmk{q~ITbC9Dgm!rSc-=5w7 zC$gr`tAB#}wvI_xZd-T%pGcmr+@GMntz*)a+t%IxCz7Wt_a~@t>zH)qwsrUaiR9_Z z{R!&ZIwoDYZQcEUB6+%Ue}ek9j!9Q;TX+ATNS?0TpP;_2W73t|*4_UnlBX;8C#Y}h zm~`c~b@%^? this._notifySaved(e.reason === SaveReason.EXPLICIT))); + this._events.set(AccessibleNotificationEvent.Format, { audioCue: AudioCue.format, alertMessage: localize('formatted', "Formatted") }); } notify(event: AccessibleNotificationEvent): void { diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 3da9c2eeade..343c228c2b1 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -143,9 +143,21 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'enum': ['userGesture', 'always', 'never'], 'default': 'never', 'enumDescriptions': [ - localize('audioCues.enabled.userGesture', "Plays the audio cue when a user explicitly saves a file."), - localize('audioCues.enabled.always', "Plays the audio cue whenever a file is saved, including auto save."), - localize('audioCues.enabled.never', "Never plays the audio cue.") + localize('audioCues.save.userGesture', "Plays the audio cue when a user explicitly saves a file."), + localize('audioCues.save.always', "Plays the audio cue whenever a file is saved, including auto save."), + localize('audioCues.save.never', "Never plays the audio cue.") + ], + tags: ['accessibility'] + }, + 'audioCues.format': { + 'markdownDescription': localize('audioCues.format', "Plays a sound when a file or notebook is formatted. Also see {0}", '`#accessibility.alert.formatted#`'), + 'type': 'string', + 'enum': ['userGesture', 'always', 'never'], + 'default': 'never', + 'enumDescriptions': [ + localize('audioCues.format.userGesture', "Plays the audio cue when a user explicitly formats a file."), + localize('audioCues.format.always', "Plays the audio cue whenever a file is formatted, including if it is set to format on save, type, or, paste, or run of a cell."), + localize('audioCues.format.never', "Never plays the audio cue.") ], tags: ['accessibility'] }, From 67e8288993a0f703e4d73b54407bd04fd5339a86 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 16 Oct 2023 10:47:19 -0700 Subject: [PATCH 143/290] Fix tests --- .../contrib/terminal/test/browser/xterm/xtermTerminal.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts index c43605db7b4..39f866b559c 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts @@ -26,7 +26,7 @@ import { isSafari } from 'vs/base/browser/browser'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; -import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { TestLayoutService, TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { importAMDNodeModule } from 'vs/amdX'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; @@ -34,6 +34,7 @@ import { Color, RGBA } from 'vs/base/common/color'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ITerminalLogService } from 'vs/platform/terminal/common/terminal'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; class TestWebglAddon implements WebglAddon { static shouldThrow = false; @@ -125,6 +126,7 @@ suite('XtermTerminal', () => { instantiationService.stub(IContextMenuService, store.add(instantiationService.createInstance(ContextMenuService))); instantiationService.stub(ILifecycleService, store.add(new TestLifecycleService())); instantiationService.stub(IContextKeyService, new MockContextKeyService()); + instantiationService.stub(ILayoutService, new TestLayoutService()); configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper)); XTermBaseCtor = (await importAMDNodeModule('xterm', 'lib/xterm.js')).Terminal; From 207df81936323ee3e962280589c9885c3af12ede Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 10:56:17 -0700 Subject: [PATCH 144/290] fix #189235 --- .../editor/contrib/format/browser/format.ts | 10 +++-- .../contrib/format/browser/formatActions.ts | 2 +- .../accessibility/common/accessibility.ts | 2 +- .../browser/accessibilityConfiguration.ts | 15 ++++++- .../browser/accessibleNotificationService.ts | 43 +++++++++++++------ .../browser/contrib/format/formatting.ts | 2 +- 6 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/vs/editor/contrib/format/browser/format.ts b/src/vs/editor/contrib/format/browser/format.ts index aa5f7bbbe69..6bd3ef94d3f 100644 --- a/src/vs/editor/contrib/format/browser/format.ts +++ b/src/vs/editor/contrib/format/browser/format.ts @@ -311,7 +311,8 @@ export async function formatDocumentWithSelectedProvider( editorOrModel: ITextModel | IActiveCodeEditor, mode: FormattingMode, progress: IProgress, - token: CancellationToken + token: CancellationToken, + userGesture?: boolean ): Promise { const instaService = accessor.get(IInstantiationService); @@ -321,7 +322,7 @@ export async function formatDocumentWithSelectedProvider( const selected = await FormattingConflicts.select(provider, model, mode); if (selected) { progress.report(selected); - await instaService.invokeFunction(formatDocumentWithProvider, selected, editorOrModel, mode, token); + await instaService.invokeFunction(formatDocumentWithProvider, selected, editorOrModel, mode, token, userGesture); } } @@ -330,7 +331,8 @@ export async function formatDocumentWithProvider( provider: DocumentFormattingEditProvider, editorOrModel: ITextModel | IActiveCodeEditor, mode: FormattingMode, - token: CancellationToken + token: CancellationToken, + userGesture?: boolean ): Promise { const workerService = accessor.get(IEditorWorkerService); const accessibleNotificationService = accessor.get(IAccessibleNotificationService); @@ -395,7 +397,7 @@ export async function formatDocumentWithProvider( return null; }); } - accessibleNotificationService.notify(AccessibleNotificationEvent.Format); + accessibleNotificationService.notify(AccessibleNotificationEvent.Format, userGesture); return true; } diff --git a/src/vs/editor/contrib/format/browser/formatActions.ts b/src/vs/editor/contrib/format/browser/formatActions.ts index 6814b36c485..3ba32683d95 100644 --- a/src/vs/editor/contrib/format/browser/formatActions.ts +++ b/src/vs/editor/contrib/format/browser/formatActions.ts @@ -233,7 +233,7 @@ class FormatDocumentAction extends EditorAction { const instaService = accessor.get(IInstantiationService); const progressService = accessor.get(IEditorProgressService); await progressService.showWhile( - instaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None), + instaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None, true), 250 ); } diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index db150f594fe..55b6f1ba0c1 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -55,7 +55,7 @@ export const IAccessibleNotificationService = createDecorator = new Map(); + private _events: Map = new Map(); constructor( @IAudioCueService private readonly _audioCueService: IAudioCueService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, - @IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService) { + @IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService, + @ILogService private readonly _logService: ILogService) { super(); this._events.set(AccessibleNotificationEvent.Clear, { audioCue: AudioCue.clear, alertMessage: localize('cleared', "Cleared") }); - this._register(this._workingCopyService.onDidSave((e) => this._notifySaved(e.reason === SaveReason.EXPLICIT))); - this._events.set(AccessibleNotificationEvent.Format, { audioCue: AudioCue.format, alertMessage: localize('formatted', "Formatted") }); + this._events.set(AccessibleNotificationEvent.Save, { audioCue: AudioCue.save, alertMessage: localize('saved', "Saved"), alertSetting: AccessibilityAlertSettingId.Save }); + this._events.set(AccessibleNotificationEvent.Format, { audioCue: AudioCue.format, alertMessage: localize('formatted', "Formatted"), alertSetting: AccessibilityAlertSettingId.Format }); + + this._register(this._workingCopyService.onDidSave((e) => this._notify(AccessibleNotificationEvent.Save, e.reason === SaveReason.EXPLICIT))); } - notify(event: AccessibleNotificationEvent): void { + notify(event: AccessibleNotificationEvent, userGesture?: boolean): void { + if (event === AccessibleNotificationEvent.Format) { + return this._notify(event, userGesture); + } const { audioCue, alertMessage } = this._events.get(event)!; const audioCueValue = this._configurationService.getValue(audioCue.settingsKey); if (audioCueValue === 'on' || audioCueValue === 'auto' && this._accessibilityService.isScreenReaderOptimized()) { + this._logService.debug('AccessibleNotificationService playing sound: ', audioCue.name); this._audioCueService.playAudioCue(audioCue); } else { + this._logService.debug('AccessibleNotificationService alerting: ', alertMessage); this._accessibilityService.alert(alertMessage); } } - private _notifySaved(userGesture: boolean): void { - const { audioCue, alertMessage } = this._events.get(AccessibleNotificationEvent.Save)!; - const alertSetting: NotificationSetting = this._configurationService.getValue('accessibility.alert.save'); - if (this._shouldNotify(alertSetting, userGesture)) { + private _notify(event: AccessibleNotificationEvent, userGesture?: boolean): void { + const { audioCue, alertMessage, alertSetting } = this._events.get(event)!; + if (!alertSetting) { + return; + } + const alertSettingValue: NotificationSetting = this._configurationService.getValue(alertSetting); + if (this._shouldNotify(alertSettingValue, userGesture)) { + this._logService.debug('AccessibleNotificationService alerting: ', alertMessage); this._accessibilityService.alert(alertMessage); } const audioCueSetting: NotificationSetting = this._configurationService.getValue(audioCue.settingsKey); if (this._shouldNotify(audioCueSetting, userGesture)) { + this._logService.debug('AccessibleNotificationService playing sound: ', audioCue.name); // Play sound bypasses the usual audio cue checks IE screen reader optimized, auto, etc. - this._audioCueService.playSound(Sound.save, true); + this._audioCueService.playSound(audioCue.sound.getSound(), true); } } - private _shouldNotify(settingValue: NotificationSetting, userGesture: boolean): boolean { - return settingValue === 'always' || settingValue === 'userGesture' && userGesture; + private _shouldNotify(settingValue: NotificationSetting, userGesture?: boolean): boolean { + return settingValue === 'always' || settingValue === 'userGesture' && userGesture === true; } } type NotificationSetting = 'never' | 'always' | 'userGesture'; @@ -58,5 +73,5 @@ export class TestAccessibleNotificationService extends Disposable implements IAc declare readonly _serviceBrand: undefined; - notify(event: AccessibleNotificationEvent): void { } + notify(event: AccessibleNotificationEvent, userGesture?: boolean): void { } } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts b/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts index 6ff70b9ae51..cfb37c00a5f 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts @@ -131,7 +131,7 @@ registerEditorAction(class FormatCellAction extends EditorAction { async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { if (editor.hasModel()) { const instaService = accessor.get(IInstantiationService); - await instaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None); + await instaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None, true); } } }); From f430137625fc5bdc0b206f34ac092259c67a1847 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2023 20:18:33 +0200 Subject: [PATCH 145/290] settings - let folders in `node_modules` still be editable (#195714) --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0c73cc745a6..e70c549fd4d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -35,7 +35,7 @@ "src/vs/editor/test/node/diffing/fixtures/**": true, }, "files.readonlyInclude": { - "**/node_modules/**": true, + "**/node_modules/**/*.*": true, "**/yarn.lock": true, "**/Cargo.lock": true, "src/vs/workbench/workbench.web.main.css": true, From e5c5ddfcf6923959d563d05d1a7cf53803793811 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 16 Oct 2023 11:21:24 -0700 Subject: [PATCH 146/290] Fix Buffer Content Tracker tests --- .../accessibility/test/browser/bufferContentTracker.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index bc717d3d81a..938c7b30498 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -15,6 +15,7 @@ import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuS import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { ILoggerService, NullLogService } from 'vs/platform/log/common/log'; import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; @@ -28,7 +29,7 @@ import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/xterm/xterm import { ITerminalConfiguration } from 'vs/workbench/contrib/terminal/common/terminal'; import { BufferContentTracker } from 'vs/workbench/contrib/terminalContrib/accessibility/browser/bufferContentTracker'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { TestLayoutService, TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices'; import { TestLoggerService } from 'vs/workbench/test/common/workbenchTestServices'; import type { Terminal } from 'xterm'; @@ -68,6 +69,7 @@ suite('Buffer Content Tracker', () => { instantiationService.stub(ILifecycleService, store.add(new TestLifecycleService())); instantiationService.stub(IContextKeyService, store.add(new MockContextKeyService())); instantiationService.stub(IAccessibleNotificationService, store.add(new TestAccessibleNotificationService())); + instantiationService.stub(ILayoutService, new TestLayoutService()); configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper)); capabilities = store.add(new TerminalCapabilityStore()); if (!isWindows) { From d2b1eb8a36e1d0fb4f294025fe6ae19b69d41a98 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 16 Oct 2023 11:37:37 -0700 Subject: [PATCH 147/290] testing: finalize TestMessage.contextValue (#195706) Closes #190277 --- extensions/vscode-api-tests/package.json | 1 - .../workbench/api/common/extHost.api.impl.ts | 2 +- src/vs/workbench/api/common/extHostTesting.ts | 8 +--- .../api/common/extHostTypeConverters.ts | 4 +- .../common/extensionsApiProposals.ts | 1 - src/vscode-dts/vscode.d.ts | 31 +++++++++++++ ...code.proposed.testMessageContextValue.d.ts | 45 ------------------- 7 files changed, 35 insertions(+), 57 deletions(-) delete mode 100644 src/vscode-dts/vscode.proposed.testMessageContextValue.d.ts diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index b38c91ce1ce..beb65ffb2e6 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -45,7 +45,6 @@ "tunnels", "testCoverage", "testObserver", - "testMessageContextValue", "textSearchProvider", "timeline", "tokenInformation", diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index cd983bdc650..a58d049f563 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1573,7 +1573,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I TestResultState: extHostTypes.TestResultState, TestRunRequest: extHostTypes.TestRunRequest, TestMessage: extHostTypes.TestMessage, - TestMessage2: extHostTypes.TestMessage, + TestMessage2: extHostTypes.TestMessage, // back compat for Oct 2023 TestTag: extHostTypes.TestTag, TestRunProfileKind: extHostTypes.TestRunProfileKind, TextSearchCompleteMessageType: TextSearchCompleteMessageType, diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index f8282d9b751..65dd87b6e3f 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -29,7 +29,6 @@ import { TestCommandId } from 'vs/workbench/contrib/testing/common/constants'; import { TestId, TestIdPathParts, TestPosition } from 'vs/workbench/contrib/testing/common/testId'; import { InvalidTestItemError } from 'vs/workbench/contrib/testing/common/testItemCollection'; import { AbstractIncrementalTestCollection, CoverageDetails, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, IStartControllerTestsResult, ITestErrorMessage, ITestItem, ITestItemContext, ITestMessageMenuArgs, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp, isStartControllerTests } from 'vs/workbench/contrib/testing/common/testTypes'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import type * as vscode from 'vscode'; interface ControllerInfo { @@ -424,7 +423,6 @@ class TestRunTracker extends Disposable { constructor( private readonly dto: TestRunDto, private readonly proxy: MainThreadTestingShape, - private readonly extension: Readonly, parentToken?: CancellationToken, ) { super(); @@ -476,10 +474,6 @@ class TestRunTracker extends Disposable { ? messages.map(Convert.TestMessage.from) : [Convert.TestMessage.from(messages)]; - if (converted.some(c => c.contextValue !== undefined)) { - checkProposedApiEnabled(this.extension, 'testMessageContextValue'); - } - if (test.uri && test.range) { const defaultLocation: ILocationDto = { range: Convert.Range.from(test.range), uri: test.uri }; for (const message of converted) { @@ -690,7 +684,7 @@ export class TestRunCoordinator { } private getTracker(req: vscode.TestRunRequest, dto: TestRunDto, extension: IRelaxedExtensionDescription, token?: CancellationToken) { - const tracker = new TestRunTracker(dto, this.proxy, extension, token); + const tracker = new TestRunTracker(dto, this.proxy, token); this.tracked.set(req, tracker); Event.once(tracker.onEnd)(() => this.tracked.delete(req)); return tracker; diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index b3ba3306276..9f3cf0a2ffc 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1833,7 +1833,7 @@ export namespace NotebookRendererScript { } export namespace TestMessage { - export function from(message: vscode.TestMessage2): ITestErrorMessage.Serialized { + export function from(message: vscode.TestMessage): ITestErrorMessage.Serialized { return { message: MarkdownString.fromStrict(message.message) || '', type: TestMessageType.Error, @@ -1844,7 +1844,7 @@ export namespace TestMessage { }; } - export function to(item: ITestErrorMessage.Serialized): vscode.TestMessage2 { + export function to(item: ITestErrorMessage.Serialized): vscode.TestMessage { const message = new types.TestMessage(typeof item.message === 'string' ? item.message : MarkdownString.to(item.message)); message.actualOutput = item.actual; message.expectedOutput = item.expected; diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index c5e30e4de43..3f07e089f9e 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -95,7 +95,6 @@ export const allApiProposals = Object.freeze({ terminalQuickFixProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalQuickFixProvider.d.ts', terminalSelection: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalSelection.d.ts', testCoverage: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testCoverage.d.ts', - testMessageContextValue: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testMessageContextValue.d.ts', testObserver: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testObserver.d.ts', textSearchProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textSearchProvider.d.ts', timeline: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.timeline.d.ts', diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index f96413d1ae4..e0f4a73bd44 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -17610,6 +17610,37 @@ declare module 'vscode' { */ location?: Location; + /** + * Context value of the test item. This can be used to contribute message- + * specific actions to the test peek view. The value set here can be found + * in the `testMessage` property of the following `menus` contribution points: + * + * - `testing/message/context` - context menu for the message in the results tree + * - `testing/message/content` - a prominent button overlaying editor content where + * the message is displayed. + * + * For example: + * + * ```json + * "contributes": { + * "menus": { + * "testing/message/content": [ + * { + * "command": "extension.deleteCommentThread", + * "when": "testMessage == canApplyRichDiff" + * } + * ] + * } + * } + * ``` + * + * The command will be called with an object containing: + * - `test`: the {@link TestItem} the message is associated with, *if* it + * is still present in the {@link TestController.items} collection. + * - `message`: the {@link TestMessage} instance. + */ + contextValue?: string; + /** * Creates a new TestMessage that will present as a diff in the editor. * @param message Message to display to the user. diff --git a/src/vscode-dts/vscode.proposed.testMessageContextValue.d.ts b/src/vscode-dts/vscode.proposed.testMessageContextValue.d.ts deleted file mode 100644 index 515a99d0e2b..00000000000 --- a/src/vscode-dts/vscode.proposed.testMessageContextValue.d.ts +++ /dev/null @@ -1,45 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - - // https://github.com/microsoft/vscode/issues/190277 - - export class TestMessage2 extends TestMessage { - - /** - * Context value of the test item. This can be used to contribute message- - * specific actions to the test peek view. The value set here can be found - * in the `testMessage` property of the following `menus` contribution points: - * - * - `testing/message/context` - context menu for the message in the results tree - * - `testing/message/content` - a prominent button overlaying editor content where - * the message is displayed. - * - * For example: - * - * ```json - * "contributes": { - * "menus": { - * "testing/message/content": [ - * { - * "command": "extension.deleteCommentThread", - * "when": "testMessage == canApplyRichDiff" - * } - * ] - * } - * } - * ``` - * - * The command will be called with an object containing: - * - `test`: the {@link TestItem} the message is associated with, *if* it - * is still present in the {@link TestController.items} collection. - * - `message`: the {@link TestMessage} instance. - */ - contextValue?: string; - - // ... - } -} From 58086904b45b21a2b462d4375af8794beec25a01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 11:43:32 -0700 Subject: [PATCH 148/290] Bump word-wrap from 1.2.3 to 1.2.4 (#188223) Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4) --- updated-dependencies: - dependency-name: word-wrap dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4283bf58f52..4a964f90843 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10172,9 +10172,9 @@ windows-foreground-love@0.5.0: integrity sha512-yjBwmKEmQBDk3Z7yg/U9hizGWat8C6Pe4MQWl5bN6mvPU81Bt6HV2k/6mGlK3ETJLW1hCLhYx2wcGh+ykUUCyA== word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + version "1.2.4" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" + integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== workerpool@6.2.1: version "6.2.1" From 325164ee57021d36621c08773f4f62efed40fd16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:03:46 +0200 Subject: [PATCH 149/290] Bump @babel/traverse from 7.18.10 to 7.23.2 (#195719) Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.18.10 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 138 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 114 insertions(+), 24 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4a964f90843..3e41e0812c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -112,6 +112,14 @@ dependencies: "@babel/highlight" "^7.18.6" +"@babel/code-frame@^7.22.13": + version "7.22.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== + dependencies: + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" + "@babel/compat-data@^7.18.8": version "7.18.8" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" @@ -147,6 +155,16 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== + dependencies: + "@babel/types" "^7.23.0" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-compilation-targets@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" @@ -162,20 +180,25 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== -"@babel/helper-function-name@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" - integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== - dependencies: - "@babel/template" "^7.18.6" - "@babel/types" "^7.18.9" +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== -"@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: - "@babel/types" "^7.18.6" + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" "@babel/helper-module-imports@^7.18.6": version "7.18.6" @@ -212,11 +235,23 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.18.10": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + "@babel/helper-validator-identifier@^7.10.4": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" @@ -227,6 +262,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + "@babel/helper-validator-option@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" @@ -259,11 +299,25 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.22.13": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + "@babel/parser@^7.14.7", "@babel/parser@^7.18.10": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.10.tgz#94b5f8522356e69e8277276adf67ed280c90ecc1" integrity sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg== +"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== + "@babel/template@^7.18.10", "@babel/template@^7.18.6": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" @@ -273,19 +327,28 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.10.tgz#37ad97d1cb00efa869b91dd5d1950f8a6cf0cb08" - integrity sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g== +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.10" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.18.10" - "@babel/types" "^7.18.10" + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" debug "^4.1.0" globals "^11.1.0" @@ -298,6 +361,15 @@ "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -443,6 +515,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" @@ -453,6 +530,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + "@jridgewell/trace-mapping@0.3.9": version "0.3.9" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" @@ -461,6 +543,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.17": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/trace-mapping@^0.3.9": version "0.3.14" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" From f2575e5cbb4bb6b3ffdd0b41b0287d420c0ee2f9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 16 Oct 2023 21:09:39 +0200 Subject: [PATCH 150/290] aux window - skip moving window to top after close editor (#195721) --- .../workbench/browser/parts/editor/editor.ts | 6 ++++++ .../browser/parts/editor/editorGroupView.ts | 11 ++++++++-- .../browser/parts/editor/editorPanes.ts | 21 ++++++++++--------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index a2a26d6f7ad..4573e19ba9d 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -236,6 +236,12 @@ export interface IInternalEditorOpenOptions extends IInternalEditorTitleControlO * When set to `true`, pass DOM focus into the tab control. */ readonly focusTabControl?: boolean; + + /** + * When set to `true`, will not attempt to move the window to + * the top that the editor opens in. + */ + readonly preserveWindowOrder?: boolean; } export interface IInternalEditorCloseOptions extends IInternalEditorTitleControlOptions { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index b34b28c1277..9a0b3c4eb67 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1073,7 +1073,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { let openEditorPromise: Promise; if (context.active) { openEditorPromise = (async () => { - const { pane, changed, cancelled, error } = await this.editorPane.openEditor(editor, options, { newInGroup: context.isNew }); + const { pane, changed, cancelled, error } = await this.editorPane.openEditor(editor, options, internalOptions, { newInGroup: context.isNew }); // Return early if the operation was cancelled by another operation if (cancelled) { @@ -1415,7 +1415,14 @@ export class EditorGroupView extends Themable implements IEditorGroupView { ignoreError: internalOptions?.fromError }; - this.doOpenEditor(nextActiveEditor, options); + const internalEditorOpenOptions: IInternalEditorOpenOptions = { + // When closing an editor, we reveal the next one in the group. + // However, this can be a result of moving an editor to another + // window so we explicitly disable window reordering in this case. + preserveWindowOrder: true + }; + + this.doOpenEditor(nextActiveEditor, options, internalEditorOpenOptions); } // Otherwise we are empty, so clear from editor control and send event diff --git a/src/vs/workbench/browser/parts/editor/editorPanes.ts b/src/vs/workbench/browser/parts/editor/editorPanes.ts index 6bc385910a1..4f4c65d6d0b 100644 --- a/src/vs/workbench/browser/parts/editor/editorPanes.ts +++ b/src/vs/workbench/browser/parts/editor/editorPanes.ts @@ -17,7 +17,7 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progress/common/progress'; -import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; +import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS, IInternalEditorOpenOptions } from 'vs/workbench/browser/parts/editor/editor'; import { assertIsDefined } from 'vs/base/common/types'; import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; import { ErrorPlaceholderEditor, IErrorEditorPlaceholderOptions, WorkspaceTrustRequiredPlaceholderEditor } from 'vs/workbench/browser/parts/editor/editorPlaceholder'; @@ -126,7 +126,7 @@ export class EditorPanes extends Disposable { } } - async openEditor(editor: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise { + async openEditor(editor: EditorInput, options: IEditorOptions | undefined, internalOptions: IInternalEditorOpenOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise { try { // Assert the `EditorInputCapabilities.AuxWindowUnsupported` condition @@ -138,12 +138,12 @@ export class EditorPanes extends Disposable { return this.groupView.closeEditor(editor); } }) - ], { forceMessage: true, forceSeverity: Severity.Warning }), editor, options, context); + ], { forceMessage: true, forceSeverity: Severity.Warning }), editor, options, internalOptions, context); } // Open editor normally else { - return await this.doOpenEditor(this.getEditorPaneDescriptor(editor), editor, options, context); + return await this.doOpenEditor(this.getEditorPaneDescriptor(editor), editor, options, internalOptions, context); } } catch (error) { @@ -159,11 +159,11 @@ export class EditorPanes extends Disposable { // For that reason we have place holder editors that can convey a // message with actions the user can click on. - return this.doShowError(error, editor, options, context); + return this.doShowError(error, editor, options, internalOptions, context); } } - private async doShowError(error: Error, editor: EditorInput, options?: IEditorOptions, context?: IEditorOpenContext): Promise { + private async doShowError(error: Error, editor: EditorInput, options: IEditorOptions | undefined, internalOptions: IInternalEditorOpenOptions | undefined, context?: IEditorOpenContext): Promise { // Always log the error to figure out what is going on this.logService.error(error); @@ -186,7 +186,7 @@ export class EditorPanes extends Disposable { } return { - ...(await this.doOpenEditor(ErrorPlaceholderEditor.DESCRIPTOR, editor, editorPlaceholderOptions, context)), + ...(await this.doOpenEditor(ErrorPlaceholderEditor.DESCRIPTOR, editor, editorPlaceholderOptions, internalOptions, context)), error }; } @@ -258,7 +258,7 @@ export class EditorPanes extends Disposable { return errorHandled; } - private async doOpenEditor(descriptor: IEditorPaneDescriptor, editor: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise { + private async doOpenEditor(descriptor: IEditorPaneDescriptor, editor: EditorInput, options: IEditorOptions | undefined, internalOptions: IInternalEditorOpenOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise { // Editor pane const pane = this.doShowEditorPane(descriptor); @@ -270,12 +270,13 @@ export class EditorPanes extends Disposable { const { changed, cancelled } = await this.doSetInput(pane, editor, options, context); // Make sure to pass focus to the pane or otherwise - // make sure that the pane window is visible. + // make sure that the pane window is visible unless + // this has been explicitly disabled. if (!cancelled) { const focus = !options || !options.preserveFocus; if (focus && this.shouldRestoreFocus(activeElement)) { pane.focus(); - } else { + } else if (!internalOptions?.preserveWindowOrder) { const paneWindow = getWindow(pane.getContainer()); if (paneWindow !== getActiveWindow()) { this.hostService.moveTop(paneWindow); From 24c7e890da55dfce97e63335b5e88b9d42e83db1 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Thu, 12 Oct 2023 10:48:12 -0700 Subject: [PATCH 151/290] stop anchoring to focus on scroll-up --- .../notebook/browser/view/notebookCellList.ts | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 1b3ad2962c3..a7c91b38011 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -20,7 +20,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/list/browser/listService'; import { CursorAtBoundary, ICellViewModel, CellEditState, CellFocusMode, ICellOutputViewModel, CellRevealType, CellRevealSyncType, CellRevealRangeType, CursorAtLineBoundary } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl'; -import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, SelectionStateType, NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, SelectionStateType, NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY, NotebookSetting, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange, cellRangesToIndexes, reduceCellRanges, cellRangesEqual } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { NOTEBOOK_CELL_LIST_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; import { clamp } from 'vs/base/common/numbers'; @@ -32,6 +32,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IListViewOptions, IListView } from 'vs/base/browser/ui/list/listView'; import { NotebookCellListView } from 'vs/workbench/contrib/notebook/browser/view/notebookCellListView'; import { NotebookOptions } from 'vs/workbench/contrib/notebook/browser/notebookOptions'; +import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; const enum CellEditorRevealType { Line, @@ -155,7 +156,8 @@ export class NotebookCellList extends WorkbenchList implements ID options: IWorkbenchListOptions, @IListService listService: IListService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IInstantiationService instantiationService: IInstantiationService + @IInstantiationService instantiationService: IInstantiationService, + @INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService, ) { super(listUser, container, delegate, renderers, options, contextKeyService, listService, configurationService, instantiationService); NOTEBOOK_CELL_LIST_FOCUSED.bindTo(this.contextKeyService).set(true); @@ -1171,6 +1173,8 @@ export class NotebookCellList extends WorkbenchList implements ID return elementBottom < this.scrollTop; } + + updateElementHeight2(element: ICellViewModel, size: number, anchorElementIndex: number | null = null): void { const index = this._getViewIndexUpperBound(element); if (index === undefined || index < 0 || index >= this.length) { @@ -1208,7 +1212,7 @@ export class NotebookCellList extends WorkbenchList implements ID const focus = focused.length ? focused[0] : null; // If the cell is growing, we should favor anchoring to the focused cell - if (focus) { + if (focus && !this.stopAnchoring) { const cellEditorIsFocused = this.view.element(focused[0]).focusMode === CellFocusMode.Editor; const anchorFocusedSetting = this.configurationService.getValue(NotebookSetting.anchorToFocusedCell); const growing = this.view.elementHeight(index) < size; @@ -1216,6 +1220,7 @@ export class NotebookCellList extends WorkbenchList implements ID const autoAnchor = allowScrolling && growing && anchorFocusedSetting !== 'off'; if (cellEditorIsFocused || autoAnchor || anchorFocusedSetting === 'on') { + this.watchAchorDuringExecution(index); return this.view.updateElementHeight(index, size, focus); } } @@ -1223,6 +1228,32 @@ export class NotebookCellList extends WorkbenchList implements ID return this.view.updateElementHeight(index, size, null); } + private stopAnchoring = false; + private executionWatcher: IDisposable | undefined; + private scrollWatcher: IDisposable | undefined; + private watchAchorDuringExecution(index: number) { + // anchor while the cell is executing unless the user scrolls up. + const viewCell = this.element(index); + if (!this.executionWatcher && viewCell && viewCell.cellKind === CellKind.Code) { + const executionState = this._notebookExecutionStateService.getCellExecution(viewCell.uri); + + if (executionState && executionState.state === NotebookCellExecutionState.Executing) { + this.executionWatcher = viewCell.onDidStopExecution(() => { + this.executionWatcher?.dispose(); + this.executionWatcher = undefined; + this.scrollWatcher?.dispose(); + this.stopAnchoring = false; + }); + this.scrollWatcher = this.onDidScroll((scrollEvent) => { + if (scrollEvent.scrollTop < scrollEvent.oldScrollTop) { + this.stopAnchoring = true; + this.scrollWatcher?.dispose(); + } + }); + } + } + } + // override override domFocus() { const focused = this.getFocusedElements()[0]; @@ -1383,6 +1414,8 @@ export class NotebookCellList extends WorkbenchList implements ID this._isDisposed = true; this._viewModelStore.dispose(); this._localDisposableStore.dispose(); + this.scrollWatcher?.dispose(); + this.executionWatcher?.dispose(); super.dispose(); // un-ref From f11eba45086449f57315164ddb0996ff8ace2f02 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Thu, 12 Oct 2023 11:56:29 -0700 Subject: [PATCH 152/290] dedicated class for anchoring logic --- .../notebook/browser/view/notebookCellList.ts | 49 +++++-------------- 1 file changed, 11 insertions(+), 38 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index a7c91b38011..cae50bbb206 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -20,7 +20,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/list/browser/listService'; import { CursorAtBoundary, ICellViewModel, CellEditState, CellFocusMode, ICellOutputViewModel, CellRevealType, CellRevealSyncType, CellRevealRangeType, CursorAtLineBoundary } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl'; -import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, SelectionStateType, NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY, NotebookSetting, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, SelectionStateType, NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange, cellRangesToIndexes, reduceCellRanges, cellRangesEqual } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { NOTEBOOK_CELL_LIST_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; import { clamp } from 'vs/base/common/numbers'; @@ -33,6 +33,7 @@ import { IListViewOptions, IListView } from 'vs/base/browser/ui/list/listView'; import { NotebookCellListView } from 'vs/workbench/contrib/notebook/browser/view/notebookCellListView'; import { NotebookOptions } from 'vs/workbench/contrib/notebook/browser/notebookOptions'; import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; +import { NotebookCellAnchor } from 'vs/workbench/contrib/notebook/browser/view/notebookCellAnchor'; const enum CellEditorRevealType { Line, @@ -93,6 +94,7 @@ export class NotebookCellList extends WorkbenchList implements ID private readonly _localDisposableStore = new DisposableStore(); private readonly _viewModelStore = new DisposableStore(); private styleElement?: HTMLStyleElement; + private _notebookCellAnchor: NotebookCellAnchor; private readonly _onDidRemoveOutputs = this._localDisposableStore.add(new Emitter()); readonly onDidRemoveOutputs = this._onDidRemoveOutputs.event; @@ -157,7 +159,7 @@ export class NotebookCellList extends WorkbenchList implements ID @IListService listService: IListService, @IConfigurationService private readonly configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService, - @INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService, + @INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService, ) { super(listUser, container, delegate, renderers, options, contextKeyService, listService, configurationService, instantiationService); NOTEBOOK_CELL_LIST_FOCUSED.bindTo(this.contextKeyService).set(true); @@ -180,6 +182,8 @@ export class NotebookCellList extends WorkbenchList implements ID const cursorSelectionListener = this._localDisposableStore.add(new MutableDisposable()); const textEditorAttachListener = this._localDisposableStore.add(new MutableDisposable()); + this._notebookCellAnchor = new NotebookCellAnchor(notebookExecutionStateService, this.configurationService); + const recomputeContext = (element: CellViewModel) => { switch (element.cursorAtBoundary()) { case CursorAtBoundary.Both: @@ -1212,15 +1216,11 @@ export class NotebookCellList extends WorkbenchList implements ID const focus = focused.length ? focused[0] : null; // If the cell is growing, we should favor anchoring to the focused cell - if (focus && !this.stopAnchoring) { - const cellEditorIsFocused = this.view.element(focused[0]).focusMode === CellFocusMode.Editor; - const anchorFocusedSetting = this.configurationService.getValue(NotebookSetting.anchorToFocusedCell); + if (focus) { + const focusMode = this.element(focused[0]).focusMode; const growing = this.view.elementHeight(index) < size; - const allowScrolling = this.configurationService.getValue(NotebookSetting.scrollToRevealCell) !== 'none'; - const autoAnchor = allowScrolling && growing && anchorFocusedSetting !== 'off'; - - if (cellEditorIsFocused || autoAnchor || anchorFocusedSetting === 'on') { - this.watchAchorDuringExecution(index); + if (this._notebookCellAnchor.shouldAnchor(focusMode, growing)) { + this._notebookCellAnchor.watchAchorDuringExecution(this.element(index), this.onDidScroll); return this.view.updateElementHeight(index, size, focus); } } @@ -1228,32 +1228,6 @@ export class NotebookCellList extends WorkbenchList implements ID return this.view.updateElementHeight(index, size, null); } - private stopAnchoring = false; - private executionWatcher: IDisposable | undefined; - private scrollWatcher: IDisposable | undefined; - private watchAchorDuringExecution(index: number) { - // anchor while the cell is executing unless the user scrolls up. - const viewCell = this.element(index); - if (!this.executionWatcher && viewCell && viewCell.cellKind === CellKind.Code) { - const executionState = this._notebookExecutionStateService.getCellExecution(viewCell.uri); - - if (executionState && executionState.state === NotebookCellExecutionState.Executing) { - this.executionWatcher = viewCell.onDidStopExecution(() => { - this.executionWatcher?.dispose(); - this.executionWatcher = undefined; - this.scrollWatcher?.dispose(); - this.stopAnchoring = false; - }); - this.scrollWatcher = this.onDidScroll((scrollEvent) => { - if (scrollEvent.scrollTop < scrollEvent.oldScrollTop) { - this.stopAnchoring = true; - this.scrollWatcher?.dispose(); - } - }); - } - } - } - // override override domFocus() { const focused = this.getFocusedElements()[0]; @@ -1414,8 +1388,7 @@ export class NotebookCellList extends WorkbenchList implements ID this._isDisposed = true; this._viewModelStore.dispose(); this._localDisposableStore.dispose(); - this.scrollWatcher?.dispose(); - this.executionWatcher?.dispose(); + this._notebookCellAnchor.dispose(); super.dispose(); // un-ref From f5be1c0d4f8cdc1c7603eb36b8441884d6f36982 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Thu, 12 Oct 2023 12:46:03 -0700 Subject: [PATCH 153/290] add missing file --- .../browser/view/notebookCellAnchor.ts | 65 +++++++++++++++++++ .../notebook/browser/view/notebookCellList.ts | 4 +- 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts new file mode 100644 index 00000000000..80d8425edc3 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IDisposable } from 'vs/base/common/lifecycle'; +import { CellFocusMode, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; +import { CellKind, NotebookCellExecutionState, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; +import { Event } from 'vs/base/common/event'; +import { ScrollEvent } from 'vs/base/common/scrollable'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + + +export class NotebookCellAnchor implements IDisposable { + + private stopAnchoring = false; + private executionWatcher: IDisposable | undefined; + private scrollWatcher: IDisposable | undefined; + + constructor( + private readonly notebookExecutionStateService: INotebookExecutionStateService, + private readonly configurationService: IConfigurationService) { + } + + public shouldAnchor(focusMode: CellFocusMode, growing: boolean) { + if (this.stopAnchoring) { + return false; + } + const cellEditorIsFocused = focusMode === CellFocusMode.Editor; + const anchorFocusedSetting = this.configurationService.getValue(NotebookSetting.anchorToFocusedCell); + const allowScrolling = this.configurationService.getValue(NotebookSetting.scrollToRevealCell) !== 'none'; + const autoAnchor = allowScrolling && growing && anchorFocusedSetting !== 'off'; + + return (cellEditorIsFocused || autoAnchor || anchorFocusedSetting === 'on'); + } + + public watchAchorDuringExecution(viewCell: ICellViewModel, scrollEvent: Event) { + // anchor while the cell is executing unless the user scrolls up. + if (!this.executionWatcher && viewCell && viewCell.cellKind === CellKind.Code) { + const executionState = this.notebookExecutionStateService.getCellExecution(viewCell.uri); + + if (executionState && executionState.state === NotebookCellExecutionState.Executing) { + this.executionWatcher = (viewCell as CodeCellViewModel).onDidStopExecution(() => { + this.executionWatcher?.dispose(); + this.executionWatcher = undefined; + this.scrollWatcher?.dispose(); + this.stopAnchoring = false; + }); + this.scrollWatcher = scrollEvent((scrollEvent) => { + if (scrollEvent.scrollTop < scrollEvent.oldScrollTop) { + this.stopAnchoring = true; + this.scrollWatcher?.dispose(); + } + }); + } + } + } + + dispose(): void { + this.executionWatcher?.dispose(); + this.scrollWatcher?.dispose(); + } +} diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index cae50bbb206..54914b41b31 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -157,7 +157,7 @@ export class NotebookCellList extends WorkbenchList implements ID contextKeyService: IContextKeyService, options: IWorkbenchListOptions, @IListService listService: IListService, - @IConfigurationService private readonly configurationService: IConfigurationService, + @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService, @INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService, ) { @@ -182,7 +182,7 @@ export class NotebookCellList extends WorkbenchList implements ID const cursorSelectionListener = this._localDisposableStore.add(new MutableDisposable()); const textEditorAttachListener = this._localDisposableStore.add(new MutableDisposable()); - this._notebookCellAnchor = new NotebookCellAnchor(notebookExecutionStateService, this.configurationService); + this._notebookCellAnchor = new NotebookCellAnchor(notebookExecutionStateService, configurationService); const recomputeContext = (element: CellViewModel) => { switch (element.cursorAtBoundary()) { From 955e9736ef9ec4af3a19389d4818603180224117 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Thu, 12 Oct 2023 15:36:45 -0700 Subject: [PATCH 154/290] unit tests --- .../browser/view/notebookCellAnchor.ts | 28 +++++---- .../notebook/browser/view/notebookCellList.ts | 8 +-- .../test/browser/notebookCellAnchor.test.ts | 60 +++++++++++++++++++ 3 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts index 80d8425edc3..e079847ddc2 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts @@ -21,34 +21,42 @@ export class NotebookCellAnchor implements IDisposable { constructor( private readonly notebookExecutionStateService: INotebookExecutionStateService, - private readonly configurationService: IConfigurationService) { + private readonly configurationService: IConfigurationService, + private readonly scrollEvent: Event) { } - public shouldAnchor(focusMode: CellFocusMode, growing: boolean) { + public shouldAnchor(focusMode: CellFocusMode, growing: boolean, executingCellUri: ICellViewModel) { + if (focusMode === CellFocusMode.Editor) { + return true; + } if (this.stopAnchoring) { return false; } - const cellEditorIsFocused = focusMode === CellFocusMode.Editor; + const anchorFocusedSetting = this.configurationService.getValue(NotebookSetting.anchorToFocusedCell); const allowScrolling = this.configurationService.getValue(NotebookSetting.scrollToRevealCell) !== 'none'; const autoAnchor = allowScrolling && growing && anchorFocusedSetting !== 'off'; - return (cellEditorIsFocused || autoAnchor || anchorFocusedSetting === 'on'); + if (autoAnchor || anchorFocusedSetting === 'on') { + this.watchAchorDuringExecution(executingCellUri); + return true; + } + + return false; } - public watchAchorDuringExecution(viewCell: ICellViewModel, scrollEvent: Event) { + public watchAchorDuringExecution(executingCell: ICellViewModel) { // anchor while the cell is executing unless the user scrolls up. - if (!this.executionWatcher && viewCell && viewCell.cellKind === CellKind.Code) { - const executionState = this.notebookExecutionStateService.getCellExecution(viewCell.uri); - + if (!this.executionWatcher && executingCell.cellKind === CellKind.Code) { + const executionState = this.notebookExecutionStateService.getCellExecution(executingCell.uri); if (executionState && executionState.state === NotebookCellExecutionState.Executing) { - this.executionWatcher = (viewCell as CodeCellViewModel).onDidStopExecution(() => { + this.executionWatcher = (executingCell as CodeCellViewModel).onDidStopExecution(() => { this.executionWatcher?.dispose(); this.executionWatcher = undefined; this.scrollWatcher?.dispose(); this.stopAnchoring = false; }); - this.scrollWatcher = scrollEvent((scrollEvent) => { + this.scrollWatcher = this.scrollEvent((scrollEvent) => { if (scrollEvent.scrollTop < scrollEvent.oldScrollTop) { this.stopAnchoring = true; this.scrollWatcher?.dispose(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 54914b41b31..092a69d9d04 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -182,7 +182,7 @@ export class NotebookCellList extends WorkbenchList implements ID const cursorSelectionListener = this._localDisposableStore.add(new MutableDisposable()); const textEditorAttachListener = this._localDisposableStore.add(new MutableDisposable()); - this._notebookCellAnchor = new NotebookCellAnchor(notebookExecutionStateService, configurationService); + this._notebookCellAnchor = new NotebookCellAnchor(notebookExecutionStateService, configurationService, this.onDidScroll); const recomputeContext = (element: CellViewModel) => { switch (element.cursorAtBoundary()) { @@ -1215,12 +1215,10 @@ export class NotebookCellList extends WorkbenchList implements ID const focused = this.getFocus(); const focus = focused.length ? focused[0] : null; - // If the cell is growing, we should favor anchoring to the focused cell if (focus) { - const focusMode = this.element(focused[0]).focusMode; + // If the cell is growing, we should favor anchoring to the focused cell const growing = this.view.elementHeight(index) < size; - if (this._notebookCellAnchor.shouldAnchor(focusMode, growing)) { - this._notebookCellAnchor.watchAchorDuringExecution(this.element(index), this.onDidScroll); + if (this._notebookCellAnchor.shouldAnchor(this.element(focused[0]).focusMode, growing, this.element(index))) { return this.view.updateElementHeight(index, size, focus); } } diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts new file mode 100644 index 00000000000..2b768682bed --- /dev/null +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { ScrollEvent } from 'vs/base/common/scrollable'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { CellFocusMode } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { NotebookCellAnchor } from 'vs/workbench/contrib/notebook/browser/view/notebookCellAnchor'; +import { Emitter } from 'vs/base/common/event'; +import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; +import { CellKind, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; + + +suite('NotebookCellAnchor', () => { + + const store = ensureNoDisposablesAreLeakedInTestSuite(); + + const config = new TestConfigurationService(); + const scrollEvent = new Emitter(); + const onDidStopExecution = new Emitter(); + const executionService = { + getCellExecution: () => { return { state: NotebookCellExecutionState.Executing }; }, + } as unknown as INotebookExecutionStateService; + const cell = { + cellKind: CellKind.Code, + onDidStopExecution: onDidStopExecution.event + } as unknown as CodeCellViewModel; + + test('Basic anchoring', async function () { + const cellAnchor = store.add(new NotebookCellAnchor(executionService, config, scrollEvent.event)); + + assert(cellAnchor.shouldAnchor(CellFocusMode.Editor, false, cell), 'should anchor if cell editor is focused'); + assert(cellAnchor.shouldAnchor(CellFocusMode.Editor, true, cell), 'should anchor if cell editor is focused'); + + assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'should anchor if cell is growing'); + assert(cellAnchor.shouldAnchor(CellFocusMode.Output, true, cell), 'should anchor if cell is growing'); + + assert(!cellAnchor.shouldAnchor(CellFocusMode.Container, false, cell), 'should not focus if not growing and editor not focused'); + }); + + test('Anchor during execution until user scrolls up', async function () { + const cellAnchor = store.add(new NotebookCellAnchor(executionService, config, scrollEvent.event)); + + assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell)); + + scrollEvent.fire({ oldScrollTop: 100, scrollTop: 150 } as ScrollEvent); + assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'cell should still be anchored after scrolling down'); + + scrollEvent.fire({ oldScrollTop: 150, scrollTop: 100 } as ScrollEvent); + assert(!cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'cell should not be anchored after scrolling up'); + assert(cellAnchor.shouldAnchor(CellFocusMode.Editor, true, cell), 'cell should anchor again if the editor is focused'); + + onDidStopExecution.fire(); + assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'cell should anchor for new execution'); + }); +}); From 0826faeaab76dcc7486651fc475bdfef11257fa2 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Thu, 12 Oct 2023 15:45:48 -0700 Subject: [PATCH 155/290] extra newlines --- .../workbench/contrib/notebook/browser/view/notebookCellList.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 092a69d9d04..899fd08baa0 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -1177,8 +1177,6 @@ export class NotebookCellList extends WorkbenchList implements ID return elementBottom < this.scrollTop; } - - updateElementHeight2(element: ICellViewModel, size: number, anchorElementIndex: number | null = null): void { const index = this._getViewIndexUpperBound(element); if (index === undefined || index < 0 || index >= this.length) { From 475d1c9eb9646d40566bb4996917105d7d61c2b4 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 10:31:50 -0700 Subject: [PATCH 156/290] do not anchor if the focused cell would still be fully in view --- .../browser/view/notebookCellAnchor.ts | 12 +- .../notebook/browser/view/notebookCellList.ts | 5 +- .../test/browser/notebookCellAnchor.test.ts | 110 ++++++++++++++---- 3 files changed, 97 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts index e079847ddc2..a592bd2656b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellAnchor.ts @@ -11,6 +11,8 @@ import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/co import { Event } from 'vs/base/common/event'; import { ScrollEvent } from 'vs/base/common/scrollable'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IListView } from 'vs/base/browser/ui/list/listView'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl'; export class NotebookCellAnchor implements IDisposable { @@ -25,17 +27,21 @@ export class NotebookCellAnchor implements IDisposable { private readonly scrollEvent: Event) { } - public shouldAnchor(focusMode: CellFocusMode, growing: boolean, executingCellUri: ICellViewModel) { - if (focusMode === CellFocusMode.Editor) { + public shouldAnchor(cellListView: IListView, focusedIndex: number, heightDelta: number, executingCellUri: ICellViewModel) { + if (cellListView.element(focusedIndex).focusMode === CellFocusMode.Editor) { return true; } if (this.stopAnchoring) { return false; } + const newFocusBottom = cellListView.elementTop(focusedIndex) + cellListView.elementHeight(focusedIndex) + heightDelta; + const viewBottom = cellListView.renderHeight + cellListView.getScrollTop(); + const focusStillVisible = viewBottom > newFocusBottom; const anchorFocusedSetting = this.configurationService.getValue(NotebookSetting.anchorToFocusedCell); const allowScrolling = this.configurationService.getValue(NotebookSetting.scrollToRevealCell) !== 'none'; - const autoAnchor = allowScrolling && growing && anchorFocusedSetting !== 'off'; + const growing = heightDelta > 0; + const autoAnchor = allowScrolling && growing && !focusStillVisible && anchorFocusedSetting !== 'off'; if (autoAnchor || anchorFocusedSetting === 'on') { this.watchAchorDuringExecution(executingCellUri); diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 899fd08baa0..4fd0e33392e 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -1215,8 +1215,9 @@ export class NotebookCellList extends WorkbenchList implements ID if (focus) { // If the cell is growing, we should favor anchoring to the focused cell - const growing = this.view.elementHeight(index) < size; - if (this._notebookCellAnchor.shouldAnchor(this.element(focused[0]).focusMode, growing, this.element(index))) { + const heightDelta = size - this.view.elementHeight(index); + + if (this._notebookCellAnchor.shouldAnchor(this.view, focus, heightDelta, this.element(index))) { return this.view.updateElementHeight(index, size, focus); } } diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts index 2b768682bed..782c8145df2 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookCellAnchor.test.ts @@ -10,51 +10,111 @@ import { CellFocusMode } from 'vs/workbench/contrib/notebook/browser/notebookBro import { NotebookCellAnchor } from 'vs/workbench/contrib/notebook/browser/view/notebookCellAnchor'; import { Emitter } from 'vs/base/common/event'; import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; -import { CellKind, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, NotebookCellExecutionState, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; +import { IListView } from 'vs/base/browser/ui/list/listView'; suite('NotebookCellAnchor', () => { const store = ensureNoDisposablesAreLeakedInTestSuite(); + let focusedCell: CodeCellViewModel; + let config: TestConfigurationService; + let scrollEvent: Emitter; + let onDidStopExecution: Emitter; + let resizingCell: CodeCellViewModel; - const config = new TestConfigurationService(); - const scrollEvent = new Emitter(); - const onDidStopExecution = new Emitter(); - const executionService = { - getCellExecution: () => { return { state: NotebookCellExecutionState.Executing }; }, - } as unknown as INotebookExecutionStateService; - const cell = { - cellKind: CellKind.Code, - onDidStopExecution: onDidStopExecution.event - } as unknown as CodeCellViewModel; + let cellAnchor: NotebookCellAnchor; + + setup(() => { + config = new TestConfigurationService(); + scrollEvent = new Emitter(); + onDidStopExecution = new Emitter(); + + const executionService = { + getCellExecution: () => { return { state: NotebookCellExecutionState.Executing }; }, + } as unknown as INotebookExecutionStateService; + + resizingCell = { + cellKind: CellKind.Code, + onDidStopExecution: onDidStopExecution.event + } as unknown as CodeCellViewModel; + + focusedCell = { + focusMode: CellFocusMode.Container + } as CodeCellViewModel; + + cellAnchor = store.add(new NotebookCellAnchor(executionService, config, scrollEvent.event)); + }); + + // for the current implementation the code under test only cares about the focused cell + // initial setup with focused cell at the bottom of the view + class MockListView { + focusedCellTop = 100; + focusedCellHeight = 50; + renderTop = 0; + renderHeight = 150; + element(_index: number) { return focusedCell; } + elementTop(_index: number) { return this.focusedCellTop; } + elementHeight(_index: number) { return this.focusedCellHeight; } + getScrollTop() { return this.renderTop; } + } test('Basic anchoring', async function () { - const cellAnchor = store.add(new NotebookCellAnchor(executionService, config, scrollEvent.event)); - assert(cellAnchor.shouldAnchor(CellFocusMode.Editor, false, cell), 'should anchor if cell editor is focused'); - assert(cellAnchor.shouldAnchor(CellFocusMode.Editor, true, cell), 'should anchor if cell editor is focused'); + focusedCell.focusMode = CellFocusMode.Editor; + const listView = new MockListView() as unknown as IListView; + assert(cellAnchor.shouldAnchor(listView, 1, -10, resizingCell), 'should anchor if cell editor is focused'); + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'should anchor if cell editor is focused'); + config.setUserConfiguration(NotebookSetting.scrollToRevealCell, 'none'); + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'should anchor if cell editor is focused'); - assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'should anchor if cell is growing'); - assert(cellAnchor.shouldAnchor(CellFocusMode.Output, true, cell), 'should anchor if cell is growing'); + config.setUserConfiguration(NotebookSetting.scrollToRevealCell, 'fullCell'); + focusedCell.focusMode = CellFocusMode.Container; + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'should anchor if cell is growing'); + focusedCell.focusMode = CellFocusMode.Output; + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'should anchor if cell is growing'); - assert(!cellAnchor.shouldAnchor(CellFocusMode.Container, false, cell), 'should not focus if not growing and editor not focused'); + assert(!cellAnchor.shouldAnchor(listView, 1, -10, resizingCell), 'should not anchor if not growing and editor not focused'); + + config.setUserConfiguration(NotebookSetting.scrollToRevealCell, 'none'); + assert(!cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'should not anchor if scroll on execute is disabled'); }); test('Anchor during execution until user scrolls up', async function () { - const cellAnchor = store.add(new NotebookCellAnchor(executionService, config, scrollEvent.event)); + const listView = new MockListView() as unknown as IListView; + const scrollDown = { oldScrollTop: 100, scrollTop: 150 } as ScrollEvent; + const scrollUp = { oldScrollTop: 200, scrollTop: 150 } as ScrollEvent; - assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell)); + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell)); - scrollEvent.fire({ oldScrollTop: 100, scrollTop: 150 } as ScrollEvent); - assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'cell should still be anchored after scrolling down'); + scrollEvent.fire(scrollDown); + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'cell should still be anchored after scrolling down'); - scrollEvent.fire({ oldScrollTop: 150, scrollTop: 100 } as ScrollEvent); - assert(!cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'cell should not be anchored after scrolling up'); - assert(cellAnchor.shouldAnchor(CellFocusMode.Editor, true, cell), 'cell should anchor again if the editor is focused'); + scrollEvent.fire(scrollUp); + assert(!cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'cell should not be anchored after scrolling up'); + focusedCell.focusMode = CellFocusMode.Editor; + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'cell should anchor again if the editor is focused'); + focusedCell.focusMode = CellFocusMode.Container; onDidStopExecution.fire(); - assert(cellAnchor.shouldAnchor(CellFocusMode.Container, true, cell), 'cell should anchor for new execution'); + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'cell should anchor for new execution'); + }); + + test('Only anchor during when the focused cell will be pushed out of view', async function () { + const mockListView = new MockListView(); + mockListView.focusedCellTop = 50; + const listView = mockListView as unknown as IListView; + + assert(!cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'should not anchor if focused cell will still be fully visible after resize'); + focusedCell.focusMode = CellFocusMode.Editor; + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'cell should always anchor if the editor is focused'); + + // fully visible focused cell would be pushed partially out of view + assert(cellAnchor.shouldAnchor(listView, 1, 150, resizingCell), 'cell should be anchored if focused cell will be pushed out of view'); + mockListView.focusedCellTop = 110; + // partially visible focused cell would be pushed further out of view + assert(cellAnchor.shouldAnchor(listView, 1, 10, resizingCell), 'cell should be anchored if focused cell will be pushed out of view'); }); }); From 9abd7cbbc7d62108c2bcb540c43e8375d9a27dea Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 15:47:53 -0700 Subject: [PATCH 157/290] fix test --- .../contrib/notebook/test/browser/notebookCellList.test.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookCellList.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookCellList.test.ts index 2573533424e..13804ee83f7 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookCellList.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookCellList.test.ts @@ -242,7 +242,12 @@ suite('NotebookCellList', () => { cellList.updateElementHeight2(viewModel.cellAt(0)!, 100); assert.deepStrictEqual(cellList.scrollHeight, 400); - // the first cell grows, but we anchor to the focused cell, so the notebook will scroll down + // the first cell grows, and the focused cell will remain fully visible, so we don't scroll + assert.deepStrictEqual(cellList.scrollTop, 5); + assert.deepStrictEqual(cellList.getViewScrollBottom(), 215); + + cellList.updateElementHeight2(viewModel.cellAt(0)!, 150); + // the first cell grows, and the focused cell will be pushed out of view, so we scroll down assert.deepStrictEqual(cellList.scrollTop, 55); assert.deepStrictEqual(cellList.getViewScrollBottom(), 265); From 482d5ba393c2014c40535ec1b39ec743af3ffecc Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Mon, 16 Oct 2023 13:58:44 -0700 Subject: [PATCH 158/290] Add some integration tests for github-auth (#195729) --- .vscode-test.js | 5 + extensions/github-authentication/package.json | 1 + extensions/github-authentication/src/flows.ts | 2 +- .../src/test/flows.test.ts | 196 ++++++++++++++++++ .../src/test/node/authServer.test.ts | 65 ++++++ extensions/github-authentication/yarn.lock | 5 + scripts/test-integration.bat | 5 + scripts/test-integration.sh | 5 + 8 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 extensions/github-authentication/src/test/flows.test.ts create mode 100644 extensions/github-authentication/src/test/node/authServer.test.ts diff --git a/.vscode-test.js b/.vscode-test.js index e09b8443b7f..6846ca522f6 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -31,6 +31,11 @@ const extensions = [ workspaceFolder: path.join(os.tmpdir(), `nbout-${Math.floor(Math.random() * 100000)}`), mocha: { timeout: 60_000 } }, + { + label: 'github-authentication', + workspaceFolder: path.join(os.tmpdir(), `msft-auth-${Math.floor(Math.random() * 100000)}`), + mocha: { timeout: 60_000 } + } ]; diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index c1e13b86e2a..a57586ec9f0 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -64,6 +64,7 @@ "vscode-tas-client": "^0.1.47" }, "devDependencies": { + "@types/mocha": "^9.1.1", "@types/node": "18.x", "@types/node-fetch": "^2.5.7" }, diff --git a/extensions/github-authentication/src/flows.ts b/extensions/github-authentication/src/flows.ts index 1e988d92d30..3641ffb3a36 100644 --- a/extensions/github-authentication/src/flows.ts +++ b/extensions/github-authentication/src/flows.ts @@ -53,7 +53,7 @@ export const enum ExtensionHost { Local } -interface IFlowQuery { +export interface IFlowQuery { target: GitHubTarget; extensionHost: ExtensionHost; isSupportedClient: boolean; diff --git a/extensions/github-authentication/src/test/flows.test.ts b/extensions/github-authentication/src/test/flows.test.ts new file mode 100644 index 00000000000..7f4963f4bd5 --- /dev/null +++ b/extensions/github-authentication/src/test/flows.test.ts @@ -0,0 +1,196 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ExtensionHost, GitHubTarget, IFlowQuery, getFlows } from '../flows'; +import { Config } from '../config'; + +const enum Flows { + UrlHandlerFlow = 'url handler', + LocalServerFlow = 'local server', + DeviceCodeFlow = 'device code', + PatFlow = 'personal access token' +} + +suite('getFlows', () => { + let lastClientSecret: string | undefined = undefined; + suiteSetup(() => { + lastClientSecret = Config.gitHubClientSecret; + Config.gitHubClientSecret = 'asdf'; + }); + + suiteTeardown(() => { + Config.gitHubClientSecret = lastClientSecret; + }); + + const testCases: Array<{ label: string; query: IFlowQuery; expectedFlows: Flows[] }> = [ + { + label: 'VS Code Desktop. Local filesystem. GitHub.com', + query: { + extensionHost: ExtensionHost.Local, + isSupportedClient: true, + target: GitHubTarget.DotCom + }, + expectedFlows: [ + Flows.UrlHandlerFlow, + Flows.LocalServerFlow, + Flows.DeviceCodeFlow + ] + }, + { + label: 'VS Code Desktop. Local filesystem. GitHub Hosted Enterprise', + query: { + extensionHost: ExtensionHost.Local, + isSupportedClient: true, + target: GitHubTarget.HostedEnterprise + }, + expectedFlows: [ + Flows.UrlHandlerFlow, + Flows.LocalServerFlow, + Flows.DeviceCodeFlow, + Flows.PatFlow + ] + }, + { + label: 'VS Code Desktop. Local filesystem. GitHub Enterprise Server', + query: { + extensionHost: ExtensionHost.Local, + isSupportedClient: true, + target: GitHubTarget.Enterprise + }, + expectedFlows: [ + Flows.DeviceCodeFlow, + Flows.PatFlow + ] + }, + { + label: 'vscode.dev. serverful. GitHub.com', + query: { + extensionHost: ExtensionHost.Remote, + isSupportedClient: true, + target: GitHubTarget.DotCom + }, + expectedFlows: [ + Flows.UrlHandlerFlow, + Flows.DeviceCodeFlow + ] + }, + { + label: 'vscode.dev. serverful. GitHub Hosted Enterprise', + query: { + extensionHost: ExtensionHost.Remote, + isSupportedClient: true, + target: GitHubTarget.HostedEnterprise + }, + expectedFlows: [ + Flows.UrlHandlerFlow, + Flows.DeviceCodeFlow, + Flows.PatFlow + ] + }, + { + label: 'vscode.dev. serverful. GitHub Enterprise', + query: { + extensionHost: ExtensionHost.Remote, + isSupportedClient: true, + target: GitHubTarget.Enterprise + }, + expectedFlows: [ + Flows.DeviceCodeFlow, + Flows.PatFlow + ] + }, + { + label: 'vscode.dev. serverless. GitHub.com', + query: { + extensionHost: ExtensionHost.WebWorker, + isSupportedClient: true, + target: GitHubTarget.DotCom + }, + expectedFlows: [ + Flows.UrlHandlerFlow + ] + }, + { + label: 'vscode.dev. serverless. GitHub Hosted Enterprise', + query: { + extensionHost: ExtensionHost.WebWorker, + isSupportedClient: true, + target: GitHubTarget.HostedEnterprise + }, + expectedFlows: [ + Flows.UrlHandlerFlow, + Flows.PatFlow + ] + }, + { + label: 'vscode.dev. serverless. GitHub Enterprise Server', + query: { + extensionHost: ExtensionHost.WebWorker, + isSupportedClient: true, + target: GitHubTarget.Enterprise + }, + expectedFlows: [ + Flows.PatFlow + ] + }, + { + label: 'Code - OSS. Local filesystem. GitHub.com', + query: { + extensionHost: ExtensionHost.Local, + isSupportedClient: false, + target: GitHubTarget.DotCom + }, + expectedFlows: [ + Flows.LocalServerFlow, + Flows.DeviceCodeFlow, + Flows.PatFlow + ] + }, + { + label: 'Code - OSS. Local filesystem. GitHub Hosted Enterprise', + query: { + extensionHost: ExtensionHost.Local, + isSupportedClient: false, + target: GitHubTarget.HostedEnterprise + }, + expectedFlows: [ + Flows.LocalServerFlow, + Flows.DeviceCodeFlow, + Flows.PatFlow + ] + }, + { + label: 'Code - OSS. Local filesystem. GitHub Enterprise Server', + query: { + extensionHost: ExtensionHost.Local, + isSupportedClient: false, + target: GitHubTarget.Enterprise + }, + expectedFlows: [ + Flows.DeviceCodeFlow, + Flows.PatFlow + ] + }, + ]; + + for (const testCase of testCases) { + test(`gives the correct flows - ${testCase.label}`, () => { + const flows = getFlows(testCase.query); + + assert.strictEqual( + flows.length, + testCase.expectedFlows.length, + `Unexpected number of flows: ${flows.map(f => f.label).join(',')}` + ); + + for (let i = 0; i < flows.length; i++) { + const flow = flows[i]; + + assert.strictEqual(flow.label, testCase.expectedFlows[i]); + } + }); + } +}); diff --git a/extensions/github-authentication/src/test/node/authServer.test.ts b/extensions/github-authentication/src/test/node/authServer.test.ts new file mode 100644 index 00000000000..6de8da61fda --- /dev/null +++ b/extensions/github-authentication/src/test/node/authServer.test.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { LoopbackAuthServer } from '../../node/authServer'; + +suite('LoopbackAuthServer', () => { + let server: LoopbackAuthServer; + let port: number; + + setup(async () => { + server = new LoopbackAuthServer(__dirname, 'http://localhost:8080'); + port = await server.start(); + }); + + teardown(async () => { + await server.stop(); + }); + + test('should redirect to starting redirect on /signin', async () => { + const response = await fetch(`http://localhost:${port}/signin?nonce=${server.nonce}`, { + redirect: 'manual' + }); + // Redirect + assert.strictEqual(response.status, 302); + + // Check location + const location = response.headers.get('location'); + assert.ok(location); + const locationUrl = new URL(location); + assert.strictEqual(locationUrl.origin, 'http://localhost:8080'); + + // Check state + const state = locationUrl.searchParams.get('state'); + assert.ok(state); + const stateLocation = new URL(state); + assert.strictEqual(stateLocation.origin, `http://127.0.0.1:${port}`); + assert.strictEqual(stateLocation.pathname, '/callback'); + assert.strictEqual(stateLocation.searchParams.get('nonce'), server.nonce); + }); + + test('should return 400 on /callback with missing parameters', async () => { + const response = await fetch(`http://localhost:${port}/callback`); + assert.strictEqual(response.status, 400); + }); + + test('should resolve with code and state on /callback with valid parameters', async () => { + server.state = 'valid-state'; + const response = await fetch( + `http://localhost:${port}/callback?code=valid-code&state=${server.state}&nonce=${server.nonce}`, + { redirect: 'manual' } + ); + assert.strictEqual(response.status, 302); + assert.strictEqual(response.headers.get('location'), '/'); + await Promise.race([ + server.waitForOAuthResponse().then(result => { + assert.strictEqual(result.code, 'valid-code'); + assert.strictEqual(result.state, server.state); + }), + new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000)) + ]); + }); +}); diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index e8c7997aa38..1a2b9b273f1 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -259,6 +259,11 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== +"@types/mocha@^9.1.1": + version "9.1.1" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" + integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== + "@types/node-fetch@^2.5.7": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 1834f26162d..4786c7f7a6d 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -92,6 +92,11 @@ mkdir %CFWORKSPACE% call "%INTEGRATION_TEST_ELECTRON_PATH%" %CFWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\configuration-editing --extensionTestsPath=%~dp0\..\extensions\configuration-editing\out\test %API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% +echo. +echo ### GitHub Authentication tests +call yarn test-extension -l github-authentication +if %errorlevel% neq 0 exit /b %errorlevel% + :: Tests standalone (CommonJS) echo. diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 6a7a1fe4a75..ab32efc798f 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -112,6 +112,11 @@ echo "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/configuration-editing --extensionTestsPath=$ROOT/extensions/configuration-editing/out/test $API_TESTS_EXTRA_ARGS kill_app +echo +echo "### GitHub Authentication tests" +echo +yarn test-extension -l github-authentication +kill_app # Tests standalone (CommonJS) From 04ca5de66f382fe3d3ab26d8941f052065fe0314 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 14:44:32 -0700 Subject: [PATCH 159/290] fix #195411 --- .../contrib/accessibility/browser/accessibleViewActions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts index 0721b08a570..2b16232434f 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts @@ -212,7 +212,6 @@ class AccessibleViewAcceptInlineCompletionAction extends Action2 { return; } await model.accept(editor); - alert('Accepted'); model.stop(); editor.focus(); } From 46e73c7837a5c27930d87da1d84f6783f7ebdc9f Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 15:15:18 -0700 Subject: [PATCH 160/290] fix #195582 --- .../accessibility/browser/accessibleView.ts | 4 +- .../contrib/terminal/browser/terminal.ts | 6 + .../terminal/browser/terminalInstance.ts | 166 +++++++++--------- .../terminalAccessibleBufferProvider.ts | 14 +- 4 files changed, 102 insertions(+), 88 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 8a7d668a8a8..b1036069275 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -57,7 +57,7 @@ export interface IAccessibleContentProvider { actions?: IAction[]; provideContent(): string; onClose(): void; - onKeyUp?(e: IKeyboardEvent): void; + onKeyDown?(e: IKeyboardEvent): void; previous?(): void; next?(): void; /** @@ -507,7 +507,6 @@ export class AccessibleView extends Disposable { setTimeout(() => provider.onClose(), 100); }; const disposableStore = new DisposableStore(); - disposableStore.add(this._editorWidget.onKeyUp((e) => provider.onKeyUp?.(e))); disposableStore.add(this._editorWidget.onKeyDown((e) => { if (e.keyCode === KeyCode.Escape) { handleEscape(e); @@ -518,6 +517,7 @@ export class AccessibleView extends Disposable { e.preventDefault(); e.stopPropagation(); } + provider.onKeyDown?.(e); })); disposableStore.add(addDisposableListener(this._toolbar.getElement(), EventType.KEY_DOWN, (e: KeyboardEvent) => { const keyboardEvent = new StandardKeyboardEvent(e); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index ea1b9088874..d7bc90e1e8b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -993,6 +993,12 @@ export interface ITerminalInstance { * Gets a terminal contribution by its ID. */ getContribution(id: string): T | null; + + /** + * Whether the event should be handled by xterm.js or the workbench. + * @param event the event to process + */ + shouldProcessKeyEvent(event: KeyboardEvent): boolean; } export const enum XtermTerminalConstants { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index a7c08bc63d8..339a9e4ce5c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -908,92 +908,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._setAriaLabel(xterm.raw, this._instanceId, this._title); - xterm.raw.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => { - // Disable all input if the terminal is exiting - if (this._isExiting) { - return false; - } + xterm.raw.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => this.shouldProcessKeyEvent(event)); - const standardKeyboardEvent = new StandardKeyboardEvent(event); - const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); - - // Respect chords if the allowChords setting is set and it's not Escape. Escape is - // handled specially for Zen Mode's Escape, Escape chord, plus it's important in - // terminals generally - const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded && this._configHelper.config.allowChords && event.key !== 'Escape'; - if (this._keybindingService.inChordMode || isValidChord) { - event.preventDefault(); - return false; - } - - const SHOW_TERMINAL_CONFIG_PROMPT_KEY = 'terminal.integrated.showTerminalConfigPrompt'; - const EXCLUDED_KEYS = ['RightArrow', 'LeftArrow', 'UpArrow', 'DownArrow', 'Space', 'Meta', 'Control', 'Shift', 'Alt', '', 'Delete', 'Backspace', 'Tab']; - - // only keep track of input if prompt hasn't already been shown - if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && - !EXCLUDED_KEYS.includes(event.key) && - !event.ctrlKey && - !event.shiftKey && - !event.altKey) { - this._hasHadInput = true; - } - - // for keyboard events that resolve to commands described - // within commandsToSkipShell, either alert or skip processing by xterm.js - if (resolveResult.kind === ResultKind.KbFound && resolveResult.commandId && this._skipTerminalCommands.some(k => k === resolveResult.commandId) && !this._configHelper.config.sendKeybindingsToShell) { - // don't alert when terminal is opened or closed - if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && - this._hasHadInput && - !TERMINAL_CREATION_COMMANDS.includes(resolveResult.commandId)) { - this._notificationService.prompt( - Severity.Info, - nls.localize('keybindingHandling', "Some keybindings don't go to the terminal by default and are handled by {0} instead.", this._productService.nameLong), - [ - { - label: nls.localize('configureTerminalSettings', "Configure Terminal Settings"), - run: () => { - this._preferencesService.openSettings({ jsonEditor: false, query: `@id:${TerminalSettingId.CommandsToSkipShell},${TerminalSettingId.SendKeybindingsToShell},${TerminalSettingId.AllowChords}` }); - } - } as IPromptChoice - ] - ); - this._storageService.store(SHOW_TERMINAL_CONFIG_PROMPT_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); - } - event.preventDefault(); - return false; - } - - // Skip processing by xterm.js of keyboard events that match menu bar mnemonics - if (this._configHelper.config.allowMnemonics && !isMacintosh && event.altKey) { - return false; - } - - // If tab focus mode is on, tab is not passed to the terminal - if (TabFocus.getTabFocusMode() && event.key === 'Tab') { - return false; - } - - // Prevent default when shift+tab is being sent to the terminal to avoid it bubbling up - // and changing focus https://github.com/microsoft/vscode/issues/188329 - if (event.key === 'Tab' && event.shiftKey) { - event.preventDefault(); - return true; - } - - // Always have alt+F4 skip the terminal on Windows and allow it to be handled by the - // system - if (isWindows && event.altKey && event.key === 'F4' && !event.ctrlKey) { - return false; - } - - // Fallback to force ctrl+v to paste on browsers that do not support - // navigator.clipboard.readText - if (!BrowserFeatures.clipboard.readText && event.key === 'v' && event.ctrlKey) { - return false; - } - - return true; - }); this._register(dom.addDisposableListener(xterm.raw.element, 'mousedown', () => { // We need to listen to the mouseup event on the document since the user may release // the mouse button anywhere outside of _xterm.element. @@ -1053,6 +969,86 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } + shouldProcessKeyEvent(event: KeyboardEvent): boolean { + // Disable all input if the terminal is exiting + if (this._isExiting) { + return false; + } + + const standardKeyboardEvent = new StandardKeyboardEvent(event); + const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); + + // Respect chords if the allowChords setting is set and it's not Escape. Escape is + // handled specially for Zen Mode's Escape, Escape chord, plus it's important in + // terminals generally + const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded && this._configHelper.config.allowChords && event.key !== 'Escape'; + if (this._keybindingService.inChordMode || isValidChord) { + event.preventDefault(); + return false; + } + + const SHOW_TERMINAL_CONFIG_PROMPT_KEY = 'terminal.integrated.showTerminalConfigPrompt'; + const EXCLUDED_KEYS = ['RightArrow', 'LeftArrow', 'UpArrow', 'DownArrow', 'Space', 'Meta', 'Control', 'Shift', 'Alt', '', 'Delete', 'Backspace', 'Tab']; + + // only keep track of input if prompt hasn't already been shown + if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && + !EXCLUDED_KEYS.includes(event.key) && + !event.ctrlKey && + !event.shiftKey && + !event.altKey) { + this._hasHadInput = true; + } + + // for keyboard events that resolve to commands described + // within commandsToSkipShell, either alert or skip processing by xterm.js + if (resolveResult.kind === ResultKind.KbFound && resolveResult.commandId && this._skipTerminalCommands.some(k => k === resolveResult.commandId) && !this._configHelper.config.sendKeybindingsToShell) { + // don't alert when terminal is opened or closed + if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && + this._hasHadInput && + !TERMINAL_CREATION_COMMANDS.includes(resolveResult.commandId)) { + this._notificationService.prompt( + Severity.Info, + nls.localize('keybindingHandling', "Some keybindings don't go to the terminal by default and are handled by {0} instead.", this._productService.nameLong), + [ + { + label: nls.localize('configureTerminalSettings', "Configure Terminal Settings"), + run: () => { + this._preferencesService.openSettings({ jsonEditor: false, query: `@id:${TerminalSettingId.CommandsToSkipShell},${TerminalSettingId.SendKeybindingsToShell},${TerminalSettingId.AllowChords}` }); + } + } as IPromptChoice + ] + ); + this._storageService.store(SHOW_TERMINAL_CONFIG_PROMPT_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); + } + event.preventDefault(); + return false; + } + + // Skip processing by xterm.js of keyboard events that match menu bar mnemonics + if (this._configHelper.config.allowMnemonics && !isMacintosh && event.altKey) { + return false; + } + + // If tab focus mode is on, tab is not passed to the terminal + if (TabFocus.getTabFocusMode() && event.key === 'Tab') { + return false; + } + + // Always have alt+F4 skip the terminal on Windows and allow it to be handled by the + // system + if (isWindows && event.altKey && event.key === 'F4' && !event.ctrlKey) { + return false; + } + + // Fallback to force ctrl+v to paste on browsers that do not support + // navigator.clipboard.readText + if (!BrowserFeatures.clipboard.readText && event.key === 'v' && event.ctrlKey) { + return false; + } + + return true; + } + resetFocusContextKey(): void { this._terminalFocusContextKey.reset(); this._terminalShellIntegrationEnabledContextKey.reset(); diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts index 057c0ab530f..ac195f84cd6 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/model'; @@ -24,7 +25,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements readonly onDidRequestClearLastProvider = this._onDidRequestClearProvider.event; private _focusedInstance: ITerminalInstance | undefined; constructor( - private readonly _instance: Pick, + private readonly _instance: Pick, private _bufferTracker: BufferContentTracker, customHelp: () => string, @IModelService _modelService: IModelService, @@ -50,6 +51,13 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements })); } + onKeyDown(e: IKeyboardEvent): void { + if (!this._instance.shouldProcessKeyEvent(e.browserEvent) || !isSingleLetterKey(e.browserEvent)) { + return; + } + this._instance.focus(); + } + onClose() { this._instance.focus(); } @@ -115,3 +123,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements } } export interface ICommandWithEditorLine { command: ITerminalCommand | ICurrentPartialCommand; lineNumber: number } + +function isSingleLetterKey(event: KeyboardEvent): boolean { + return event.key.length === 1 && !event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey; +} From 4662a2b026d1b2fde5bc08b31ff0d0cf6d32f017 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Oct 2023 15:20:09 -0700 Subject: [PATCH 161/290] rm something --- .../contrib/accessibility/browser/accessibleViewActions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts index 2b16232434f..d931e39bf79 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleViewActions.ts @@ -15,7 +15,6 @@ import { AccessibleViewProviderId, accessibilityHelpIsShown, accessibleViewCurre import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { InlineCompletionsController } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController'; -import { alert } from 'vs/base/browser/ui/aria/aria'; const accessibleViewMenu = { id: MenuId.AccessibleView, From 9f46428a17e822ad22beab394eb914f9cffb2be3 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 17 Oct 2023 00:55:18 +0200 Subject: [PATCH 162/290] Support code block part in inline chat (#195725) * extract CodeBlockPart * separate css * layout updating * Use code block actions in inline chat * improve css * polish * fix test mocks --- .../browser/actions/chatCodeblockActions.ts | 175 ++++++----- .../contrib/chat/browser/chatListRenderer.ts | 257 +--------------- .../contrib/chat/browser/chatOptions.ts | 2 +- .../contrib/chat/browser/codeBlockPart.css | 55 ++++ .../contrib/chat/browser/codeBlockPart.ts | 277 ++++++++++++++++++ .../contrib/chat/browser/media/chat.css | 59 +--- .../contrib/inlineChat/browser/inlineChat.css | 4 + .../browser/inlineChatController.ts | 6 +- .../inlineChat/browser/inlineChatWidget.ts | 40 ++- .../test/browser/inlineChatController.test.ts | 11 + 10 files changed, 496 insertions(+), 390 deletions(-) create mode 100644 src/vs/workbench/contrib/chat/browser/codeBlockPart.css create mode 100644 src/vs/workbench/contrib/chat/browser/codeBlockPart.ts diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index e96cba918ef..c29335d7607 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -26,9 +26,11 @@ import { TerminalLocation } from 'vs/platform/terminal/common/terminal'; import { IUntitledTextResourceEditorInput } from 'vs/workbench/common/editor'; import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions'; import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; +import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart'; import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; -import { IChatCopyAction, IChatService, IChatUserActionEvent, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatCopyAction, IChatService, IChatUserActionEvent, IDocumentContext, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; +import { CTX_INLINE_CHAT_VISIBLE } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellKind, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -36,17 +38,22 @@ import { ITerminalEditorService, ITerminalGroupService, ITerminalService } from import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -export interface IChatCodeBlockActionContext { - code: string; - languageId: string; - codeBlockIndex: number; +export interface IChatCodeBlockActionContext extends ICodeBlockActionContext { element: IChatResponseViewModel; } -export function isCodeBlockActionContext(thing: unknown): thing is IChatCodeBlockActionContext { +export function isCodeBlockActionContext(thing: unknown): thing is ICodeBlockActionContext { return typeof thing === 'object' && thing !== null && 'code' in thing && 'element' in thing; } +function isResponseFiltered(context: ICodeBlockActionContext) { + return isResponseVM(context.element) && context.element.errorDetails?.responseIsFiltered; +} + +function getUsedDocuments(context: ICodeBlockActionContext): IDocumentContext[] | undefined { + return isResponseVM(context.element) ? context.element.response.usedContext?.documents : undefined; +} + abstract class ChatCodeBlockAction extends Action2 { run(accessor: ServicesAccessor, ...args: any[]) { let context = args[0]; @@ -66,7 +73,7 @@ abstract class ChatCodeBlockAction extends Action2 { return this.runWithContext(accessor, context); } - abstract runWithContext(accessor: ServicesAccessor, context: IChatCodeBlockActionContext): any; + abstract runWithContext(accessor: ServicesAccessor, context: ICodeBlockActionContext): any; } export function registerChatCodeBlockActions() { @@ -90,33 +97,30 @@ export function registerChatCodeBlockActions() { run(accessor: ServicesAccessor, ...args: any[]) { const context = args[0]; - if (!isCodeBlockActionContext(context)) { - return; - } - - if (context.element.errorDetails?.responseIsFiltered) { - // When run from command palette + if (!isCodeBlockActionContext(context) || isResponseFiltered(context)) { return; } const clipboardService = accessor.get(IClipboardService); clipboardService.writeText(context.code); - const chatService = accessor.get(IChatService); - chatService.notifyUserAction({ - providerId: context.element.providerId, - agentId: context.element.agent?.id, - sessionId: context.element.sessionId, - action: { - kind: 'copy', - responseId: context.element.providerResponseId, - codeBlockIndex: context.codeBlockIndex, - copyType: InteractiveSessionCopyKind.Toolbar, - copiedCharacters: context.code.length, - totalCharacters: context.code.length, - copiedText: context.code, - } - }); + if (isResponseVM(context.element)) { + const chatService = accessor.get(IChatService); + chatService.notifyUserAction({ + providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, + action: { + kind: 'copy', + responseId: context.element.providerResponseId, + codeBlockIndex: context.codeBlockIndex, + copyType: InteractiveSessionCopyKind.Toolbar, + copiedCharacters: context.code.length, + totalCharacters: context.code.length, + copiedText: context.code, + } + }); + } } }); @@ -186,9 +190,10 @@ export function registerChatCodeBlockActions() { menu: { id: MenuId.ChatCodeBlock, group: 'navigation', + when: CONTEXT_IN_CHAT_SESSION, }, keybinding: { - when: CONTEXT_ACCESSIBILITY_MODE_ENABLED, + when: ContextKeyExpr.and(CONTEXT_IN_CHAT_SESSION, CONTEXT_ACCESSIBILITY_MODE_ENABLED), primary: KeyMod.CtrlCmd | KeyCode.Enter, mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, weight: KeybindingWeight.WorkbenchContrib @@ -196,11 +201,11 @@ export function registerChatCodeBlockActions() { }); } - override async runWithContext(accessor: ServicesAccessor, context: IChatCodeBlockActionContext) { + override async runWithContext(accessor: ServicesAccessor, context: ICodeBlockActionContext) { const editorService = accessor.get(IEditorService); const textFileService = accessor.get(ITextFileService); - if (context.element.errorDetails?.responseIsFiltered) { + if (isResponseFiltered(context)) { // When run from command palette return; } @@ -232,7 +237,7 @@ export function registerChatCodeBlockActions() { await this.handleTextEditor(accessor, activeEditorControl, activeModel, context); } - private async handleNotebookEditor(accessor: ServicesAccessor, notebookEditor: INotebookEditor, context: IChatCodeBlockActionContext) { + private async handleNotebookEditor(accessor: ServicesAccessor, notebookEditor: INotebookEditor, context: ICodeBlockActionContext) { if (!notebookEditor.hasModel()) { return; } @@ -257,8 +262,8 @@ export function registerChatCodeBlockActions() { this.notifyUserAction(accessor, context); } - private async handleTextEditor(accessor: ServicesAccessor, codeEditor: ICodeEditor, activeModel: ITextModel, chatCodeBlockActionContext: IChatCodeBlockActionContext) { - this.notifyUserAction(accessor, chatCodeBlockActionContext); + private async handleTextEditor(accessor: ServicesAccessor, codeEditor: ICodeEditor, activeModel: ITextModel, codeBlockActionContext: ICodeBlockActionContext) { + this.notifyUserAction(accessor, codeBlockActionContext); const bulkEditService = accessor.get(IBulkEditService); const codeEditorService = accessor.get(ICodeEditorService); @@ -292,7 +297,7 @@ export function registerChatCodeBlockActions() { } } - const usedDocuments = chatCodeBlockActionContext.element.response.usedContext?.documents; + const usedDocuments = getUsedDocuments(codeBlockActionContext); if (usedDocuments) { docRefs.push(usedDocuments); } @@ -301,7 +306,7 @@ export function registerChatCodeBlockActions() { mappedEdits = await mostRelevantProvider.provideMappedEdits( activeModel, - [chatCodeBlockActionContext.code], + [codeBlockActionContext.code], { documents: docRefs }, cancellationTokenSource.token); } @@ -313,26 +318,28 @@ export function registerChatCodeBlockActions() { await bulkEditService.apply([ new ResourceTextEdit(activeModel.uri, { range: activeSelection, - text: chatCodeBlockActionContext.code, + text: codeBlockActionContext.code, }), ]); } codeEditorService.listCodeEditors().find(editor => editor.getModel()?.uri.toString() === activeModel.uri.toString())?.focus(); } - private notifyUserAction(accessor: ServicesAccessor, context: IChatCodeBlockActionContext) { - const chatService = accessor.get(IChatService); - chatService.notifyUserAction({ - providerId: context.element.providerId, - agentId: context.element.agent?.id, - sessionId: context.element.sessionId, - action: { - kind: 'insert', - responseId: context.element.providerResponseId, - codeBlockIndex: context.codeBlockIndex, - totalCharacters: context.code.length, - } - }); + private notifyUserAction(accessor: ServicesAccessor, context: ICodeBlockActionContext) { + if (isResponseVM(context.element)) { + const chatService = accessor.get(IChatService); + chatService.notifyUserAction({ + providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, + action: { + kind: 'insert', + responseId: context.element.providerResponseId, + codeBlockIndex: context.codeBlockIndex, + totalCharacters: context.code.length, + } + }); + } } }); @@ -357,28 +364,31 @@ export function registerChatCodeBlockActions() { }); } - override async runWithContext(accessor: ServicesAccessor, context: IChatCodeBlockActionContext) { - if (context.element.errorDetails?.responseIsFiltered) { + override async runWithContext(accessor: ServicesAccessor, context: ICodeBlockActionContext) { + if (isResponseFiltered(context)) { // When run from command palette return; } const editorService = accessor.get(IEditorService); const chatService = accessor.get(IChatService); + editorService.openEditor({ contents: context.code, languageId: context.languageId, resource: undefined }); - chatService.notifyUserAction({ - providerId: context.element.providerId, - agentId: context.element.agent?.id, - sessionId: context.element.sessionId, - action: { - kind: 'insert', - responseId: context.element.providerResponseId, - codeBlockIndex: context.codeBlockIndex, - totalCharacters: context.code.length, - newFile: true - } - }); + if (isResponseVM(context.element)) { + chatService.notifyUserAction({ + providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, + action: { + kind: 'insert', + responseId: context.element.providerResponseId, + codeBlockIndex: context.codeBlockIndex, + totalCharacters: context.code.length, + newFile: true + } + }); + } } }); @@ -394,11 +404,16 @@ export function registerChatCodeBlockActions() { f1: true, category: CHAT_CATEGORY, icon: Codicon.terminal, - menu: { + menu: [{ id: MenuId.ChatCodeBlock, group: 'navigation', isHiddenByDefault: true, - }, + when: CONTEXT_IN_CHAT_SESSION, + }, { + id: MenuId.ChatCodeBlock, + group: 'navigation', + when: CTX_INLINE_CHAT_VISIBLE, + }], keybinding: [{ primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter, mac: { @@ -416,8 +431,8 @@ export function registerChatCodeBlockActions() { }); } - override async runWithContext(accessor: ServicesAccessor, context: IChatCodeBlockActionContext) { - if (context.element.errorDetails?.responseIsFiltered) { + override async runWithContext(accessor: ServicesAccessor, context: ICodeBlockActionContext) { + if (isResponseFiltered(context)) { // When run from command palette return; } @@ -445,17 +460,19 @@ export function registerChatCodeBlockActions() { terminal.sendText(context.code, false, true); - chatService.notifyUserAction({ - providerId: context.element.providerId, - agentId: context.element.agent?.id, - sessionId: context.element.sessionId, - action: { - kind: 'runInTerminal', - responseId: context.element.providerResponseId, - codeBlockIndex: context.codeBlockIndex, - languageId: context.languageId, - } - }); + if (isResponseVM(context.element)) { + chatService.notifyUserAction({ + providerId: context.element.providerId, + agentId: context.element.agent?.id, + sessionId: context.element.sessionId, + action: { + kind: 'runInTerminal', + responseId: context.element.providerResponseId, + codeBlockIndex: context.codeBlockIndex, + languageId: context.languageId, + } + }); + } } }); diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 2cb8c08dace..1f9dc7db688 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -27,22 +27,8 @@ import { marked } from 'vs/base/common/marked/marked'; import { FileAccess } from 'vs/base/common/network'; import { ThemeIcon } from 'vs/base/common/themables'; import { URI } from 'vs/base/common/uri'; -import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; -import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; -import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions'; -import { Range } from 'vs/editor/common/core/range'; -import { ILanguageService } from 'vs/editor/common/languages/language'; -import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; -import { EndOfLinePreference, ITextModel } from 'vs/editor/common/model'; -import { IModelService } from 'vs/editor/common/services/model'; -import { BracketMatchingController } from 'vs/editor/contrib/bracketMatching/browser/bracketMatching'; -import { ContextMenuController } from 'vs/editor/contrib/contextmenu/browser/contextmenu'; import { IMarkdownRenderResult, MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer'; -import { ViewportSemanticTokensContribution } from 'vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens'; -import { SmartSelectController } from 'vs/editor/contrib/smartSelect/browser/smartSelect'; -import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter'; import { localize } from 'vs/nls'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IMenuEntryActionViewItemOptions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; import { MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; @@ -61,8 +47,8 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView'; -import { IChatCodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatCodeblockActions'; import { ChatTreeItem, IChatCodeBlockInfo, IChatFileTreeInfo } from 'vs/workbench/contrib/chat/browser/chat'; +import { CodeBlockPart, ICodeBlockData, ICodeBlockPart } from 'vs/workbench/contrib/chat/browser/codeBlockPart'; import { ChatFollowups } from 'vs/workbench/contrib/chat/browser/chatFollowups'; import { convertParsedRequestToMarkdown, reduceInlineContentReferences, walkTreeAndAnnotateReferenceLinks } from 'vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer'; import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions'; @@ -71,9 +57,6 @@ import { IPlaceholderMarkdownString } from 'vs/workbench/contrib/chat/common/cha import { IChatContentReference, IChatReplyFollowup, IChatResponseProgressFileTreeData, IChatService, ISlashCommand, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatResponseMarkdownRenderData, IChatResponseRenderData, IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; import { IWordCountResult, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter'; -import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; -import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; -import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { createFileIconThemableTreeContainerScope } from 'vs/workbench/contrib/files/browser/views/explorerView'; import { IFilesConfiguration } from 'vs/workbench/contrib/files/common/files'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -714,7 +697,8 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { - const data = { languageId, text, codeBlockIndex: codeBlockIndex++, element, parentContextKeyService: templateData.contextKeyService }; + const hideToolbar = isResponseVM(element) && element.errorDetails?.responseIsFiltered; + const data = { languageId, text, codeBlockIndex: codeBlockIndex++, element, hideToolbar, parentContextKeyService: templateData.contextKeyService }; const ref = this.renderCodeBlock(data, disposables); // Attach this after updating text/layout of the editor, so it should only be fired when the size updates later (horizontal scrollbar, wrapping) @@ -767,7 +751,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { + private renderCodeBlock(data: ICodeBlockData, disposables: DisposableStore): IDisposableReference { const ref = this._editorPool.get(); const editorInfo = ref.object; editorInfo.render(data, this._currentLayoutWidth); @@ -905,229 +889,6 @@ export class ChatAccessibilityProvider implements IListAccessibilityProvider; - readonly element: HTMLElement; - readonly textModel: ITextModel; - layout(width: number): void; - render(data: IChatResultCodeBlockData, width: number): void; - focus(): void; - dispose(): void; -} - -const defaultCodeblockPadding = 10; - -class CodeBlockPart extends Disposable implements IChatResultCodeBlockPart { - private readonly _onDidChangeContentHeight = this._register(new Emitter()); - public readonly onDidChangeContentHeight = this._onDidChangeContentHeight.event; - - private readonly editor: CodeEditorWidget; - private readonly toolbar: MenuWorkbenchToolBar; - private readonly contextKeyService: IContextKeyService; - - public readonly textModel: ITextModel; - public readonly element: HTMLElement; - - private currentScrollWidth = 0; - - constructor( - private readonly options: ChatEditorOptions, - @IInstantiationService instantiationService: IInstantiationService, - @IContextKeyService contextKeyService: IContextKeyService, - @ILanguageService private readonly languageService: ILanguageService, - @IModelService private readonly modelService: IModelService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IAccessibilityService private readonly accessibilityService: IAccessibilityService - ) { - super(); - this.element = $('.interactive-result-editor-wrapper'); - this.contextKeyService = this._register(contextKeyService.createScoped(this.element)); - const scopedInstantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this.contextKeyService])); - this.toolbar = this._register(scopedInstantiationService.createInstance(MenuWorkbenchToolBar, this.element, MenuId.ChatCodeBlock, { - menuOptions: { - shouldForwardArgs: true - } - })); - - this._configureForScreenReader(); - this._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => this._configureForScreenReader())); - this._register(this.configurationService.onDidChangeConfiguration((e) => { - if (e.affectedKeys.has(AccessibilityVerbositySettingId.Chat)) { - this._configureForScreenReader(); - } - })); - const editorElement = dom.append(this.element, $('.interactive-result-editor')); - this.editor = this._register(scopedInstantiationService.createInstance(CodeEditorWidget, editorElement, { - ...getSimpleEditorOptions(this.configurationService), - readOnly: true, - lineNumbers: 'off', - selectOnLineNumbers: true, - scrollBeyondLastLine: false, - lineDecorationsWidth: 8, - dragAndDrop: false, - padding: { top: defaultCodeblockPadding, bottom: defaultCodeblockPadding }, - mouseWheelZoom: false, - scrollbar: { - alwaysConsumeMouseWheel: false - }, - ariaLabel: localize('chat.codeBlockHelp', 'Code block'), - ...this.getEditorOptionsFromConfig() - }, { - isSimpleWidget: true, - contributions: EditorExtensionsRegistry.getSomeEditorContributions([ - MenuPreventer.ID, - SelectionClipboardContributionID, - ContextMenuController.ID, - - WordHighlighterContribution.ID, - ViewportSemanticTokensContribution.ID, - BracketMatchingController.ID, - SmartSelectController.ID, - ]) - })); - - this._register(this.options.onDidChange(() => { - this.editor.updateOptions(this.getEditorOptionsFromConfig()); - })); - - this._register(this.editor.onDidScrollChange(e => { - this.currentScrollWidth = e.scrollWidth; - })); - this._register(this.editor.onDidContentSizeChange(e => { - if (e.contentHeightChanged) { - this._onDidChangeContentHeight.fire(e.contentHeight); - } - })); - this._register(this.editor.onDidBlurEditorWidget(() => { - this.element.classList.remove('focused'); - WordHighlighterContribution.get(this.editor)?.stopHighlighting(); - })); - this._register(this.editor.onDidFocusEditorWidget(() => { - this.element.classList.add('focused'); - WordHighlighterContribution.get(this.editor)?.restoreViewState(true); - })); - - this.textModel = this._register(this.modelService.createModel('', null, undefined)); - this.editor.setModel(this.textModel); - } - - focus(): void { - this.editor.focus(); - } - - private updatePaddingForLayout() { - // scrollWidth = "the width of the content that needs to be scrolled" - // contentWidth = "the width of the area where content is displayed" - const horizontalScrollbarVisible = this.currentScrollWidth > this.editor.getLayoutInfo().contentWidth; - const scrollbarHeight = this.editor.getLayoutInfo().horizontalScrollbarHeight; - const bottomPadding = horizontalScrollbarVisible ? - Math.max(defaultCodeblockPadding - scrollbarHeight, 2) : - defaultCodeblockPadding; - this.editor.updateOptions({ padding: { top: defaultCodeblockPadding, bottom: bottomPadding } }); - } - - private _configureForScreenReader(): void { - const toolbarElt = this.toolbar.getElement(); - if (this.accessibilityService.isScreenReaderOptimized()) { - toolbarElt.style.display = 'block'; - toolbarElt.ariaLabel = this.configurationService.getValue(AccessibilityVerbositySettingId.Chat) ? localize('chat.codeBlock.toolbarVerbose', 'Toolbar for code block which can be reached via tab') : localize('chat.codeBlock.toolbar', 'Code block toolbar'); - } else { - toolbarElt.style.display = ''; - } - - } - - private getEditorOptionsFromConfig(): IEditorOptions { - return { - wordWrap: this.options.configuration.resultEditor.wordWrap, - fontLigatures: this.options.configuration.resultEditor.fontLigatures, - bracketPairColorization: this.options.configuration.resultEditor.bracketPairColorization, - fontFamily: this.options.configuration.resultEditor.fontFamily === 'default' ? - EDITOR_FONT_DEFAULTS.fontFamily : - this.options.configuration.resultEditor.fontFamily, - fontSize: this.options.configuration.resultEditor.fontSize, - fontWeight: this.options.configuration.resultEditor.fontWeight, - lineHeight: this.options.configuration.resultEditor.lineHeight, - }; - } - - layout(width: number): void { - const realContentHeight = this.editor.getContentHeight(); - const editorBorder = 2; - this.editor.layout({ width: width - editorBorder, height: realContentHeight }); - this.updatePaddingForLayout(); - } - - render(data: IChatResultCodeBlockData, width: number): void { - this.contextKeyService.updateParent(data.parentContextKeyService); - - if (this.options.configuration.resultEditor.wordWrap === 'on') { - // Intialize the editor with the new proper width so that getContentHeight - // will be computed correctly in the next call to layout() - this.layout(width); - } - - const text = this.fixCodeText(data.text, data.languageId); - this.setText(text); - - const vscodeLanguageId = this.languageService.getLanguageIdByLanguageName(data.languageId) ?? undefined; - this.setLanguage(vscodeLanguageId); - - this.layout(width); - this.editor.updateOptions({ ariaLabel: localize('chat.codeBlockLabel', "Code block {0}", data.codeBlockIndex + 1) }); - this.toolbar.context = { - code: data.text, - codeBlockIndex: data.codeBlockIndex, - element: data.element, - languageId: vscodeLanguageId - }; - - if (isResponseVM(data.element) && data.element.errorDetails?.responseIsFiltered) { - dom.hide(this.toolbar.getElement()); - } else { - dom.show(this.toolbar.getElement()); - } - } - - private fixCodeText(text: string, languageId: string): string { - if (languageId === 'php') { - if (!text.trim().startsWith('<')) { - return ``; - } - } - - return text; - } - - private setText(newText: string): void { - const currentText = this.textModel.getValue(EndOfLinePreference.LF); - if (newText === currentText) { - return; - } - - if (newText.startsWith(currentText)) { - const text = newText.slice(currentText.length); - const lastLine = this.textModel.getLineCount(); - const lastCol = this.textModel.getLineMaxColumn(lastLine); - this.textModel.applyEdits([{ range: new Range(lastLine, lastCol, lastLine, lastCol), text }]); - } else { - // console.log(`Failed to optimize setText`); - this.textModel.setValue(newText); - } - } - - private setLanguage(vscodeLanguageId: string | undefined): void { - this.textModel.setLanguage(vscodeLanguageId ?? PLAINTEXT_LANGUAGE_ID); - } -} interface IDisposableReference extends IDisposable { object: T; @@ -1135,9 +896,9 @@ interface IDisposableReference extends IDisposable { } class EditorPool extends Disposable { - private _pool: ResourcePool; + private _pool: ResourcePool; - public get inUse(): ReadonlySet { + public get inUse(): ReadonlySet { return this._pool.inUse; } @@ -1151,11 +912,11 @@ class EditorPool extends Disposable { // TODO listen to changes on options } - private editorFactory(): IChatResultCodeBlockPart { - return this.instantiationService.createInstance(CodeBlockPart, this.options); + private editorFactory(): ICodeBlockPart { + return this.instantiationService.createInstance(CodeBlockPart, this.options, MenuId.ChatCodeBlock); } - get(): IDisposableReference { + get(): IDisposableReference { const object = this._pool.get(); let stale = false; return { diff --git a/src/vs/workbench/contrib/chat/browser/chatOptions.ts b/src/vs/workbench/contrib/chat/browser/chatOptions.ts index 1995598eba9..e76519d260a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatOptions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatOptions.ts @@ -79,7 +79,7 @@ export class ChatEditorOptions extends Disposable { private readonly resultEditorBackgroundColor: string, @IConfigurationService private readonly configurationService: IConfigurationService, @IThemeService private readonly themeService: IThemeService, - @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService + @IViewDescriptorService readonly viewDescriptorService: IViewDescriptorService ) { super(); diff --git a/src/vs/workbench/contrib/chat/browser/codeBlockPart.css b/src/vs/workbench/contrib/chat/browser/codeBlockPart.css new file mode 100644 index 00000000000..5bd75dd7c55 --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/codeBlockPart.css @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + + +.interactive-result-code-block { + position: relative; +} + +.interactive-result-code-block .monaco-toolbar { + display: none; + position: absolute; + top: -13px; + right: 10px; + height: 26px; + background-color: var(--vscode-interactive-result-editor-background-color, var(--vscode-editor-background)); + border: 1px solid var(--vscode-chat-requestBorder); + z-index: 100; +} + +.interactive-result-code-block .monaco-toolbar .action-item { + height: 24px; + width: 24px; + margin: 1px 2px; +} + +.interactive-result-code-block .monaco-toolbar .action-item .codicon { + margin: 1px; +} + +.interactive-result-code-block:hover .monaco-toolbar, +.interactive-result-code-block .monaco-toolbar:focus-within, +.interactive-result-code-block.focused .monaco-toolbar { + display: initial; + border-radius: 2px; +} + +.interactive-result-code-block { + margin: 16px 0; +} + +.interactive-result-code-block .interactive-result-editor .monaco-editor { + border: 1px solid var(--vscode-input-border, transparent); +} + +.interactive-result-code-block .interactive-result-editor .monaco-editor.focused { + border-color: var(--vscode-focusBorder, transparent); +} + +.interactive-result-code-block, +.interactive-result-code-block .monaco-editor, +.interactive-result-code-block .monaco-editor .overflow-guard { + border-radius: 4px; +} diff --git a/src/vs/workbench/contrib/chat/browser/codeBlockPart.ts b/src/vs/workbench/contrib/chat/browser/codeBlockPart.ts new file mode 100644 index 00000000000..1f64b2cad82 --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/codeBlockPart.ts @@ -0,0 +1,277 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./codeBlockPart'; + +import * as dom from 'vs/base/browser/dom'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; + +import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; +import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { Range } from 'vs/editor/common/core/range'; +import { ILanguageService } from 'vs/editor/common/languages/language'; +import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; +import { EndOfLinePreference, ITextModel } from 'vs/editor/common/model'; +import { IModelService } from 'vs/editor/common/services/model'; +import { BracketMatchingController } from 'vs/editor/contrib/bracketMatching/browser/bracketMatching'; +import { ContextMenuController } from 'vs/editor/contrib/contextmenu/browser/contextmenu'; +import { ViewportSemanticTokensContribution } from 'vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens'; +import { SmartSelectController } from 'vs/editor/contrib/smartSelect/browser/smartSelect'; +import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter'; +import { localize } from 'vs/nls'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; +import { MenuId } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; +import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions'; +import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; +import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; + +const $ = dom.$; + + +export interface ICodeBlockData { + text: string; + languageId: string; + codeBlockIndex: number; + element: unknown; + parentContextKeyService?: IContextKeyService; + hideToolbar?: boolean; +} + +export interface ICodeBlockActionContext { + code: string; + languageId: string; + codeBlockIndex: number; + element: unknown; +} + + +export interface ICodeBlockPart { + readonly onDidChangeContentHeight: Event; + readonly element: HTMLElement; + readonly textModel: ITextModel; + layout(width: number): void; + render(data: ICodeBlockData, width: number): void; + focus(): void; + dispose(): void; +} + +const defaultCodeblockPadding = 10; + +export class CodeBlockPart extends Disposable implements ICodeBlockPart { + private readonly _onDidChangeContentHeight = this._register(new Emitter()); + public readonly onDidChangeContentHeight = this._onDidChangeContentHeight.event; + + private readonly editor: CodeEditorWidget; + private readonly toolbar: MenuWorkbenchToolBar; + private readonly contextKeyService: IContextKeyService; + + public readonly textModel: ITextModel; + public readonly element: HTMLElement; + + private currentScrollWidth = 0; + + constructor( + private readonly options: ChatEditorOptions, + readonly menuId: MenuId, + @IInstantiationService instantiationService: IInstantiationService, + @IContextKeyService contextKeyService: IContextKeyService, + @ILanguageService private readonly languageService: ILanguageService, + @IModelService private readonly modelService: IModelService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IAccessibilityService private readonly accessibilityService: IAccessibilityService + ) { + super(); + this.element = $('.interactive-result-code-block'); + this.contextKeyService = this._register(contextKeyService.createScoped(this.element)); + const scopedInstantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this.contextKeyService])); + this.toolbar = this._register(scopedInstantiationService.createInstance(MenuWorkbenchToolBar, this.element, menuId, { + menuOptions: { + shouldForwardArgs: true + } + })); + + this._configureForScreenReader(); + this._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => this._configureForScreenReader())); + this._register(this.configurationService.onDidChangeConfiguration((e) => { + if (e.affectedKeys.has(AccessibilityVerbositySettingId.Chat)) { + this._configureForScreenReader(); + } + })); + const editorElement = dom.append(this.element, $('.interactive-result-editor')); + this.editor = this._register(scopedInstantiationService.createInstance(CodeEditorWidget, editorElement, { + ...getSimpleEditorOptions(this.configurationService), + readOnly: true, + lineNumbers: 'off', + selectOnLineNumbers: true, + scrollBeyondLastLine: false, + lineDecorationsWidth: 8, + dragAndDrop: false, + padding: { top: defaultCodeblockPadding, bottom: defaultCodeblockPadding }, + mouseWheelZoom: false, + scrollbar: { + alwaysConsumeMouseWheel: false + }, + ariaLabel: localize('chat.codeBlockHelp', 'Code block'), + ...this.getEditorOptionsFromConfig() + }, { + isSimpleWidget: true, + contributions: EditorExtensionsRegistry.getSomeEditorContributions([ + MenuPreventer.ID, + SelectionClipboardContributionID, + ContextMenuController.ID, + + WordHighlighterContribution.ID, + ViewportSemanticTokensContribution.ID, + BracketMatchingController.ID, + SmartSelectController.ID, + ]) + })); + + this._register(this.options.onDidChange(() => { + this.editor.updateOptions(this.getEditorOptionsFromConfig()); + })); + + this._register(this.editor.onDidScrollChange(e => { + this.currentScrollWidth = e.scrollWidth; + })); + this._register(this.editor.onDidContentSizeChange(e => { + if (e.contentHeightChanged) { + this._onDidChangeContentHeight.fire(e.contentHeight); + } + })); + this._register(this.editor.onDidBlurEditorWidget(() => { + this.element.classList.remove('focused'); + WordHighlighterContribution.get(this.editor)?.stopHighlighting(); + })); + this._register(this.editor.onDidFocusEditorWidget(() => { + this.element.classList.add('focused'); + WordHighlighterContribution.get(this.editor)?.restoreViewState(true); + })); + + this.textModel = this._register(this.modelService.createModel('', null, undefined)); + this.editor.setModel(this.textModel); + } + + focus(): void { + this.editor.focus(); + } + + private updatePaddingForLayout() { + // scrollWidth = "the width of the content that needs to be scrolled" + // contentWidth = "the width of the area where content is displayed" + const horizontalScrollbarVisible = this.currentScrollWidth > this.editor.getLayoutInfo().contentWidth; + const scrollbarHeight = this.editor.getLayoutInfo().horizontalScrollbarHeight; + const bottomPadding = horizontalScrollbarVisible ? + Math.max(defaultCodeblockPadding - scrollbarHeight, 2) : + defaultCodeblockPadding; + this.editor.updateOptions({ padding: { top: defaultCodeblockPadding, bottom: bottomPadding } }); + } + + private _configureForScreenReader(): void { + const toolbarElt = this.toolbar.getElement(); + if (this.accessibilityService.isScreenReaderOptimized()) { + toolbarElt.style.display = 'block'; + toolbarElt.ariaLabel = this.configurationService.getValue(AccessibilityVerbositySettingId.Chat) ? localize('chat.codeBlock.toolbarVerbose', 'Toolbar for code block which can be reached via tab') : localize('chat.codeBlock.toolbar', 'Code block toolbar'); + } else { + toolbarElt.style.display = ''; + } + + } + + private getEditorOptionsFromConfig(): IEditorOptions { + return { + wordWrap: this.options.configuration.resultEditor.wordWrap, + fontLigatures: this.options.configuration.resultEditor.fontLigatures, + bracketPairColorization: this.options.configuration.resultEditor.bracketPairColorization, + fontFamily: this.options.configuration.resultEditor.fontFamily === 'default' ? + EDITOR_FONT_DEFAULTS.fontFamily : + this.options.configuration.resultEditor.fontFamily, + fontSize: this.options.configuration.resultEditor.fontSize, + fontWeight: this.options.configuration.resultEditor.fontWeight, + lineHeight: this.options.configuration.resultEditor.lineHeight, + }; + } + + layout(width: number): void { + const realContentHeight = this.editor.getContentHeight(); + const editorBorder = 2; + this.editor.layout({ width: width - editorBorder, height: realContentHeight }); + this.updatePaddingForLayout(); + } + + + render(data: ICodeBlockData, width: number): void { + if (data.parentContextKeyService) { + this.contextKeyService.updateParent(data.parentContextKeyService); + } + + if (this.options.configuration.resultEditor.wordWrap === 'on') { + // Intialize the editor with the new proper width so that getContentHeight + // will be computed correctly in the next call to layout() + this.layout(width); + } + + const text = this.fixCodeText(data.text, data.languageId); + this.setText(text); + + const vscodeLanguageId = this.languageService.getLanguageIdByLanguageName(data.languageId) ?? undefined; + this.setLanguage(vscodeLanguageId); + + this.layout(width); + this.editor.updateOptions({ ariaLabel: localize('chat.codeBlockLabel', "Code block {0}", data.codeBlockIndex + 1) }); + this.toolbar.context = { + code: data.text, + codeBlockIndex: data.codeBlockIndex, + element: data.element, + languageId: vscodeLanguageId + }; + + if (data.hideToolbar) { + dom.hide(this.toolbar.getElement()); + } else { + dom.show(this.toolbar.getElement()); + } + } + + private fixCodeText(text: string, languageId: string): string { + if (languageId === 'php') { + if (!text.trim().startsWith('<')) { + return ``; + } + } + + return text; + } + + private setText(newText: string): void { + const currentText = this.textModel.getValue(EndOfLinePreference.LF); + if (newText === currentText) { + return; + } + + if (newText.startsWith(currentText)) { + const text = newText.slice(currentText.length); + const lastLine = this.textModel.getLineCount(); + const lastCol = this.textModel.getLineMaxColumn(lastLine); + this.textModel.applyEdits([{ range: new Range(lastLine, lastCol, lastLine, lastCol), text }]); + } else { + // console.log(`Failed to optimize setText`); + this.textModel.setValue(newText); + } + } + + private setLanguage(vscodeLanguageId: string | undefined): void { + this.textModel.setLanguage(vscodeLanguageId ?? PLAINTEXT_LANGUAGE_ID); + } +} diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 727dcef57d6..3ee1eba535f 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -257,66 +257,17 @@ color: var(--vscode-icon-foreground) !important; } -.interactive-item-container .interactive-result-editor-wrapper { - position: relative; -} - -.interactive-item-container .interactive-result-editor-wrapper .monaco-toolbar { - display: none; - position: absolute; - top: -13px; - right: 10px; - height: 26px; - background-color: var(--vscode-interactive-result-editor-background-color, var(--vscode-editor-background)); - border: 1px solid var(--vscode-chat-requestBorder); - z-index: 100; -} - -.interactive-item-container .interactive-result-editor-wrapper .monaco-toolbar .action-item { - height: 24px; - width: 24px; - margin: 1px 2px; -} - -.interactive-item-container .interactive-result-editor-wrapper .monaco-toolbar .action-item .codicon { - margin: 1px; -} - -.interactive-item-container .interactive-result-editor-wrapper:hover .monaco-toolbar, -.interactive-item-container .interactive-result-editor-wrapper .monaco-toolbar:focus-within, -.interactive-item-container .interactive-result-editor-wrapper.focused .monaco-toolbar { - display: initial; - border-radius: 2px; -} - -.interactive-item-container .interactive-result-editor-wrapper { - margin: 16px 0; -} - -.interactive-session .interactive-item-container.interactive-response .interactive-result-editor-wrapper .interactive-result-editor .monaco-editor, -.interactive-session .interactive-item-container.interactive-response .interactive-result-editor-wrapper .interactive-result-editor .monaco-editor .margin, -.interactive-session .interactive-item-container.interactive-response .interactive-result-editor-wrapper .interactive-result-editor .monaco-editor .monaco-editor-background { +.interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor, +.interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor .margin, +.interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor .monaco-editor-background { background-color: var(--vscode-interactive-result-editor-background-color); } -.interactive-item-container .interactive-result-editor-wrapper .interactive-result-editor .monaco-editor { - border: 1px solid var(--vscode-input-border, transparent); -} - -.interactive-item-container .interactive-result-editor-wrapper .interactive-result-editor .monaco-editor.focused { - border-color: var(--vscode-focusBorder, transparent); -} - -.interactive-item-container .interactive-result-editor-wrapper, -.interactive-item-container .interactive-result-editor-wrapper .monaco-editor, -.interactive-item-container .interactive-result-editor-wrapper .monaco-editor .overflow-guard { - border-radius: 4px; -} - -.interactive-item-container.interactive-item-compact .interactive-result-editor-wrapper { +.interactive-item-compact .interactive-result-code-block { margin: 0 0 8px 0; } + .interactive-response .interactive-response-error-details { display: flex; align-items: start; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css index 12d60096fcb..92b75867291 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css @@ -164,6 +164,10 @@ margin: unset; } +.monaco-editor .inline-chat .markdownMessage .message .interactive-result-code-block { + margin: 16px 0; +} + .monaco-editor .inline-chat .markdownMessage .message { -webkit-line-clamp: initial; -webkit-box-orient: vertical; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 57b125fbf74..c10fb758a41 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { renderMarkdown } from 'vs/base/browser/markdownRenderer'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { Barrier, raceCancellationError } from 'vs/base/common/async'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; @@ -730,11 +729,10 @@ export class InlineChatController implements IEditorContribution { } else if (response instanceof MarkdownResponse) { // clear status, show MD message - const renderedMarkdown = renderMarkdown(response.raw.message, { inline: true }); + this._zone.value.widget.updateStatus(''); - this._zone.value.widget.updateMarkdownMessage(renderedMarkdown.element); + const content = this._zone.value.widget.updateMarkdownMessage(response.raw.message); this._zone.value.widget.updateToolbar(true); - const content = renderedMarkdown.element.textContent; if (content) { status = localize('markdownResponseMessage', "{0}", content); } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index d3360338d41..db86fea8ea0 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -55,6 +55,12 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { assertType } from 'vs/base/common/types'; import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer'; +import { IMarkdownString } from 'vs/base/common/htmlContent'; +import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer'; +import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions'; +import { MenuId } from 'vs/platform/actions/common/actions'; +import { editorForeground, inputBackground, editorBackground } from 'vs/platform/theme/common/colorRegistry'; +import { CodeBlockPart } from 'vs/workbench/contrib/chat/browser/codeBlockPart'; import { Lazy } from 'vs/base/common/lazy'; const defaultAriaLabel = localize('aria-label', "Inline Chat Input"); @@ -182,6 +188,7 @@ export class InlineChatWidget { private readonly _onDidChangeHeight = this._store.add(new MicrotaskEmitter()); readonly onDidChangeHeight: Event = Event.filter(this._onDidChangeHeight.event, _ => !this._isLayouting); + private readonly _onDidChangeLayout = this._store.add(new MicrotaskEmitter()); private readonly _onDidChangeInput = this._store.add(new Emitter()); readonly onDidChangeInput: Event = this._onDidChangeInput.event; @@ -193,6 +200,10 @@ export class InlineChatWidget { private _slashCommandContentWidget: SlashCommandContentWidget; + private readonly _markdownRenderer: MarkdownRenderer; + private readonly _editorOptions: ChatEditorOptions; + private _codeBlockDisposables = this._store.add(new DisposableStore()); + constructor( private readonly parentEditor: ICodeEditor, @IModelService private readonly _modelService: IModelService, @@ -235,6 +246,10 @@ export class InlineChatWidget { this._inputModel = this._store.add(this._modelService.getModel(uri) ?? this._modelService.createModel('', null, uri)); this._inputEditor.setModel(this._inputModel); + this._markdownRenderer = this._store.add(_instantiationService.createInstance(MarkdownRenderer, {})); + this._editorOptions = this._store.add(_instantiationService.createInstance(ChatEditorOptions, undefined, editorForeground, inputBackground, editorBackground)); + + // --- context keys this._ctxMessageCropState = CTX_INLINE_CHAT_MESSAGE_CROP_STATE.bindTo(this._contextKeyService); @@ -444,6 +459,7 @@ export class InlineChatWidget { const editorHeightInLines = Math.floor(editorHeight / lineHeight); this._elements.root.style.setProperty('--vscode-inline-chat-cropped', String(Math.floor(editorHeightInLines / 5))); this._elements.root.style.setProperty('--vscode-inline-chat-expanded', String(Math.floor(editorHeightInLines / 3))); + this._onDidChangeLayout.fire(); } } finally { this._isLayouting = false; @@ -523,22 +539,37 @@ export class InlineChatWidget { return this._elements.markdownMessage.textContent ?? undefined; } - updateMarkdownMessage(message: Node | undefined) { + updateMarkdownMessage(message: IMarkdownString | undefined) { + this._codeBlockDisposables.clear(); this._elements.markdownMessage.classList.toggle('hidden', !message); let expansionState: ExpansionState; + let textContent: string | undefined = undefined; if (!message) { reset(this._elements.message); this._ctxMessageCropState.reset(); expansionState = ExpansionState.NOT_CROPPED; - } else { + let codeBlockIndex = 0; + const renderedMarkdown = this._codeBlockDisposables.add(this._markdownRenderer.render(message, { + fillInIncompleteTokens: true, + codeBlockRendererSync: (languageId, text) => { + const codeBlockPart = this._codeBlockDisposables.add(this._instantiationService.createInstance(CodeBlockPart, this._editorOptions, MenuId.ChatCodeBlock)); + const data = { languageId, text, codeBlockIndex: codeBlockIndex++, element: undefined }; + codeBlockPart.render(data, this._elements.message.clientWidth); + this._codeBlockDisposables.add(this._onDidChangeLayout.event(() => { + codeBlockPart.layout(this._elements.message.clientWidth); + })); + return codeBlockPart.element; + } + })); + textContent = renderedMarkdown.element.textContent ?? undefined; if (this._preferredExpansionState) { - reset(this._elements.message, message); + reset(this._elements.message, renderedMarkdown.element); expansionState = this._preferredExpansionState; this._preferredExpansionState = undefined; } else { this._updateLineClamp(ExpansionState.CROPPED); - reset(this._elements.message, message); + reset(this._elements.message, renderedMarkdown.element); expansionState = this._elements.message.scrollHeight > this._elements.message.clientHeight ? ExpansionState.CROPPED : ExpansionState.NOT_CROPPED; } this._ctxMessageCropState.set(expansionState); @@ -546,6 +577,7 @@ export class InlineChatWidget { } this._expansionState = expansionState; this._onDidChangeHeight.fire(); + return textContent; } updateMarkdownMessageExpansionState(expansionState: ExpansionState) { diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts index 806f24b91e4..bb25fb4e308 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts @@ -16,12 +16,15 @@ import { Range } from 'vs/editor/common/core/range'; import { ITextModel } from 'vs/editor/common/model'; import { IModelService } from 'vs/editor/common/services/model'; import { instantiateTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; +import { IViewDescriptorService } from 'vs/workbench/common/views'; import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView'; import { IChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chat'; @@ -91,6 +94,10 @@ suite('InteractiveChatController', function () { const contextKeyService = new MockContextKeyService(); inlineChatService = new InlineChatServiceImpl(contextKeyService); + const configurationService = new TestConfigurationService(); + configurationService.setUserConfiguration('chat', { editor: { fontSize: 14, fontFamily: 'default' } }); + configurationService.setUserConfiguration('editor', {}); + const serviceCollection = new ServiceCollection( [IContextKeyService, contextKeyService], [IInlineChatService, inlineChatService], @@ -113,6 +120,10 @@ suite('InteractiveChatController', function () { override getOpenAriaHint(verbositySettingKey: AccessibilityVerbositySettingId): string | null { return null; } + }], + [IConfigurationService, configurationService], + [IViewDescriptorService, new class extends mock() { + override onDidChangeLocation = Event.None; }] ); From 4be7c199b9809d9c7915c44b88bf754d9680ec87 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 01:46:42 +0200 Subject: [PATCH 163/290] Revert "fix #195348 (#195637)" (#195734) This reverts commit ae774a04cf1f5ecfc03d79165f30b8001cde862d. --- .../browser/parts/activitybar/activitybarPart.ts | 4 +--- src/vs/workbench/browser/parts/paneCompositeBar.ts | 8 +------- src/vs/workbench/common/views.ts | 1 + .../services/views/browser/viewDescriptorService.ts | 4 ++++ .../views/test/browser/viewDescriptorService.test.ts | 1 + 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 45597e813ba..13f0980b69c 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -39,7 +39,6 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b import { TitleBarVisibleContext } from 'vs/workbench/common/contextkeys'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect'; export class ActivitybarPart extends Part { @@ -179,7 +178,6 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { @IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IContextKeyService contextKeyService: IContextKeyService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IExtensionBisectService extensionBisectService: IExtensionBisectService, @IConfigurationService private readonly configurationService: IConfigurationService, @IMenuService private readonly menuService: IMenuService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @@ -190,7 +188,7 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { this.fillContextMenuActions(actions, e); options.fillExtraContextMenuActions(actions, e); } - }, part, paneCompositePart, instantiationService, storageService, extensionService, extensionBisectService, viewDescriptorService, contextKeyService, environmentService); + }, part, paneCompositePart, instantiationService, storageService, extensionService, viewDescriptorService, contextKeyService, environmentService); if (showGlobalActivities) { this.globalCompositeBar = this._register(instantiationService.createInstance(GlobalCompositeBar, () => this.getContextMenuActions(), (theme: IColorTheme) => this.options.colors(theme), this.options.activityHoverOptions)); diff --git a/src/vs/workbench/browser/parts/paneCompositeBar.ts b/src/vs/workbench/browser/parts/paneCompositeBar.ts index aa080683cc6..6c1286bc2b0 100644 --- a/src/vs/workbench/browser/parts/paneCompositeBar.ts +++ b/src/vs/workbench/browser/parts/paneCompositeBar.ts @@ -30,7 +30,6 @@ import { GestureEvent } from 'vs/base/browser/touch'; import { IPaneCompositePart } from 'vs/workbench/browser/parts/paneCompositePart'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect'; interface IPlaceholderViewContainer { readonly id: string; @@ -97,7 +96,6 @@ export class PaneCompositeBar extends Disposable { @IInstantiationService protected readonly instantiationService: IInstantiationService, @IStorageService private readonly storageService: IStorageService, @IExtensionService private readonly extensionService: IExtensionService, - @IExtensionBisectService private readonly extensionBisectService: IExtensionBisectService, @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, @IContextKeyService protected readonly contextKeyService: IContextKeyService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @@ -219,16 +217,12 @@ export class PaneCompositeBar extends Disposable { this.hasExtensionsRegistered = true; // show/hide/remove composites - const shouldRemoveNotExsitingComposite = !(this.extensionBisectService.isActive - || this.environmentService.disableExtensions === true - || (Array.isArray(this.environmentService.disableExtensions) && this.environmentService.disableExtensions.length > 0)); - for (const { id } of this.cachedViewContainers) { const viewContainer = this.getViewContainer(id); if (viewContainer) { this.showOrHideViewContainer(viewContainer); } else { - if (shouldRemoveNotExsitingComposite) { + if (this.viewDescriptorService.isViewContainerRemovedPermanently(id)) { this.removeComposite(id); } else { this.hideComposite(id); diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index db7f36bbbea..9c886825943 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -609,6 +609,7 @@ export interface IViewDescriptorService { getDefaultViewContainer(location: ViewContainerLocation): ViewContainer | undefined; getViewContainerById(id: string): ViewContainer | null; + isViewContainerRemovedPermanently(id: string): boolean; getDefaultViewContainerLocation(viewContainer: ViewContainer): ViewContainerLocation | null; getViewContainerLocation(viewContainer: ViewContainer): ViewContainerLocation | null; getViewContainersByLocation(location: ViewContainerLocation): ViewContainer[]; diff --git a/src/vs/workbench/services/views/browser/viewDescriptorService.ts b/src/vs/workbench/services/views/browser/viewDescriptorService.ts index 05d70551deb..d10b48306c1 100644 --- a/src/vs/workbench/services/views/browser/viewDescriptorService.ts +++ b/src/vs/workbench/services/views/browser/viewDescriptorService.ts @@ -378,6 +378,10 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor this.saveViewCustomizations(); } + isViewContainerRemovedPermanently(viewContainerId: string): boolean { + return this.isGeneratedContainerId(viewContainerId) && !this.viewContainersCustomLocations.has(viewContainerId); + } + private onDidChangeDefaultContainer(views: IViewDescriptor[], from: ViewContainer, to: ViewContainer): void { const viewsToMove = views.filter(view => !this.viewDescriptorsCustomLocations.has(view.id) // Move views which are not already moved diff --git a/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts b/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts index d47daa9b947..58103b06c38 100644 --- a/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts +++ b/src/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts @@ -516,6 +516,7 @@ suite('ViewDescriptorService', () => { testObject.whenExtensionsRegistered(); assert.deepStrictEqual(testObject.getViewContainerById(generatedViewContainerId), null); + assert.deepStrictEqual(testObject.isViewContainerRemovedPermanently(generatedViewContainerId), true); const actual = JSON.parse(storageService.get('views.customizations', StorageScope.PROFILE)!); assert.deepStrictEqual(actual, { viewContainerLocations: {}, viewLocations: {}, viewContainerBadgeEnablementStates: {} }); From 90787304bb342a84ade5d4bbbee9063ef8eb712c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 01:49:18 +0200 Subject: [PATCH 164/290] make visibility workspace state (#195739) --- .../parts/activitybar/activitybarPart.ts | 2 + .../parts/auxiliarybar/auxiliaryBarPart.ts | 2 + .../browser/parts/paneCompositeBar.ts | 55 ++++++++++++++++++- .../browser/parts/panel/panelPart.ts | 1 + .../browser/parts/sidebar/sidebarPart.ts | 1 + 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 13f0980b69c..d0182c35883 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -46,6 +46,7 @@ export class ActivitybarPart extends Part { static readonly pinnedViewContainersKey = 'workbench.activity.pinnedViewlets2'; static readonly placeholderViewContainersKey = 'workbench.activity.placeholderViewlets'; + static readonly viewContainersWorkspaceStateKey = 'workbench.activity.viewletsWorkspaceState'; //#region IView @@ -74,6 +75,7 @@ export class ActivitybarPart extends Part { partContainerClass: 'activitybar', pinnedViewContainersKey: ActivitybarPart.pinnedViewContainersKey, placeholderViewContainersKey: ActivitybarPart.placeholderViewContainersKey, + viewContainersWorkspaceStateKey: ActivitybarPart.viewContainersWorkspaceStateKey, orientation: ActionsOrientation.VERTICAL, icon: true, iconSize: 24, diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts index e6bd36f86c6..a574fdae744 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts @@ -34,6 +34,7 @@ export class AuxiliaryBarPart extends AbstractPaneCompositePart { static readonly activePanelSettingsKey = 'workbench.auxiliarybar.activepanelid'; static readonly pinnedPanelsKey = 'workbench.auxiliarybar.pinnedPanels'; static readonly placeholdeViewContainersKey = 'workbench.auxiliarybar.placeholderPanels'; + static readonly viewContainersWorkspaceStateKey = 'workbench.auxiliarybar.viewContainersWorkspaceState'; // Use the side bar dimensions override readonly minimumWidth: number = 170; @@ -127,6 +128,7 @@ export class AuxiliaryBarPart extends AbstractPaneCompositePart { partContainerClass: 'auxiliarybar', pinnedViewContainersKey: AuxiliaryBarPart.pinnedPanelsKey, placeholderViewContainersKey: AuxiliaryBarPart.placeholdeViewContainersKey, + viewContainersWorkspaceStateKey: AuxiliaryBarPart.viewContainersWorkspaceStateKey, icon: true, orientation: ActionsOrientation.HORIZONTAL, recomputeSizes: true, diff --git a/src/vs/workbench/browser/parts/paneCompositeBar.ts b/src/vs/workbench/browser/parts/paneCompositeBar.ts index 6c1286bc2b0..73d02bedaad 100644 --- a/src/vs/workbench/browser/parts/paneCompositeBar.ts +++ b/src/vs/workbench/browser/parts/paneCompositeBar.ts @@ -38,6 +38,7 @@ interface IPlaceholderViewContainer { readonly themeIcon?: ThemeIcon; readonly isBuiltin?: boolean; readonly views?: { when?: string }[]; + // TODO @sandy081: Remove this after a while. Migrated to visible in IViewContainerWorkspaceState readonly visible?: boolean; } @@ -45,7 +46,12 @@ interface IPinnedViewContainer { readonly id: string; readonly pinned: boolean; readonly order?: number; - // TODO @sandy081: Remove this after a while. Migrated to visible in IPlaceholderViewContainer + // TODO @sandy081: Remove this after a while. Migrated to visible in IViewContainerWorkspaceState + readonly visible: boolean; +} + +interface IViewContainerWorkspaceState { + readonly id: string; readonly visible: boolean; } @@ -64,6 +70,7 @@ export interface IPaneCompositeBarOptions { readonly partContainerClass: string; readonly pinnedViewContainersKey: string; readonly placeholderViewContainersKey: string; + readonly viewContainersWorkspaceStateKey: string; readonly icon: boolean; readonly compact?: boolean; readonly iconSize: number; @@ -554,6 +561,12 @@ export class PaneCompositeBar extends Disposable { cachedViewContainer.isBuiltin = placeholderViewContainer.isBuiltin; } } + for (const viewContainerWorkspaceState of this.getViewContainersWorkspaceState()) { + const cachedViewContainer = this._cachedViewContainers.find(cached => cached.id === viewContainerWorkspaceState.id); + if (cachedViewContainer) { + cachedViewContainer.visible = viewContainerWorkspaceState.visible ?? cachedViewContainer.visible; + } + } } return this._cachedViewContainers; @@ -568,15 +581,19 @@ export class PaneCompositeBar extends Disposable { order }))); - this.setPlaceholderViewContainers(cachedViewContainers.map(({ id, icon, name, views, visible, isBuiltin }) => ({ + this.setPlaceholderViewContainers(cachedViewContainers.map(({ id, icon, name, views, isBuiltin }) => ({ id, iconUrl: URI.isUri(icon) ? icon : undefined, themeIcon: ThemeIcon.isThemeIcon(icon) ? icon : undefined, name, isBuiltin, - visible, views }))); + + this.setViewContainersWorkspaceState(cachedViewContainers.map(({ id, visible }) => ({ + id, + visible, + }))); } private getPinnedViewContainers(): IPinnedViewContainer[] { @@ -642,6 +659,38 @@ export class PaneCompositeBar extends Disposable { private setStoredPlaceholderViewContainersValue(value: string): void { this.storageService.store(this.options.placeholderViewContainersKey, value, StorageScope.PROFILE, StorageTarget.MACHINE); } + + private getViewContainersWorkspaceState(): IViewContainerWorkspaceState[] { + return JSON.parse(this.viewContainersWorkspaceStateValue); + } + + private setViewContainersWorkspaceState(viewContainersWorkspaceState: IViewContainerWorkspaceState[]): void { + this.viewContainersWorkspaceStateValue = JSON.stringify(viewContainersWorkspaceState); + } + + private _viewContainersWorkspaceStateValue: string | undefined; + private get viewContainersWorkspaceStateValue(): string { + if (!this._viewContainersWorkspaceStateValue) { + this._viewContainersWorkspaceStateValue = this.getStoredViewContainersWorkspaceStateValue(); + } + + return this._viewContainersWorkspaceStateValue; + } + + private set viewContainersWorkspaceStateValue(viewContainersWorkspaceStateValue: string) { + if (this.viewContainersWorkspaceStateValue !== viewContainersWorkspaceStateValue) { + this._viewContainersWorkspaceStateValue = viewContainersWorkspaceStateValue; + this.setStoredViewContainersWorkspaceStateValue(viewContainersWorkspaceStateValue); + } + } + + private getStoredViewContainersWorkspaceStateValue(): string { + return this.storageService.get(this.options.viewContainersWorkspaceStateKey, StorageScope.WORKSPACE, '[]'); + } + + private setStoredViewContainersWorkspaceStateValue(value: string): void { + this.storageService.store(this.options.viewContainersWorkspaceStateKey, value, StorageScope.WORKSPACE, StorageTarget.MACHINE); + } } class ViewContainerActivityAction extends CompositeBarAction { diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index cd158dfcdba..aa0cba7df12 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -120,6 +120,7 @@ export class PanelPart extends AbstractPaneCompositePart { partContainerClass: 'panel', pinnedViewContainersKey: 'workbench.panel.pinnedPanels', placeholderViewContainersKey: 'workbench.panel.placeholderPanels', + viewContainersWorkspaceStateKey: 'workbench.panel.viewContainersWorkspaceState', icon: false, orientation: ActionsOrientation.HORIZONTAL, recomputeSizes: true, diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 17a010dfad8..fd1aaa43fb2 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -165,6 +165,7 @@ export class SidebarPart extends AbstractPaneCompositePart { partContainerClass: 'sidebar', pinnedViewContainersKey: ActivitybarPart.pinnedViewContainersKey, placeholderViewContainersKey: ActivitybarPart.placeholderViewContainersKey, + viewContainersWorkspaceStateKey: ActivitybarPart.viewContainersWorkspaceStateKey, icon: true, orientation: ActionsOrientation.HORIZONTAL, recomputeSizes: true, From 8f1f4595dd37c768adccb4060d8b02e364191a16 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 01:50:52 +0200 Subject: [PATCH 165/290] show number in the badge (#195744) --- .../browser/parts/compositeBarActions.ts | 27 +++++-------------- .../browser/parts/media/paneCompositePart.css | 12 ++++----- .../parts/titlebar/media/titlebarpart.css | 10 +++---- .../services/activity/common/activity.ts | 7 ----- 4 files changed, 17 insertions(+), 39 deletions(-) diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index b4dfa8fdc9f..161e0a84840 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -10,7 +10,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { toDisposable, DisposableStore, disposeIfDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService'; -import { TextBadge, NumberBadge, IBadge, IActivity, IconBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; +import { NumberBadge, IBadge, IActivity, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { DelayedDragHandler } from 'vs/base/browser/dnd'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -314,15 +314,15 @@ export class CompoisteBarActionViewItem extends BaseActionViewItem { classes.push('progress-badge'); } - else if (this.options.compact) { - show(this.badge); - } - // Number else if (badge instanceof NumberBadge) { if (badge.number) { let number = badge.number.toString(); - if (badge.number > 999) { + if (this.options.compact) { + if (badge.number > 99) { + number = ''; + } + } else if (badge.number > 999) { const noOfThousands = badge.number / 1000; const floor = Math.floor(noOfThousands); if (noOfThousands > floor) { @@ -336,19 +336,6 @@ export class CompoisteBarActionViewItem extends BaseActionViewItem { } } - // Text - else if (badge instanceof TextBadge) { - this.badgeContent.textContent = badge.text; - show(this.badge); - } - - // Icon - else if (badge instanceof IconBadge) { - const clazzList = ThemeIcon.asClassNameArray(badge.icon); - this.badgeContent.classList.add(...clazzList); - show(this.badge); - } - if (classes.length) { this.badge.classList.add(...classes); this.badgeDisposable.value = toDisposable(() => this.badge.classList.remove(...classes)); @@ -518,8 +505,6 @@ export class CompositeOverflowActivityActionViewItem extends CompoisteBarActionV let suffix: string | number | undefined; if (badge instanceof NumberBadge) { suffix = badge.number; - } else if (badge instanceof TextBadge) { - suffix = badge.text; } if (suffix) { diff --git a/src/vs/workbench/browser/parts/media/paneCompositePart.css b/src/vs/workbench/browser/parts/media/paneCompositePart.css index ee9abd7b981..f632aba96a8 100644 --- a/src/vs/workbench/browser/parts/media/paneCompositePart.css +++ b/src/vs/workbench/browser/parts/media/paneCompositePart.css @@ -173,20 +173,20 @@ .monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; top: 13px; - right: 2px; + right: 0px; font-size: 9px; font-weight: 600; - min-width: 10px; + min-width: 12px; height: 10px; - padding: 0 4px; + padding: 0 2px; border-radius: 16px; text-align: center; } .monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact.progress-badge .badge-content::before { - mask-size: 10px; - -webkit-mask-size: 10px; - top: 4px; + mask-size: 12px; + -webkit-mask-size: 12px; + top: 2px; } /* active item indicator */ diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 5325e70151d..4ab426c4c17 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -437,9 +437,9 @@ } .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content::before { - mask-size: 10px; - -webkit-mask-size: 10px; - top: 4px; + mask-size: 12px; + -webkit-mask-size: 12px; + top: 2px; } .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content { @@ -448,10 +448,10 @@ right: 0px; font-size: 9px; font-weight: 600; - min-width: 10px; + min-width: 12px; height: 10px; line-height: 10px; - padding: 0 4px; + padding: 0 2px; border-radius: 16px; text-align: center; } diff --git a/src/vs/workbench/services/activity/common/activity.ts b/src/vs/workbench/services/activity/common/activity.ts index 62f5150097b..d4707b5d695 100644 --- a/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -84,13 +84,6 @@ export class NumberBadge extends BaseBadge { } } -export class TextBadge extends BaseBadge { - - constructor(readonly text: string, descriptorFn: () => string) { - super(descriptorFn); - } -} - export class IconBadge extends BaseBadge { constructor(readonly icon: ThemeIcon, descriptorFn: () => string) { super(descriptorFn); From b605cb8aa9d826383b44e8529c2533c148d9c6f9 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Mon, 16 Oct 2023 17:05:23 -0700 Subject: [PATCH 166/290] Tweak follow up styles --- src/vs/workbench/contrib/chat/browser/media/chat.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 3ee1eba535f..6813766137b 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -303,7 +303,7 @@ .interactive-session-followups { display: flex; flex-direction: column; - gap: 8px; + gap: 6px; align-items: start; } @@ -344,8 +344,6 @@ .interactive-session-followups .monaco-button.interactive-followup-reply { padding: 0px; - font-size: 12px; - font-weight: 600; border: none; } From 89bfd062463149e795b64188d7994f2204c13d96 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Mon, 16 Oct 2023 17:09:49 -0700 Subject: [PATCH 167/290] Fix border radius --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 3ee1eba535f..54fe8f3b7df 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -434,7 +434,7 @@ .interactive-session .chat-used-context-list { border: 1px solid var(--vscode-chat-requestBorder); - border-radius: 3px; + border-radius: 4px; padding: 4px; } From f1c3b1dcf85e3b6ddb24b7dce0e4b122e8ce6233 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 16 Oct 2023 20:35:35 -0700 Subject: [PATCH 168/290] Move references list to the top (#195751) --- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 1f9dc7db688..9427302ee8d 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -221,8 +221,8 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer Date: Tue, 17 Oct 2023 15:31:39 +0900 Subject: [PATCH 169/290] chore: bump electron@25.9.1 (#195755) * chore: bump electron@25.9.1 * chore: bump distro --- .yarnrc | 4 ++-- build/checksums/electron.txt | 46 ++++++++++++++++++------------------ build/checksums/nodejs.txt | 1 - cgmanifest.json | 4 ++-- package.json | 4 ++-- yarn.lock | 8 +++---- 6 files changed, 33 insertions(+), 34 deletions(-) diff --git a/.yarnrc b/.yarnrc index b0814477f16..eb7739abf44 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,5 +1,5 @@ disturl "https://electronjs.org/headers" -target "25.8.4" -ms_build_id "24154031" +target "25.9.1" +ms_build_id "24472542" runtime "electron" build_from_source "true" diff --git a/build/checksums/electron.txt b/build/checksums/electron.txt index ff618fd4cc4..421b88a4fdb 100644 --- a/build/checksums/electron.txt +++ b/build/checksums/electron.txt @@ -1,23 +1,23 @@ -db3e9eb9f47f465bb63d15de486ea1d9274233b24bbe451038bfbaf48f9b0e39 *electron-v25.8.4-darwin-arm64-symbols.zip -5d83e2094a26bfe22e4c80e660ab088ec94ae3cc2d518c6efcac338f48cc0266 *electron-v25.8.4-darwin-arm64.zip -6fdd506328c65a9d8205425a463098210743c9ef79a546738b91a91d56100447 *electron-v25.8.4-darwin-x64-symbols.zip -d4015cd251e58ef074d1f7f3e99bfbbe4cd6b690981f376fc642b2de955e8750 *electron-v25.8.4-darwin-x64.zip -b46da627829a84cdf84b5570f95e044d38660fb0e58712757e834ff13b43c72d *electron-v25.8.4-linux-arm64-symbols.zip -fbb6e06417b1741b94d59a6de5dcf3262bfb3fc98cffbcad475296c42d1cbe94 *electron-v25.8.4-linux-arm64.zip -2569c260b4bb90894c5e63e175d3ee9665525e928d7c70158c6a9d98cb82f6a9 *electron-v25.8.4-linux-armv7l-symbols.zip -6301e6fde3e7c8149a5eca84c3817ba9ad3ffcb72e79318a355f025d7d3f8408 *electron-v25.8.4-linux-armv7l.zip -63580a081a4481eec2773606e9cd50c3468758741f11a14d6c47ab716c064896 *electron-v25.8.4-linux-x64-symbols.zip -0cbbcaf90f3dc79dedec97d073ffe954530316523479c31b11781a141f8a87f6 *electron-v25.8.4-linux-x64.zip -8860faaaabcc15a531733dd164c858a1cc1bffefdbba7ec54f7687db796f93f3 *electron-v25.8.4-win32-arm64-pdb.zip -e909628b4c984b3472c58b3897214e59f55ce69bee99229cdf1451a281865176 *electron-v25.8.4-win32-arm64-symbols.zip -1355293a73da3e5d3f06a6c95c81a5124c4f26be2ec1035ccfcfeccd4c766f5d *electron-v25.8.4-win32-arm64.zip -fef9e5ec4d146e6b310137140cee2a1172964e7584540088b1bc7fd1df15f1ff *electron-v25.8.4-win32-x64-pdb.zip -1227ec90ae2fb30e01d4c6814af1adae983b78ea832dea0520caaa8a05ac0390 *electron-v25.8.4-win32-x64-symbols.zip -0bbe72439cab1e72dee5fb850fdb1b17ea16fef61aa3dae93c562687737084f1 *electron-v25.8.4-win32-x64.zip -41e5b5392efcb1b47826f20e2f867dac6026dd435b92f50acb58bfae99b96e08 *ffmpeg-v25.8.4-darwin-arm64.zip -bad5ed7f10eef768c95a134cbd6754e9c347eb8bfae871e65975afb96cc49b86 *ffmpeg-v25.8.4-darwin-x64.zip -bd52d57ff97fb56ac01a3482af905d04f0d4e9c13c53858c6d9f99957eca82da *ffmpeg-v25.8.4-linux-arm64.zip -9b3d09177fa1e63e2a6beecfa70aeec30aeb5c1873ff21128a68051c4e23f95d *ffmpeg-v25.8.4-linux-armv7l.zip -edc7b1c9f1a0733f109a2c0375a4e40c5bfe0bf28b7f06dcc76e1ada0aa2f125 *ffmpeg-v25.8.4-linux-x64.zip -84ec373f124f628ce7d8964e000e79cd1448acec05b92417207baecf9b0f039a *ffmpeg-v25.8.4-win32-arm64.zip -7506346ff7a98377eca26464370a7c5a8c44d010d5c46a8357fa107980582fac *ffmpeg-v25.8.4-win32-x64.zip +4a472f48b54e92855ad77606f11a620523f3abe4ee1bc2997a300ae72da4b2f5 *electron-v25.9.1-darwin-arm64-symbols.zip +247daa6c9faf711162dc623832fcb189d3c1ef6a15884084cb45c8da3a037b6b *electron-v25.9.1-darwin-arm64.zip +7d8ec9d3272dbe356deb09b47ccfda30c421b32f7e906f1186ea26f894b22dc1 *electron-v25.9.1-darwin-x64-symbols.zip +35fc99808ea026a21afeca537c218ace398d299fba7ab73d2630be513f1e1617 *electron-v25.9.1-darwin-x64.zip +bfcd6ac66f067cfec08b6d18ed80b519e6d70a96d9b1d31dc2cfcf86f4a9af96 *electron-v25.9.1-linux-arm64-symbols.zip +1c8aa3f13ade23858664b687ad334634ccd698ec7d627554d16cbb596ffa7a0f *electron-v25.9.1-linux-arm64.zip +dcfb4a1d6b2ceffa7a8d9a60b9de027d006753eae1278f07de907c474e71c270 *electron-v25.9.1-linux-armv7l-symbols.zip +f4320f1888354e17595fb6901c03c383f45325bfba5e6e1b91b4200ff696049f *electron-v25.9.1-linux-armv7l.zip +772dd276d328549e0111b93b43d395de51ff46eba550be48c649c386997125a8 *electron-v25.9.1-linux-x64-symbols.zip +35529c411275791abf9aa46f0a2e216b0affa542757583afb438a76047f6b90c *electron-v25.9.1-linux-x64.zip +5b0b4595691da19258ce0b2c09f58ba969987d24ae8160661a715eaadf42c16b *electron-v25.9.1-win32-arm64-pdb.zip +1e67a35b41927962765a8d8cb01ce73e8c28db6453323f2661e63afd8fdf49e8 *electron-v25.9.1-win32-arm64-symbols.zip +a378f5fc44e872f05d037c3ca7f03802ed3a9b2611f59741ce933f500557af7c *electron-v25.9.1-win32-arm64.zip +b50f8675b12eda5d0717f83179e40b411ba3254f81bd7142821745c00b566560 *electron-v25.9.1-win32-x64-pdb.zip +8ddaa416e51bac1e93c63d1223bec37b6dd78b00c860e5b91912da09af7ff7b5 *electron-v25.9.1-win32-x64-symbols.zip +f6762a98193baa9877f443c9414b1f825f99b7cf1094be579d5202b72442b5be *electron-v25.9.1-win32-x64.zip +a0c2566efff0a796f751cfc63cddd52d6c4153b35b6ad582bbdd15a2c4317bc9 *ffmpeg-v25.9.1-darwin-arm64.zip +b8cd9d93cdf8ebbd3caf68581b6504529b8bf2dea984b6e5f637343ea9d61946 *ffmpeg-v25.9.1-darwin-x64.zip +bd52d57ff97fb56ac01a3482af905d04f0d4e9c13c53858c6d9f99957eca82da *ffmpeg-v25.9.1-linux-arm64.zip +9b3d09177fa1e63e2a6beecfa70aeec30aeb5c1873ff21128a68051c4e23f95d *ffmpeg-v25.9.1-linux-armv7l.zip +edc7b1c9f1a0733f109a2c0375a4e40c5bfe0bf28b7f06dcc76e1ada0aa2f125 *ffmpeg-v25.9.1-linux-x64.zip +2467f6567356340e8d9872753a3df486555334b7c868c0d12991f80f2353ce1f *ffmpeg-v25.9.1-win32-arm64.zip +fe4676a13bf9d6f87353f3496e0fb37cd3db151fcea13dad7610a2835d238062 *ffmpeg-v25.9.1-win32-x64.zip diff --git a/build/checksums/nodejs.txt b/build/checksums/nodejs.txt index de9f8f07150..7159352a1b2 100644 --- a/build/checksums/nodejs.txt +++ b/build/checksums/nodejs.txt @@ -4,4 +4,3 @@ bd302a689c3c34e2b61d86b97de66d26a335881a17af09b6a0a4bb1019df56e4 node-v18.15.0- ca2186313d3cbe5c67d0c08e931a6d290906f4f13c584e63fefa05a04dee9c58 node-v18.15.0-linux-armv7l.tar.gz b298a73a9fc07badfa9e4a2e86ed48824fc9201327cdc43e3f3f58b273c535e7 node-v18.15.0-linux-x64.tar.gz 17fd75d8a41bf9b4c475143e19ff2808afa7a92f7502ede731537d9da674d5e8 win-x64/node.exe -d78b2f981465a40a23b964b2db32a390db1970a0dd5371682e121ae2b7422697 win-x86/node.exe diff --git a/cgmanifest.json b/cgmanifest.json index 8cbbecf6915..2fa163fb7ba 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -528,12 +528,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "415301c477b600502cf264e93318dda551288829" + "commitHash": "805674fa8aae4d652b6956a96f8eadf9d9137457" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "25.8.4" + "version": "25.9.1" }, { "component": { diff --git a/package.json b/package.json index bfe56304cee..6301522d2f2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.84.0", - "distro": "ace645d011b7e53ba51e8d5ff153c47e3773b3d8", + "distro": "0f218422a902175f8b82cbf0f13fa4feb278f22a", "author": { "name": "Microsoft Corporation" }, @@ -150,7 +150,7 @@ "cssnano": "^4.1.11", "debounce": "^1.0.0", "deemon": "^1.8.0", - "electron": "25.8.4", + "electron": "25.9.1", "eslint": "8.36.0", "eslint-plugin-header": "3.1.1", "eslint-plugin-jsdoc": "^46.5.0", diff --git a/yarn.lock b/yarn.lock index 3e41e0812c9..6f519ddb78f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3518,10 +3518,10 @@ electron-to-chromium@^1.4.202: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.207.tgz#9c3310ebace2952903d05dcaba8abe3a4ed44c01" integrity sha512-piH7MJDJp4rJCduWbVvmUd59AUne1AFBJ8JaRQvk0KzNTSUnZrVXHCZc+eg+CGE4OujkcLJznhGKD6tuAshj5Q== -electron@25.8.4: - version "25.8.4" - resolved "https://registry.yarnpkg.com/electron/-/electron-25.8.4.tgz#b50877aac7d96323920437baf309ad86382cb455" - integrity sha512-hUYS3RGdaa6E1UWnzeGnsdsBYOggwMMg4WGxNGvAoWtmRrr6J1BsjFW/yRq4WsJHJce2HdzQXtz4OGXV6yUCLg== +electron@25.9.1: + version "25.9.1" + resolved "https://registry.yarnpkg.com/electron/-/electron-25.9.1.tgz#cc4baecbebe346b050b9cf9db9882d3d00fc4abd" + integrity sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ== dependencies: "@electron/get" "^2.0.0" "@types/node" "^18.11.18" From 6490e99d80eca60013b26041da9736b5fd43b5f5 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2023 01:46:56 -0700 Subject: [PATCH 170/290] Don't show suggestions for agent subcommand in an invalid spot after other text (#195752) And clean up the parser a little --- .../browser/contrib/chatInputEditorContrib.ts | 12 ++- .../contrib/chat/common/chatRequestParser.ts | 79 +++++++++--------- ..._agent_and_subcommand_after_newline.0.snap | 82 +++++++++++++++++++ ..._subcommand_with_leading_whitespace.0.snap | 82 +++++++++++++++++++ .../ChatRequestParser_agent_not_first.0.snap | 62 +------------- ...r_agent_with_subcommand_after_text.0.snap} | 32 +------- ..._and_variables_and_multiline__part2.0.snap | 32 +------- .../test/common/chatRequestParser.test.ts | 24 +++++- 8 files changed, 243 insertions(+), 162 deletions(-) create mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap create mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap rename src/vs/workbench/contrib/chat/test/common/__snapshots__/{ChatRequestParser_agents.0.snap => ChatRequestParser_agent_with_subcommand_after_text.0.snap} (55%) diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index cb000e55f38..e6d57bf6efb 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -374,8 +374,8 @@ class AgentCompletions extends Disposable { } const parsedRequest = (await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(widget.viewModel.sessionId, model.getValue())).parts; - const usedAgent = parsedRequest.find((p): p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart); - if (!usedAgent) { + const usedAgentIdx = parsedRequest.findIndex((p): p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart); + if (usedAgentIdx < 0) { return; } @@ -385,6 +385,14 @@ class AgentCompletions extends Disposable { return; } + for (const partAfterAgent of parsedRequest.slice(usedAgentIdx + 1)) { + if (!(partAfterAgent instanceof ChatRequestTextPart) || !partAfterAgent.text.match(/^\s+(\/\w*)?$/)) { + // No text allowed between agent and subcommand + return; + } + } + + const usedAgent = parsedRequest[usedAgentIdx] as ChatRequestAgentPart; const commands = await usedAgent.agent.provideSlashCommands(token); return { diff --git a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts index 6b322bdea63..9491e40cf77 100644 --- a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts +++ b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts @@ -7,7 +7,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { OffsetRange } from 'vs/editor/common/core/offsetRange'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicReferencePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, IParsedChatRequest, IParsedChatRequestPart, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables'; @@ -33,14 +33,14 @@ export class ChatRequestParser { const previousChar = message.charAt(i - 1); const char = message.charAt(i); let newPart: IParsedChatRequestPart | undefined; - if (previousChar === ' ' || i === 0) { + if (previousChar.match(/\s/) || i === 0) { if (char === chatVariableLeader) { newPart = this.tryToParseVariable(message.slice(i), i, new Position(lineNumber, column), parts); } else if (char === '@') { - newPart = this.tryToParseAgent(message.slice(i), i, new Position(lineNumber, column), parts); + newPart = this.tryToParseAgent(message.slice(i), message, i, new Position(lineNumber, column), parts); } else if (char === '/') { // TODO try to make this sync - newPart = await this.tryToParseSlashCommand(sessionId, message.slice(i), i, new Position(lineNumber, column), parts); + newPart = await this.tryToParseSlashCommand(sessionId, message.slice(i), message, i, new Position(lineNumber, column), parts); } else if (char === '$') { newPart = await this.tryToParseDynamicVariable(sessionId, message.slice(i), i, new Position(lineNumber, column), parts); } @@ -79,36 +79,13 @@ export class ChatRequestParser { message.slice(lastPartEnd, message.length))); } - - // fix up parts: - // * only one agent at the beginning of the message - // * only one agent command after the agent or at the beginning of the message - let agentIndex = -1; - for (let i = 0; i < parts.length; i++) { - const part = parts[i]; - if (part instanceof ChatRequestAgentPart) { - if (i === 0) { - agentIndex = 0; - } else { - // agent not first -> make text part - parts[i] = new ChatRequestTextPart(part.range, part.editorRange, part.text); - } - } - if (part instanceof ChatRequestAgentSubcommandPart) { - if (!(i === 0 || agentIndex === 0 && i === 2 && /^\s+$/.test(parts[1].text))) { - // agent command not after agent nor first -> make text part - parts[i] = new ChatRequestTextPart(part.range, part.editorRange, part.text); - } - } - } - return { parts, text: message, }; } - private tryToParseAgent(message: string, offset: number, position: IPosition, parts: ReadonlyArray): ChatRequestAgentPart | ChatRequestVariablePart | undefined { + private tryToParseAgent(message: string, fullMessage: string, offset: number, position: IPosition, parts: ReadonlyArray): ChatRequestAgentPart | ChatRequestVariablePart | undefined { const nextVariableMatch = message.match(agentReg); if (!nextVariableMatch) { return; @@ -118,17 +95,29 @@ export class ChatRequestParser { const varRange = new OffsetRange(offset, offset + full.length); const varEditorRange = new Range(position.lineNumber, position.column, position.lineNumber, position.column + full.length); - let agent: IChatAgent | undefined; - if ((agent = this.agentService.getAgent(name))) { - if (parts.some(p => p instanceof ChatRequestAgentPart)) { - // Only one agent allowed - return; - } else { - return new ChatRequestAgentPart(varRange, varEditorRange, agent); - } + const agent = this.agentService.getAgent(name); + if (!agent) { + return; } - return; + if (parts.some(p => p instanceof ChatRequestAgentPart)) { + // Only one agent allowed + return; + } + + // The agent must come first + if (parts.some(p => (p instanceof ChatRequestTextPart && p.text.trim() !== '') || !(p instanceof ChatRequestAgentPart))) { + return; + } + + const previousPart = parts.at(-1); + const previousPartEnd = previousPart?.range.endExclusive ?? 0; + const textSincePreviousPart = fullMessage.slice(previousPartEnd, offset); + if (textSincePreviousPart.trim() !== '') { + return; + } + + return new ChatRequestAgentPart(varRange, varEditorRange, agent); } private tryToParseVariable(message: string, offset: number, position: IPosition, parts: ReadonlyArray): ChatRequestAgentPart | ChatRequestVariablePart | undefined { @@ -149,8 +138,8 @@ export class ChatRequestParser { return; } - private async tryToParseSlashCommand(sessionId: string, message: string, offset: number, position: IPosition, parts: ReadonlyArray): Promise { - const nextSlashMatch = message.match(slashReg); + private async tryToParseSlashCommand(sessionId: string, remainingMessage: string, fullMessage: string, offset: number, position: IPosition, parts: ReadonlyArray): Promise { + const nextSlashMatch = remainingMessage.match(slashReg); if (!nextSlashMatch) { return; } @@ -166,6 +155,18 @@ export class ChatRequestParser { const usedAgent = parts.find((p): p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart); if (usedAgent) { + // The slash command must come immediately after the agent + if (parts.some(p => (p instanceof ChatRequestTextPart && p.text.trim() !== '') || !(p instanceof ChatRequestAgentPart) && !(p instanceof ChatRequestTextPart))) { + return; + } + + const previousPart = parts.at(-1); + const previousPartEnd = previousPart?.range.endExclusive ?? 0; + const textSincePreviousPart = fullMessage.slice(previousPartEnd, offset); + if (textSincePreviousPart.trim() !== '') { + return; + } + const subCommands = await usedAgent.agent.provideSlashCommands(CancellationToken.None); const subCommand = subCommands.find(c => c.name === command); if (subCommand) { diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap new file mode 100644 index 00000000000..7a73d008baa --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap @@ -0,0 +1,82 @@ +{ + parts: [ + { + range: { + start: 0, + endExclusive: 5 + }, + editorRange: { + startLineNumber: 1, + startColumn: 1, + endLineNumber: 2, + endColumn: 1 + }, + text: " \n", + kind: "text" + }, + { + range: { + start: 5, + endExclusive: 11 + }, + editorRange: { + startLineNumber: 2, + startColumn: 1, + endLineNumber: 2, + endColumn: 7 + }, + agent: { + id: "agent", + metadata: { description: "" }, + provideSlashCommands: [Function provideSlashCommands] + }, + kind: "agent" + }, + { + range: { + start: 11, + endExclusive: 12 + }, + editorRange: { + startLineNumber: 2, + startColumn: 7, + endLineNumber: 3, + endColumn: 1 + }, + text: "\n", + kind: "text" + }, + { + range: { + start: 12, + endExclusive: 23 + }, + editorRange: { + startLineNumber: 3, + startColumn: 1, + endLineNumber: 3, + endColumn: 12 + }, + command: { + name: "subCommand", + description: "" + }, + kind: "subcommand" + }, + { + range: { + start: 23, + endExclusive: 30 + }, + editorRange: { + startLineNumber: 3, + startColumn: 12, + endLineNumber: 3, + endColumn: 19 + }, + text: " Thanks", + kind: "text" + } + ], + text: " \n@agent\n/subCommand Thanks" +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap new file mode 100644 index 00000000000..ccd7eb870e0 --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap @@ -0,0 +1,82 @@ +{ + parts: [ + { + range: { + start: 0, + endExclusive: 10 + }, + editorRange: { + startLineNumber: 1, + startColumn: 1, + endLineNumber: 2, + endColumn: 5 + }, + text: " \r\n\t ", + kind: "text" + }, + { + range: { + start: 10, + endExclusive: 16 + }, + editorRange: { + startLineNumber: 2, + startColumn: 5, + endLineNumber: 2, + endColumn: 11 + }, + agent: { + id: "agent", + metadata: { description: "" }, + provideSlashCommands: [Function provideSlashCommands] + }, + kind: "agent" + }, + { + range: { + start: 16, + endExclusive: 23 + }, + editorRange: { + startLineNumber: 2, + startColumn: 11, + endLineNumber: 3, + endColumn: 5 + }, + text: " \r\n\t ", + kind: "text" + }, + { + range: { + start: 23, + endExclusive: 34 + }, + editorRange: { + startLineNumber: 3, + startColumn: 5, + endLineNumber: 3, + endColumn: 16 + }, + command: { + name: "subCommand", + description: "" + }, + kind: "subcommand" + }, + { + range: { + start: 34, + endExclusive: 41 + }, + editorRange: { + startLineNumber: 3, + startColumn: 16, + endLineNumber: 3, + endColumn: 23 + }, + text: " Thanks", + kind: "text" + } + ], + text: " \r\n\t @agent \r\n\t /subCommand Thanks" +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap index 0ac17204ee0..29c85351e95 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_not_first.0.snap @@ -3,73 +3,17 @@ { range: { start: 0, - endExclusive: 10 + endExclusive: 16 }, editorRange: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, - endColumn: 11 - }, - text: "Hello Mr. ", - kind: "text" - }, - { - range: { - start: 10, - endExclusive: 16 - }, - editorRange: { - startLineNumber: 1, - startColumn: 11, - endLineNumber: 1, endColumn: 17 }, - text: "@agent", - kind: "text" - }, - { - range: { - start: 16, - endExclusive: 17 - }, - editorRange: { - startLineNumber: 1, - startColumn: 17, - endLineNumber: 1, - endColumn: 18 - }, - text: " ", - kind: "text" - }, - { - range: { - start: 17, - endExclusive: 28 - }, - editorRange: { - startLineNumber: 1, - startColumn: 18, - endLineNumber: 1, - endColumn: 29 - }, - text: "/subCommand", - kind: "text" - }, - { - range: { - start: 28, - endExclusive: 35 - }, - editorRange: { - startLineNumber: 1, - startColumn: 29, - endLineNumber: 1, - endColumn: 36 - }, - text: " thanks", + text: "Hello Mr. @agent", kind: "text" } ], - text: "Hello Mr. @agent /subCommand thanks" + text: "Hello Mr. @agent" } \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_subcommand_after_text.0.snap similarity index 55% rename from src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents.0.snap rename to src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_subcommand_after_text.0.snap index 8a83800323f..b1954f78a47 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_subcommand_after_text.0.snap @@ -21,43 +21,15 @@ { range: { start: 6, - endExclusive: 17 + endExclusive: 35 }, editorRange: { startLineNumber: 1, startColumn: 7, endLineNumber: 1, - endColumn: 18 - }, - text: " Please do ", - kind: "text" - }, - { - range: { - start: 17, - endExclusive: 28 - }, - editorRange: { - startLineNumber: 1, - startColumn: 18, - endLineNumber: 1, - endColumn: 29 - }, - text: "/subCommand", - kind: "text" - }, - { - range: { - start: 28, - endExclusive: 35 - }, - editorRange: { - startLineNumber: 1, - startColumn: 29, - endLineNumber: 1, endColumn: 36 }, - text: " thanks", + text: " Please do /subCommand thanks", kind: "text" } ], diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap index 3708cf78541..310f36005b3 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap @@ -21,43 +21,15 @@ { range: { start: 6, - endExclusive: 18 + endExclusive: 35 }, editorRange: { startLineNumber: 1, startColumn: 7, endLineNumber: 2, - endColumn: 4 - }, - text: " Please \ndo ", - kind: "text" - }, - { - range: { - start: 18, - endExclusive: 29 - }, - editorRange: { - startLineNumber: 2, - startColumn: 4, - endLineNumber: 2, - endColumn: 15 - }, - text: "/subCommand", - kind: "text" - }, - { - range: { - start: 29, - endExclusive: 35 - }, - editorRange: { - startLineNumber: 2, - startColumn: 15, - endLineNumber: 2, endColumn: 21 }, - text: " with ", + text: " Please \ndo /subCommand with ", kind: "text" }, { diff --git a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts index 78317a10496..f3e56c5ff02 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts @@ -109,7 +109,7 @@ suite('ChatRequestParser', () => { await assertSnapshot(result); }); - test('agents', async () => { + test('agent with subcommand after text', async () => { const agentsService = mockObject()({}); agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); instantiationService.stub(IChatAgentService, agentsService as any); @@ -139,13 +139,33 @@ suite('ChatRequestParser', () => { await assertSnapshot(result); }); + test('agent and subcommand with leading whitespace', async () => { + const agentsService = mockObject()({}); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); + instantiationService.stub(IChatAgentService, agentsService as any); + + parser = instantiationService.createInstance(ChatRequestParser); + const result = await parser.parseChatRequest('1', ' \r\n\t @agent \r\n\t /subCommand Thanks'); + await assertSnapshot(result); + }); + + test('agent and subcommand after newline', async () => { + const agentsService = mockObject()({}); + agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); + instantiationService.stub(IChatAgentService, agentsService as any); + + parser = instantiationService.createInstance(ChatRequestParser); + const result = await parser.parseChatRequest('1', ' \n@agent\n/subCommand Thanks'); + await assertSnapshot(result); + }); + test('agent not first', async () => { const agentsService = mockObject()({}); agentsService.getAgent.returns(>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => { return [{ name: 'subCommand', description: '' }]; } }); instantiationService.stub(IChatAgentService, agentsService as any); parser = instantiationService.createInstance(ChatRequestParser); - const result = await parser.parseChatRequest('1', 'Hello Mr. @agent /subCommand thanks'); + const result = await parser.parseChatRequest('1', 'Hello Mr. @agent'); await assertSnapshot(result); }); From 74d99c24f0d9858d018568b43e52d89936446bbd Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 10:52:48 +0200 Subject: [PATCH 171/290] use existing state for missing view containers (#195764) - these could be enabled in workspace --- src/vs/workbench/browser/parts/paneCompositeBar.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/parts/paneCompositeBar.ts b/src/vs/workbench/browser/parts/paneCompositeBar.ts index 73d02bedaad..6f53db7149e 100644 --- a/src/vs/workbench/browser/parts/paneCompositeBar.ts +++ b/src/vs/workbench/browser/parts/paneCompositeBar.ts @@ -502,9 +502,9 @@ export class PaneCompositeBar extends Disposable { newCompositeItems.push({ id: viewContainer.id, name: typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.value, - order: viewContainer.order, - pinned: e.external ? true : compositeItem?.pinned ?? true, - visible: e.external ? !this.shouldBeHidden(viewContainer) : compositeItem?.visible ?? true, + order: compositeItem?.order ?? viewContainer.order, + pinned: compositeItem?.pinned ?? true, + visible: compositeItem?.visible ?? !this.shouldBeHidden(viewContainer), }); } } From 1fd04d02ee5d95eca37dda4c838ed03c64af68e1 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 10:52:57 +0200 Subject: [PATCH 172/290] fix cumulative number badge (#195765) --- src/vs/workbench/browser/parts/globalCompositeBar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/globalCompositeBar.ts b/src/vs/workbench/browser/parts/globalCompositeBar.ts index f7391720341..808ffa8645d 100644 --- a/src/vs/workbench/browser/parts/globalCompositeBar.ts +++ b/src/vs/workbench/browser/parts/globalCompositeBar.ts @@ -195,7 +195,7 @@ abstract class AbstractGlobalActivityActionViewItem extends CompoisteBarActionVi } private getCumulativeNumberBadge(activityCache: IActivity[], priority: number): NumberBadge { - const numberActivities = activityCache.filter(activity => activity.badge instanceof NumberBadge && activity.priority === priority); + const numberActivities = activityCache.filter(activity => activity.badge instanceof NumberBadge && (activity.priority ?? 0) === priority); const number = numberActivities.reduce((result, activity) => { return result + (activity.badge).number; }, 0); const descriptorFn = (): string => { return numberActivities.reduce((result, activity, index) => { From 2d531738cb43ef7cd8a0b4754743f13a061ad14e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 11:12:15 +0200 Subject: [PATCH 173/290] polish compact badge (#195763) --- src/vs/workbench/browser/parts/media/paneCompositePart.css | 4 ++-- .../workbench/browser/parts/titlebar/media/titlebarpart.css | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/parts/media/paneCompositePart.css b/src/vs/workbench/browser/parts/media/paneCompositePart.css index f632aba96a8..0006a43986d 100644 --- a/src/vs/workbench/browser/parts/media/paneCompositePart.css +++ b/src/vs/workbench/browser/parts/media/paneCompositePart.css @@ -172,12 +172,12 @@ .monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; - top: 13px; + top: 11px; right: 0px; font-size: 9px; font-weight: 600; min-width: 12px; - height: 10px; + height: 12px; padding: 0 2px; border-radius: 16px; text-align: center; diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 4ab426c4c17..5109fdeaf92 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -444,13 +444,12 @@ .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; - top: 12px; + top: 10px; right: 0px; font-size: 9px; font-weight: 600; min-width: 12px; - height: 10px; - line-height: 10px; + height: 12px; padding: 0 2px; border-radius: 16px; text-align: center; From d84904c1a96ad46354f59a02a828e1e49d50b929 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 Oct 2023 12:14:23 +0200 Subject: [PATCH 174/290] add support for follow-up actions as `onDidPerformAction` (#195777) --- .../api/common/extHostChatAgents2.ts | 2 +- .../contrib/chat/browser/chatInputPart.ts | 7 +++--- .../contrib/chat/browser/chatWidget.ts | 22 ++++++++++++++----- .../contrib/chat/common/chatService.ts | 7 +++++- ...scode.proposed.interactiveUserActions.d.ts | 8 ++++++- 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 22849d610cf..3e30a121e20 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -173,7 +173,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { // handled by $acceptFeedback return; } - agent.acceptAction(Object.freeze({ action: action.action, result })); + agent.acceptAction(Object.freeze({ action: action.action as any, result })); } } diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 55116ec3aa5..7576aadb922 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -36,6 +36,7 @@ import { isMacintosh } from 'vs/base/common/platform'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { ModesHoverController } from 'vs/editor/contrib/hover/browser/hover'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { IChatResponseViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel'; const $ = dom.$; @@ -54,7 +55,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge private _onDidBlur = this._register(new Emitter()); readonly onDidBlur = this._onDidBlur.event; - private _onDidAcceptFollowup = this._register(new Emitter()); + private _onDidAcceptFollowup = this._register(new Emitter<{ followup: IChatReplyFollowup; response: IChatResponseViewModel | undefined }>()); readonly onDidAcceptFollowup = this._onDidAcceptFollowup.event; private inputEditorHeight = 0; @@ -271,7 +272,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } } - async renderFollowups(items?: IChatReplyFollowup[]): Promise { + async renderFollowups(items: IChatReplyFollowup[] | undefined, response: IChatResponseViewModel | undefined): Promise { if (!this.options.renderFollowups) { return; } @@ -279,7 +280,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge dom.clearNode(this.followupsContainer); if (items && items.length > 0) { - this.followupsDisposables.add(new ChatFollowups(this.followupsContainer, items, undefined, followup => this._onDidAcceptFollowup.fire(followup), this.contextKeyService)); + this.followupsDisposables.add(new ChatFollowups(this.followupsContainer, items, undefined, followup => this._onDidAcceptFollowup.fire({ followup, response }), this.contextKeyService)); } } diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 3df91a83aa5..30ca4ca5734 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -265,7 +265,7 @@ export class ChatWidget extends Disposable implements IChatWidget { const lastItem = treeItems[treeItems.length - 1]?.element; if (lastItem && isResponseVM(lastItem) && lastItem.isComplete) { - this.renderFollowups(lastItem.replyFollowups); + this.renderFollowups(lastItem.replyFollowups, lastItem); } else if (lastItem && isWelcomeVM(lastItem)) { this.renderFollowups(lastItem.sampleQuestions); } else { @@ -274,8 +274,8 @@ export class ChatWidget extends Disposable implements IChatWidget { } } - private async renderFollowups(items?: IChatReplyFollowup[]): Promise { - this.inputPart.renderFollowups(items); + private async renderFollowups(items: IChatReplyFollowup[] | undefined, response?: IChatResponseViewModel): Promise { + this.inputPart.renderFollowups(items, response); if (this.bodyDimension) { this.layout(this.bodyDimension.height, this.bodyDimension.width); @@ -411,9 +411,21 @@ export class ChatWidget extends Disposable implements IChatWidget { this.inputPart.render(container, '', this); this._register(this.inputPart.onDidFocus(() => this._onDidFocus.fire())); - this._register(this.inputPart.onDidAcceptFollowup(followup => { + this._register(this.inputPart.onDidAcceptFollowup(e => { // this.chatService.notifyUserAction - this.acceptInput(followup.message); + if (!this.viewModel) { + return; + } + this.chatService.notifyUserAction({ + providerId: this.viewModel.providerId, + sessionId: this.viewModel.sessionId, + agentId: e.response?.agent?.id, + action: { + kind: 'followUp', + followup: e.followup + }, + }); + this.acceptInput(e.followup.message); })); this._register(this.inputPart.onDidChangeHeight(() => this.bodyDimension && this.layout(this.bodyDimension.height, this.bodyDimension.width))); } diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 356cbe6ab58..bb52eeaceef 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -210,7 +210,12 @@ export interface IChatCommandAction { command: IChatResponseCommandFollowup; } -export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatTerminalAction | IChatCommandAction; +export interface IChatFollowupAction { + kind: 'followUp'; + followup: IChatFollowup; +} + +export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction; export interface IChatUserActionEvent { action: ChatUserAction; diff --git a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts index b0b662decc9..4232e8b36b7 100644 --- a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts +++ b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts @@ -61,7 +61,13 @@ declare module 'vscode' { command: InteractiveResponseCommand; } - export type InteractiveSessionUserAction = InteractiveSessionVoteAction | InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction; + export interface InteractiveSessionFollowupAction { + // eslint-disable-next-line local/vscode-dts-string-type-literals + kind: 'followUp'; + followup: InteractiveSessionFollowup; + } + + export type InteractiveSessionUserAction = InteractiveSessionVoteAction | InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction | InteractiveSessionFollowupAction; export interface InteractiveSessionUserActionEvent { action: InteractiveSessionUserAction; From 9eca5219a30366bec8d6cd68cbca3342a675f07d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 12:25:02 +0200 Subject: [PATCH 175/290] fix #195776 (#195779) --- .../workbench/browser/parts/compositeBar.ts | 3 +-- .../browser/parts/paneCompositeBar.ts | 27 +++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 04403ef1a22..c7711d30555 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -683,8 +683,7 @@ class CompositeBarModel { setItems(items: ICompositeBarItem[]): void { this._items = []; this._items = items - .map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.visible)) - .sort((a, b) => (a.order ?? items.length) - (b.order ?? items.length)); + .map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.visible)); } get visibleItems(): ICompositeBarModelItem[] { diff --git a/src/vs/workbench/browser/parts/paneCompositeBar.ts b/src/vs/workbench/browser/parts/paneCompositeBar.ts index 6f53db7149e..02f606e4349 100644 --- a/src/vs/workbench/browser/parts/paneCompositeBar.ts +++ b/src/vs/workbench/browser/parts/paneCompositeBar.ts @@ -498,14 +498,25 @@ export class PaneCompositeBar extends Disposable { for (const viewContainer of this.getViewContainers()) { // Add missing view containers if (!newCompositeItems.some(({ id }) => id === viewContainer.id)) { - const compositeItem = compositeItems.find(({ id }) => id === viewContainer.id); - newCompositeItems.push({ - id: viewContainer.id, - name: typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.value, - order: compositeItem?.order ?? viewContainer.order, - pinned: compositeItem?.pinned ?? true, - visible: compositeItem?.visible ?? !this.shouldBeHidden(viewContainer), - }); + const index = compositeItems.findIndex(({ id }) => id === viewContainer.id); + if (index !== -1) { + const compositeItem = compositeItems[index]; + newCompositeItems.splice(index, 0, { + id: viewContainer.id, + name: typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.value, + order: compositeItem.order, + pinned: compositeItem.pinned, + visible: compositeItem.visible, + }); + } else { + newCompositeItems.push({ + id: viewContainer.id, + name: typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.value, + order: viewContainer.order, + pinned: true, + visible: !this.shouldBeHidden(viewContainer), + }); + } } } From 4e57a268640b97140795eb7dc7046f6b7263dedc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Oct 2023 13:10:22 +0200 Subject: [PATCH 176/290] fetch if current version is not latest (#195790) --- .../workbench/contrib/extensions/browser/extensionsActions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index d426590f0da..37438e01b38 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -1283,7 +1283,8 @@ export class InstallAnotherVersionAction extends ExtensionAction { } try { if (pick.latest) { - await this.extensionsWorkbenchService.install(this.extension!, { installPreReleaseVersion: pick.isPreReleaseVersion }); + const [extension] = pick.id !== this.extension?.version ? await this.extensionsWorkbenchService.getExtensions([{ id: this.extension!.identifier.id, preRelease: pick.isPreReleaseVersion }], CancellationToken.None) : [this.extension]; + await this.extensionsWorkbenchService.install(extension ?? this.extension!, { installPreReleaseVersion: pick.isPreReleaseVersion }); } else { await this.extensionsWorkbenchService.installVersion(this.extension!, pick.id, { installPreReleaseVersion: pick.isPreReleaseVersion }); } From 75a6f715b843e4f5ca51022ec0d811d64157fb6b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 17 Oct 2023 14:01:35 +0200 Subject: [PATCH 177/290] Fix forced type assertion (#195788) --- src/vs/workbench/api/common/extHostChatAgents2.ts | 2 +- src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts | 2 +- src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 3e30a121e20..22849d610cf 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -173,7 +173,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { // handled by $acceptFeedback return; } - agent.acceptAction(Object.freeze({ action: action.action as any, result })); + agent.acceptAction(Object.freeze({ action: action.action, result })); } } diff --git a/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts b/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts index 4b98979813c..edbb44415ef 100644 --- a/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts +++ b/src/vscode-dts/vscode.proposed.chatAgents2Additions.d.ts @@ -7,7 +7,7 @@ declare module 'vscode' { export interface ChatAgentUserActionEvent { readonly result: ChatAgentResult2; - readonly action: InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction; + readonly action: InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction | InteractiveSessionFollowupAction; } export interface ChatAgentContent { diff --git a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts index 4232e8b36b7..f9b400c1d94 100644 --- a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts +++ b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts @@ -67,7 +67,7 @@ declare module 'vscode' { followup: InteractiveSessionFollowup; } - export type InteractiveSessionUserAction = InteractiveSessionVoteAction | InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction | InteractiveSessionFollowupAction; + export type InteractiveSessionUserAction = InteractiveSessionVoteAction | InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction; export interface InteractiveSessionUserActionEvent { action: InteractiveSessionUserAction; From d8ec7cef51db5101a15ee07caecf52599662db74 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2023 06:34:14 +0200 Subject: [PATCH 178/290] aux window - null window on dispose --- .../auxiliaryWindow/electron-main/auxiliaryWindow.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts index b2715f1b555..28cb3aafdd0 100644 --- a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts +++ b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts @@ -78,4 +78,10 @@ export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow { this._lastFocusTime = Date.now(); }); } + + override dispose(): void { + super.dispose(); + + this._win = null!; // Important to dereference the window object to allow for GC + } } From d1986ba985b53dd156d5c740ed1e66a701b7ce3a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2023 07:03:09 +0200 Subject: [PATCH 179/290] aux window - move some methods to be `IEditorPart` only --- .../api/browser/mainThreadEditorTabs.ts | 2 +- src/vs/workbench/browser/contextkeys.ts | 2 +- src/vs/workbench/browser/layout.ts | 10 +- .../browser/parts/editor/editorParts.ts | 42 ++--- .../browser/parts/editor/editorsObserver.ts | 2 +- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../services/notebookEditorServiceImpl.ts | 2 +- .../contrib/splash/browser/partsSplash.ts | 2 +- .../webviewPanel/browser/webviewEditor.ts | 8 +- .../browser/webviewPanel.contribution.ts | 2 +- .../browser/gettingStarted.ts | 4 +- .../services/editor/browser/editorService.ts | 2 +- .../editor/common/editorGroupsService.ts | 148 ++++++++++-------- .../history/browser/historyService.ts | 4 +- .../test/browser/workbenchTestServices.ts | 5 + 15 files changed, 123 insertions(+), 114 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadEditorTabs.ts b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts index 3da6c5ed51d..9fc8e3d4667 100644 --- a/src/vs/workbench/api/browser/mainThreadEditorTabs.ts +++ b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts @@ -69,7 +69,7 @@ export class MainThreadEditorTabs implements MainThreadEditorTabsShape { this._dispoables.add(this._editorGroupsService.onDidRemoveGroup(() => this._createTabsModel())); // Once everything is read go ahead and initialize the model - this._editorGroupsService.whenReady.then(() => this._createTabsModel()); + this._editorGroupsService.mainPart.whenReady.then(() => this._createTabsModel()); } dispose(): void { diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index c77d98a5758..5c5ce04ad09 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -218,7 +218,7 @@ export class WorkbenchContextKeysHandler extends Disposable { } private registerListeners(): void { - this.editorGroupService.whenReady.then(() => { + this.editorGroupService.mainPart.whenReady.then(() => { this.updateEditorAreaContextKeys(); this.updateEditorContextKeys(); }); diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 4f33c7fc37d..f14c67db2cc 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -281,7 +281,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Wait to register these listeners after the editor group service // is ready to avoid conflicts on startup - this.editorGroupService.whenRestored.then(() => { + this.editorGroupService.mainPart.whenRestored.then(() => { // Restore editor part on any editor change this._register(this.editorService.onDidVisibleEditorsChange(showEditorIfHidden)); @@ -404,7 +404,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.updateMenubarVisibility(!!skipLayout); // Centered Layout - this.editorGroupService.whenRestored.then(() => { + this.editorGroupService.mainPart.whenRestored.then(() => { this.centerEditorLayout(this.stateModel.getRuntimeValue(LayoutStateKeys.EDITOR_CENTERED), skipLayout); }); } @@ -688,7 +688,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Empty workbench configured to open untitled file if empty else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.configurationService.getValue('workbench.startupEditor') === 'newUntitledFile') { - if (this.editorGroupService.hasRestorableState) { + if (this.editorGroupService.mainPart.hasRestorableState) { return []; // do not open any empty untitled file if we restored groups/editors from previous session } @@ -761,7 +761,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi mark('code/willRestoreEditors'); // first ensure the editor part is ready - await this.editorGroupService.whenReady; + await this.editorGroupService.mainPart.whenReady; mark('code/restoreEditors/editorGroupsReady'); // apply editor layout if any @@ -817,7 +817,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi layoutRestoredPromises.push( Promise.all([ openEditorsPromise?.finally(() => mark('code/restoreEditors/editorsOpened')), - this.editorGroupService.whenRestored.finally(() => mark('code/restoreEditors/editorGroupsRestored')) + this.editorGroupService.mainPart.whenRestored.finally(() => mark('code/restoreEditors/editorGroupsRestored')) ]).finally(() => { // the `code/didRestoreEditors` perf mark is specifically // for when visible editors have resolved, so we only mark diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 492b8c63b76..20d39b64adc 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -5,7 +5,7 @@ import { EditorGroupLayout, GroupDirection, GroupOrientation, GroupsArrangement, GroupsOrder, IAuxiliaryEditorPart, IEditorDropTargetDelegate, IEditorGroupsService, IEditorSideGroup, IFindGroupScope, IMergeGroupOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { Event, Emitter } from 'vs/base/common/event'; -import { IDimension, getActiveDocument } from 'vs/base/browser/dom'; +import { getActiveDocument } from 'vs/base/browser/dom'; import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { GroupIdentifier, IEditorPartOptions } from 'vs/workbench/common/editor'; import { AuxiliaryEditorPart, EditorPart, MainEditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; @@ -19,7 +19,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd declare readonly _serviceBrand: undefined; - private readonly mainEditorPart = this._register(this.createMainEditorPart()); + readonly mainPart = this._register(this.createMainEditorPart()); constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -28,7 +28,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd ) { super(); - this._register(this.registerEditorPart(this.mainEditorPart)); + this._register(this.registerEditorPart(this.mainPart)); } protected createMainEditorPart(): MainEditorPart { @@ -94,9 +94,6 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd disposables.add(part.onDidMoveGroup(group => this._onDidMoveGroup.fire(group))); disposables.add(part.onDidActivateGroup(group => this._onDidActivateGroup.fire(group))); - disposables.add(part.onDidLayout(dimension => this._onDidLayout.fire(dimension))); - disposables.add(part.onDidScroll(() => this._onDidScroll.fire())); - disposables.add(part.onDidChangeGroupIndex(group => this._onDidChangeGroupIndex.fire(group))); disposables.add(part.onDidChangeGroupLocked(group => this._onDidChangeGroupLocked.fire(group))); } @@ -118,12 +115,12 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd } } - return this.mainEditorPart; + return this.mainPart; } - private getPart(group: IEditorGroupView | GroupIdentifier): EditorPart; - private getPart(element: HTMLElement): EditorPart; - private getPart(groupOrElement: IEditorGroupView | GroupIdentifier | HTMLElement): EditorPart { + getPart(group: IEditorGroupView | GroupIdentifier): EditorPart; + getPart(element: HTMLElement): EditorPart; + getPart(groupOrElement: IEditorGroupView | GroupIdentifier | HTMLElement): EditorPart { if (this.parts.size > 1) { if (groupOrElement instanceof HTMLElement) { const element = groupOrElement; @@ -147,7 +144,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd } } - return this.mainEditorPart; + return this.mainPart; } //#endregion @@ -169,12 +166,6 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd private readonly _onDidActivateGroup = this._register(new Emitter()); readonly onDidActivateGroup = this._onDidActivateGroup.event; - private readonly _onDidLayout = this._register(new Emitter()); - readonly onDidLayout = this._onDidLayout.event; - - private readonly _onDidScroll = this._register(new Emitter()); - readonly onDidScroll = this._onDidScroll.event; - private readonly _onDidChangeGroupIndex = this._register(new Emitter()); readonly onDidChangeGroupIndex = this._onDidChangeGroupIndex.event; @@ -207,7 +198,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd return [...this.parts].map(part => part.getGroups(order)).flat(); } - return this.mainEditorPart.getGroups(order); + return this.mainPart.getGroups(order); } getGroup(identifier: GroupIdentifier): IEditorGroupView | undefined { @@ -220,7 +211,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd } } - return this.mainEditorPart.getGroup(identifier); + return this.mainPart.getGroup(identifier); } activateGroup(group: IEditorGroupView | GroupIdentifier): IEditorGroupView { @@ -235,8 +226,6 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd return this.getPart(group).setSize(group, size); } - get contentDimension() { return this.activePart.contentDimension; } - arrangeGroups(arrangement: GroupsArrangement): void { return this.activePart.arrangeGroups(arrangement); } @@ -309,16 +298,11 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd //#region Main Editor Part Only - get isReady() { return this.mainEditorPart.isReady; } - get whenReady() { return this.mainEditorPart.whenReady; } - get whenRestored() { return this.mainEditorPart.whenRestored; } - get hasRestorableState() { return this.mainEditorPart.hasRestorableState; } - - get partOptions() { return this.mainEditorPart.partOptions; } - get onDidChangeEditorPartOptions() { return this.mainEditorPart.onDidChangeEditorPartOptions; } + get partOptions() { return this.mainPart.partOptions; } + get onDidChangeEditorPartOptions() { return this.mainPart.onDidChangeEditorPartOptions; } enforcePartOptions(options: IEditorPartOptions): IDisposable { - return this.mainEditorPart.enforcePartOptions(options); + return this.mainPart.enforcePartOptions(options); } //#endregion diff --git a/src/vs/workbench/browser/parts/editor/editorsObserver.ts b/src/vs/workbench/browser/parts/editor/editorsObserver.ts index 9c7b411e5dc..90fcada51de 100644 --- a/src/vs/workbench/browser/parts/editor/editorsObserver.ts +++ b/src/vs/workbench/browser/parts/editor/editorsObserver.ts @@ -92,7 +92,7 @@ export class EditorsObserver extends Disposable { this._register(this.editorGroupsService.onDidAddGroup(group => this.onGroupAdded(group))); this._register(this.editorGroupsService.onDidChangeEditorPartOptions(e => this.onDidChangeEditorPartOptions(e))); - this.editorGroupsService.whenReady.then(() => this.loadState()); + this.editorGroupsService.mainPart.whenReady.then(() => this.loadState()); } private onGroupAdded(group: IEditorGroup): void { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 6864d008943..7c1955bc425 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -385,7 +385,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } })); - this._register(editorGroupsService.onDidScroll(e => { + this._register(editorGroupsService.activePart.onDidScroll(e => { if (!this._shadowElement || !this._isVisible) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts index e5baf7c6af3..b45c469242f 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts @@ -77,7 +77,7 @@ export class NotebookEditorWidgetService implements INotebookEditorService { groupListener.set(id, listeners); }; this._disposables.add(editorGroupService.onDidAddGroup(onNewGroup)); - editorGroupService.whenReady.then(() => editorGroupService.groups.forEach(onNewGroup)); + editorGroupService.mainPart.whenReady.then(() => editorGroupService.groups.forEach(onNewGroup)); // group removed -> clean up listeners, clean up widgets this._disposables.add(editorGroupService.onDidRemoveGroup(group => { diff --git a/src/vs/workbench/contrib/splash/browser/partsSplash.ts b/src/vs/workbench/contrib/splash/browser/partsSplash.ts index ab5d5e7e892..d8a0657f0f0 100644 --- a/src/vs/workbench/contrib/splash/browser/partsSplash.ts +++ b/src/vs/workbench/contrib/splash/browser/partsSplash.ts @@ -43,7 +43,7 @@ export class PartsSplash { }, undefined, this._disposables); let lastIdleSchedule: IDisposable | undefined; - Event.any(onDidChangeFullscreen, editorGroupsService.onDidLayout, _themeService.onDidColorThemeChange)(() => { + Event.any(onDidChangeFullscreen, editorGroupsService.mainPart.onDidLayout, _themeService.onDidColorThemeChange)(() => { lastIdleSchedule?.dispose(); lastIdleSchedule = runWhenIdle(() => this._savePartsSplash(), 800); }, undefined, this._disposables); diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts index f6f1404ff2a..613ba0ec71a 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts @@ -64,10 +64,10 @@ export class WebviewEditor extends EditorPane { super(WebviewEditor.ID, telemetryService, themeService, storageService); this._register(Event.any( - _editorGroupsService.onDidScroll, - _editorGroupsService.onDidAddGroup, - _editorGroupsService.onDidRemoveGroup, - _editorGroupsService.onDidMoveGroup, + _editorGroupsService.activePart.onDidScroll, + _editorGroupsService.activePart.onDidAddGroup, + _editorGroupsService.activePart.onDidRemoveGroup, + _editorGroupsService.activePart.onDidMoveGroup, )(() => { if (this.webview && this._visible) { this.synchronizeWebviewContainerDimensions(this.webview); diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts index 8d49c0221a1..cc01ea4ed52 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts @@ -36,7 +36,7 @@ class WebviewPanelContribution extends Disposable implements IWorkbenchContribut super(); // Add all the initial groups to be listened to - this.editorGroupService.whenReady.then(() => this.editorGroupService.groups.forEach(group => { + this.editorGroupService.mainPart.whenReady.then(() => this.editorGroupService.groups.forEach(group => { this.registerGroupListener(group); })); diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts index 17bdabb3297..811b21608bb 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts @@ -1225,9 +1225,9 @@ export class GettingStartedPage extends EditorPane { this.telemetryService.publicLog2('gettingStarted.ActionExecuted', { command: 'runStepAction', argument: href, walkthroughId: this.currentWalkthrough?.id }); - const fullSize = this.groupsService.contentDimension; + const fullSize = this.group ? this.groupsService.getPart(this.group).contentDimension : undefined; - if (toSide && fullSize.width > 700) { + if (toSide && fullSize && fullSize.width > 700) { if (this.groupsService.count === 1) { const sideGroup = this.groupsService.addGroup(this.groupsService.groups[0], GroupDirection.RIGHT); this.groupsService.activateGroup(sideGroup); diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index f3e96358a17..4e4e5a4c3ee 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -82,7 +82,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { private registerListeners(): void { // Editor & group changes - this.editorGroupService.whenReady.then(() => this.onEditorGroupsReady()); + this.editorGroupService.mainPart.whenReady.then(() => this.onEditorGroupsReady()); this._register(this.editorGroupService.onDidChangeActiveGroup(group => this.handleActiveEditorChange(group))); this._register(this.editorGroupService.onDidAddGroup(group => this.registerGroupListeners(group as IEditorGroupView))); this._register(this.editorsObserver.onDidMostRecentlyActiveEditorsChange(() => this._onDidMostRecentlyActiveEditorsChange.fire())); diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 1b6299a0a52..0ae10e6268c 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -172,10 +172,11 @@ export interface IEditorDropTargetDelegate { } /** - * An editor part is a viewer of editor groups. There can be multiple editor - * parts opened in multiple windows. + * The basic primitive to work with editor groups. This interface is both implemented + * by editor part component as well as the editor groups service that operates across + * all opened editor parts. */ -export interface IEditorPart { +export interface IEditorGroupsContainer { /** * An event for when the active editor group changes. The active editor @@ -203,16 +204,6 @@ export interface IEditorPart { */ readonly onDidActivateGroup: Event; - /** - * An event for when the group container is layed out. - */ - readonly onDidLayout: Event; - - /** - * An event for when the group container is scrolled. - */ - readonly onDidScroll: Event; - /** * An event for when the index of a group changes. */ @@ -223,11 +214,6 @@ export interface IEditorPart { */ readonly onDidChangeGroupLocked: Event; - /** - * The size of the editor groups area. - */ - readonly contentDimension: IDimension; - /** * An active group is the default location for new editors to open. */ @@ -240,13 +226,14 @@ export interface IEditorPart { readonly sideGroup: IEditorSideGroup; /** - * All groups that are currently visible in the editor area in the - * order of their creation (oldest first). + * All groups that are currently visible in the container in the order + * of their creation (oldest first). */ readonly groups: readonly IEditorGroup[]; /** - * The number of editor groups that are currently opened. + * The number of editor groups that are currently opened in the + * container. */ readonly count: number; @@ -256,42 +243,7 @@ export interface IEditorPart { readonly orientation: GroupOrientation; /** - * A property that indicates when groups have been created - * and are ready to be used. - */ - readonly isReady: boolean; - - /** - * A promise that resolves when groups have been created - * and are ready to be used. - * - * Await this promise to safely work on the editor groups model - * (for example, install editor group listeners). - * - * Use the `whenRestored` property to await visible editors - * having fully resolved. - */ - readonly whenReady: Promise; - - /** - * A promise that resolves when groups have been restored. - * - * For groups with active editor, the promise will resolve - * when the visible editor has finished to resolve. - * - * Use the `whenReady` property to not await editors to - * resolve. - */ - readonly whenRestored: Promise; - - /** - * Find out if the editor group service has UI state to restore - * from a previous session. - */ - readonly hasRestorableState: boolean; - - /** - * Get all groups that are currently visible in the editor area. + * Get all groups that are currently visible in the container. * * @param order the order of the editors to use */ @@ -318,7 +270,7 @@ export interface IEditorPart { setSize(group: IEditorGroup | GroupIdentifier, size: { width: number; height: number }): void; /** - * Arrange all groups according to the provided arrangement. + * Arrange all groups in the container according to the provided arrangement. */ arrangeGroups(arrangement: GroupsArrangement): void; @@ -328,7 +280,7 @@ export interface IEditorPart { applyLayout(layout: EditorGroupLayout): void; /** - * Returns an editor layout describing the current grid + * Returns an editor layout of the container. */ getLayout(): EditorGroupLayout; @@ -365,7 +317,7 @@ export interface IEditorPart { findGroup(scope: IFindGroupScope, source?: IEditorGroup | GroupIdentifier, wrap?: boolean): IEditorGroup | undefined; /** - * Add a new group to the editor area. A new group is added by splitting a provided one in + * Add a new group to the container. A new group is added by splitting a provided one in * one of the four directions. * * @param location the group from which to split to add a new group @@ -374,12 +326,12 @@ export interface IEditorPart { addGroup(location: IEditorGroup | GroupIdentifier, direction: GroupDirection): IEditorGroup; /** - * Remove a group from the editor area. + * Remove a group from the container. */ removeGroup(group: IEditorGroup | GroupIdentifier): void; /** - * Move a group to a new group in the editor area. + * Move a group to a new group in the container. * * @param group the group to move * @param location the group from which to split to add the moved group @@ -407,7 +359,7 @@ export interface IEditorPart { mergeAllGroups(): IEditorGroup; /** - * Copy a group to a new group in the editor area. + * Copy a group to a new group in the container. * * @param group the group to copy * @param location the group from which to split to add the copied group @@ -437,6 +389,64 @@ export interface IEditorPart { createEditorDropTarget(container: unknown /* HTMLElement */, delegate: IEditorDropTargetDelegate): IDisposable; } +/** + * An editor part is a viewer of editor groups. There can be multiple editor + * parts opened in multiple windows. + */ +export interface IEditorPart extends IEditorGroupsContainer { + + /** + * An event for when the editor part is layed out. + */ + readonly onDidLayout: Event; + + /** + * An event for when the editor part is scrolled. + */ + readonly onDidScroll: Event; + + /** + * The size of the editor part. + */ + readonly contentDimension: IDimension; + + /** + * A property that indicates when groups have been created + * and are ready to be used in the editor part. + */ + readonly isReady: boolean; + + /** + * A promise that resolves when groups have been created + * and are ready to be used in the editor part. + * + * Await this promise to safely work on the editor groups model + * (for example, install editor group listeners). + * + * Use the `whenRestored` property to await visible editors + * having fully resolved. + */ + readonly whenReady: Promise; + + /** + * A promise that resolves when groups have been restored in + * the editor part. + * + * For groups with active editor, the promise will resolve + * when the visible editor has finished to resolve. + * + * Use the `whenReady` property to not await editors to + * resolve. + */ + readonly whenRestored: Promise; + + /** + * Find out if the editor part has UI state to restore + * from a previous session. + */ + readonly hasRestorableState: boolean; +} + export interface IAuxiliaryEditorPart extends IEditorPart { /** @@ -448,7 +458,7 @@ export interface IAuxiliaryEditorPart extends IEditorPart { /** * The main service to interact with editor groups across all opened editor parts. */ -export interface IEditorGroupsService extends IEditorPart { +export interface IEditorGroupsService extends IEditorGroupsContainer { readonly _serviceBrand: undefined; @@ -457,6 +467,16 @@ export interface IEditorGroupsService extends IEditorPart { */ readonly activePart: IEditorPart; + /** + * Provides access to the main window editor part. + */ + readonly mainPart: IEditorPart; + + /** + * Get the editor part that contains the group with the provided identifier. + */ + getPart(group: IEditorGroup | GroupIdentifier): IEditorPart; + /** * Opens a new window with a full editor part instantiated * in there. diff --git a/src/vs/workbench/services/history/browser/historyService.ts b/src/vs/workbench/services/history/browser/historyService.ts index 63bf77e5e15..a92bb81906a 100644 --- a/src/vs/workbench/services/history/browser/historyService.ts +++ b/src/vs/workbench/services/history/browser/historyService.ts @@ -934,11 +934,11 @@ export class HistoryService extends Disposable implements IHistoryService { // We want to seed history from opened editors // too as well as previous stored state, so we // need to wait for the editor groups being ready - if (this.editorGroupService.isReady) { + if (this.editorGroupService.mainPart.isReady) { this.loadHistory(); } else { (async () => { - await this.editorGroupService.whenReady; + await this.editorGroupService.mainPart.whenReady; this.loadHistory(); })(); diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index c7b26d65a40..d1ba09d3c00 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -840,6 +840,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { get sideGroup(): IEditorGroup { return this.groups[0]; } get count(): number { return this.groups.length; } + getPart(group: number | IEditorGroup): IEditorPart { return this; } getGroups(_order?: GroupsOrder): readonly IEditorGroup[] { return this.groups; } getGroup(identifier: number): IEditorGroup | undefined { return this.groups.find(group => group.id === identifier); } getLabel(_identifier: number): string { return 'Group 1'; } @@ -866,6 +867,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { enforcePartOptions(options: IEditorPartOptions): IDisposable { return Disposable.None; } readonly activePart = this; + readonly mainPart = this; registerEditorPart(part: any): IDisposable { return Disposable.None; } createAuxiliaryEditorPart(): IAuxiliaryEditorPart { throw new Error('Method not implemented.'); } } @@ -1729,6 +1731,7 @@ export class TestEditorPart extends MainEditorPart implements IEditorGroupsServi declare readonly _serviceBrand: undefined; readonly activePart = this; + readonly mainPart = this; testSaveState(): void { return super.saveState(); @@ -1753,6 +1756,8 @@ export class TestEditorPart extends MainEditorPart implements IEditorGroupsServi createAuxiliaryEditorPart(): IAuxiliaryEditorPart { throw new Error('Method not implemented.'); } + + getPart(group: number | IEditorGroup): IEditorPart { return this; } } export async function createEditorPart(instantiationService: IInstantiationService, disposables: DisposableStore): Promise { From f3553876139247c110b26cc113537c6e584f86b5 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2023 08:58:08 +0200 Subject: [PATCH 180/290] aux window - reduce global access to `window` object --- src/vs/base/browser/dom.ts | 19 ++++++++++++------- .../base/browser/globalPointerMoveMonitor.ts | 2 +- src/vs/base/browser/ui/dialog/dialog.ts | 7 ++++--- src/vs/base/browser/ui/menu/menu.ts | 4 +++- src/vs/base/browser/ui/menu/menubar.ts | 1 + src/vs/base/browser/ui/sash/sash.ts | 10 ++++++---- .../browser/ui/scrollbar/scrollableElement.ts | 2 +- .../browser/ui/selectBox/selectBoxCustom.ts | 1 + src/vs/base/browser/ui/tree/abstractTree.ts | 6 +++--- src/vs/base/common/event.ts | 6 ++++-- .../viewParts/viewCursors/viewCursor.ts | 5 +++-- .../diffEditor/hideUnchangedRegionsFeature.ts | 5 ++++- src/vs/editor/test/browser/testCodeEditor.ts | 1 + .../contextview/browser/contextMenuHandler.ts | 3 ++- .../browser/quickInputController.ts | 13 +++++++------ .../workspacesManagementMainService.ts | 2 +- src/vs/workbench/browser/contextkeys.ts | 4 ++-- src/vs/workbench/browser/layout.ts | 4 ++-- .../parts/editor/breadcrumbsControl.ts | 1 + .../browser/parts/editor/editorDropTarget.ts | 6 ++++-- .../electron-sandbox/contextmenuService.ts | 1 + .../keybinding/browser/keybindingService.ts | 5 +---- 22 files changed, 65 insertions(+), 43 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 57aace68687..97743d5a097 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -959,6 +959,7 @@ class FocusTracker extends Disposable implements IFocusTracker { const activeElement = (shadowRoot ? shadowRoot.activeElement : element.ownerDocument.activeElement); return isAncestor(activeElement, element); } else { + const window = element; return isAncestor(window.document.activeElement, window.document); } } @@ -1209,7 +1210,7 @@ export function domContentLoaded(): Promise { * of 1.25, the cursor will be 2.5 screen pixels wide. Depending on how the dom node aligns/"snaps" * with the screen pixels, it will sometimes be rendered with 2 screen pixels, and sometimes with 3 screen pixels. */ -export function computeScreenAwareSize(cssPx: number): number { +export function computeScreenAwareSize(window: Window, cssPx: number): number { const screenPx = window.devicePixelRatio * cssPx; return Math.max(1, Math.floor(screenPx)) / window.devicePixelRatio; } @@ -1633,7 +1634,11 @@ export class ModifierKeyEmitter extends event.Emitter { metaKey: false }; - this._subscriptions.add(addDisposableListener(window, 'keydown', e => { + this._subscriptions.add(event.Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposableStore }) => this.registerListeners(window, disposableStore), { window, disposableStore: this._subscriptions })); + } + + private registerListeners(window: Window, disposables: DisposableStore): void { + disposables.add(addDisposableListener(window, 'keydown', e => { if (e.defaultPrevented) { return; } @@ -1670,7 +1675,7 @@ export class ModifierKeyEmitter extends event.Emitter { } }, true)); - this._subscriptions.add(addDisposableListener(window, 'keyup', e => { + disposables.add(addDisposableListener(window, 'keyup', e => { if (e.defaultPrevented) { return; } @@ -1702,21 +1707,21 @@ export class ModifierKeyEmitter extends event.Emitter { } }, true)); - this._subscriptions.add(addDisposableListener(document.body, 'mousedown', () => { + disposables.add(addDisposableListener(window.document.body, 'mousedown', () => { this._keyStatus.lastKeyPressed = undefined; }, true)); - this._subscriptions.add(addDisposableListener(document.body, 'mouseup', () => { + disposables.add(addDisposableListener(window.document.body, 'mouseup', () => { this._keyStatus.lastKeyPressed = undefined; }, true)); - this._subscriptions.add(addDisposableListener(document.body, 'mousemove', e => { + disposables.add(addDisposableListener(window.document.body, 'mousemove', e => { if (e.buttons) { this._keyStatus.lastKeyPressed = undefined; } }, true)); - this._subscriptions.add(addDisposableListener(window, 'blur', () => { + disposables.add(addDisposableListener(window, 'blur', () => { this.resetKeyStatus(); })); } diff --git a/src/vs/base/browser/globalPointerMoveMonitor.ts b/src/vs/base/browser/globalPointerMoveMonitor.ts index 0348db2528f..9841596cddf 100644 --- a/src/vs/base/browser/globalPointerMoveMonitor.ts +++ b/src/vs/base/browser/globalPointerMoveMonitor.ts @@ -85,7 +85,7 @@ export class GlobalPointerMoveMonitor implements IDisposable { // DOMException: Failed to execute 'setPointerCapture' on 'Element': // No active pointer with the given id is found. // In case of failure, we bind the listeners on the window - eventSource = window; + eventSource = dom.getWindow(initialElement); } this._hooks.add(dom.addDisposableListener( diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index 0b252ae46e9..e42c66a81f0 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, addDisposableListener, clearNode, EventHelper, EventType, hide, isAncestor, show } from 'vs/base/browser/dom'; +import { $, addDisposableListener, clearNode, EventHelper, EventType, getWindow, hide, isAncestor, show } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ButtonBar, ButtonWithDescription, IButtonStyles } from 'vs/base/browser/ui/button/button'; @@ -198,7 +198,8 @@ export class Dialog extends Disposable { } async show(): Promise { - this.focusToReturn = document.activeElement as HTMLElement; + const window = getWindow(this.container); + this.focusToReturn = window.document.activeElement as HTMLElement; return new Promise((resolve) => { clearNode(this.buttonsContainer); @@ -472,7 +473,7 @@ export class Dialog extends Disposable { this.modalElement = undefined; } - if (this.focusToReturn && isAncestor(this.focusToReturn, document.body)) { + if (this.focusToReturn && isAncestor(this.focusToReturn, getWindow(this.container).document.body)) { this.focusToReturn.focus(); this.focusToReturn = undefined; } diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 9f09c7565e4..93eb168121e 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -5,7 +5,7 @@ import { isFirefox } from 'vs/base/browser/browser'; import { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch'; -import { $, addDisposableListener, append, clearNode, createStyleSheet, Dimension, EventHelper, EventLike, EventType, getActiveElement, IDomNodePagePosition, isAncestor, isInShadowDOM } from 'vs/base/browser/dom'; +import { $, addDisposableListener, append, clearNode, createStyleSheet, Dimension, EventHelper, EventLike, EventType, getActiveElement, getWindow, IDomNodePagePosition, isAncestor, isInShadowDOM } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -259,6 +259,7 @@ export class Menu extends ActionBar { e.preventDefault(); })); + const window = getWindow(container); menuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 35)}px`; actions = actions.filter(a => { @@ -899,6 +900,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { const viewBox = this.submenuContainer.getBoundingClientRect(); + const window = getWindow(this.element); const { top, left } = this.calculateSubmenuMenuLayout(new Dimension(window.innerWidth, window.innerHeight), Dimension.lift(viewBox), entryBoxUpdated, this.expandDirection); // subtract offsets caused by transform parent this.submenuContainer.style.left = `${left - viewBox.left}px`; diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index 5bec50e3280..ce52caea6f1 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -145,6 +145,7 @@ export class MenuBar extends Disposable { } })); + const window = DOM.getWindow(this.container); this._register(DOM.addDisposableListener(window, DOM.EventType.MOUSE_DOWN, () => { // This mouse event is outside the menubar so it counts as a focus out if (this.isFocused) { diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index a69b863f21d..ae21febbcc9 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, append, createStyleSheet, EventHelper, EventLike } from 'vs/base/browser/dom'; +import { $, append, createStyleSheet, EventHelper, EventLike, getWindow } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { EventType, Gesture } from 'vs/base/browser/touch'; import { Delayer } from 'vs/base/common/async'; @@ -175,14 +175,16 @@ class MouseEventFactory implements IPointerEventFactory { private readonly disposables = new DisposableStore(); + constructor(private el: HTMLElement) { } + @memoize get onPointerMove(): Event { - return this.disposables.add(new DomEmitter(window, 'mousemove')).event; + return this.disposables.add(new DomEmitter(getWindow(this.el), 'mousemove')).event; } @memoize get onPointerUp(): Event { - return this.disposables.add(new DomEmitter(window, 'mouseup')).event; + return this.disposables.add(new DomEmitter(getWindow(this.el), 'mouseup')).event; } dispose(): void { @@ -425,7 +427,7 @@ export class Sash extends Disposable { } const onMouseDown = this._register(new DomEmitter(this.el, 'mousedown')).event; - this._register(onMouseDown(e => this.onPointerStart(e, new MouseEventFactory()), this)); + this._register(onMouseDown(e => this.onPointerStart(e, new MouseEventFactory(container)), this)); const onMouseDoubleClick = this._register(new DomEmitter(this.el, 'dblclick')).event; this._register(onMouseDoubleClick(this.onPointerDoublePress, this)); const onMouseEnter = this._register(new DomEmitter(this.el, 'mouseenter')).event; diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index 4073f4272d0..6cb673170c8 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -87,7 +87,7 @@ export class MouseWheelClassifier { } public acceptStandardWheelEvent(e: StandardWheelEvent): void { - const osZoomFactor = window.devicePixelRatio / getZoomFactor(); + const osZoomFactor = dom.getWindow(e.browserEvent).devicePixelRatio / getZoomFactor(); if (platform.isWindows || platform.isLinux) { // On Windows and Linux, the incoming delta events are multiplied with the OS zoom factor. // The OS zoom factor can be reverse engineered by using the device pixel ratio and the configured zoom factor into account. diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 819921c07ea..4ec3abac78e 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -545,6 +545,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi // Make visible to enable measurements this.selectDropDownContainer.classList.add('visible'); + const window = dom.getWindow(this.selectElement); const selectPosition = dom.getDomNodePagePosition(this.selectElement); const styles = getComputedStyle(this.selectElement); const verticalPadding = parseFloat(styles.getPropertyValue('--dropdown-padding-top')) + parseFloat(styles.getPropertyValue('--dropdown-padding-bottom')); diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 1a5f138db2f..13e931b3b76 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDragAndDropData } from 'vs/base/browser/dnd'; -import { $, append, clearNode, createStyleSheet, h, hasParentWithClass } from 'vs/base/browser/dom'; +import { $, append, clearNode, createStyleSheet, getWindow, h, hasParentWithClass } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -861,8 +861,8 @@ class FindWidget extends Disposable { this._register(onGrabMouseDown.event(e => { const disposables = new DisposableStore(); - const onWindowMouseMove = disposables.add(new DomEmitter(window, 'mousemove')); - const onWindowMouseUp = disposables.add(new DomEmitter(window, 'mouseup')); + const onWindowMouseMove = disposables.add(new DomEmitter(getWindow(e), 'mousemove')); + const onWindowMouseUp = disposables.add(new DomEmitter(getWindow(e), 'mouseup')); const startRight = this.right; const startX = e.pageX; diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 8bf0cc71a30..9f76502f48a 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -615,8 +615,10 @@ export namespace Event { * runAndSubscribe(dataChangeEvent, () => this._updateUI()); * ``` */ - export function runAndSubscribe(event: Event, handler: (e: T | undefined) => any): IDisposable { - handler(undefined); + export function runAndSubscribe(event: Event, handler: (e: T) => any, initial: T): IDisposable; + export function runAndSubscribe(event: Event, handler: (e: T | undefined) => any): IDisposable; + export function runAndSubscribe(event: Event, handler: (e: T | undefined) => any, initial?: T): IDisposable { + handler(initial); return event(e => handler(e)); } diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts index 34c5bd76451..a09df64b633 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts @@ -146,15 +146,16 @@ export class ViewCursor { return null; } + const window = dom.getWindow(this._domNode); let width: number; if (this._cursorStyle === TextEditorCursorStyle.Line) { - width = dom.computeScreenAwareSize(this._lineCursorWidth > 0 ? this._lineCursorWidth : 2); + width = dom.computeScreenAwareSize(window, this._lineCursorWidth > 0 ? this._lineCursorWidth : 2); if (width > 2) { textContent = nextGrapheme; textContentClassName = this._getTokenClassName(position); } } else { - width = dom.computeScreenAwareSize(1); + width = dom.computeScreenAwareSize(window, 1); } let left = visibleRange.left; diff --git a/src/vs/editor/browser/widget/diffEditor/hideUnchangedRegionsFeature.ts b/src/vs/editor/browser/widget/diffEditor/hideUnchangedRegionsFeature.ts index 2017672847b..395ecbcd785 100644 --- a/src/vs/editor/browser/widget/diffEditor/hideUnchangedRegionsFeature.ts +++ b/src/vs/editor/browser/widget/diffEditor/hideUnchangedRegionsFeature.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, addDisposableListener, h, reset } from 'vs/base/browser/dom'; +import { $, addDisposableListener, getWindow, h, reset } from 'vs/base/browser/dom'; import { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { compareBy, numberComparator, reverseOrder } from 'vs/base/common/arrays'; import { Codicon } from 'vs/base/common/codicons'; @@ -306,6 +306,7 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget { const cur = this._unchangedRegion.visibleLineCountTop.get(); this._unchangedRegion.isDragged.set(true, undefined); + const window = getWindow(this._nodes.top); const mouseMoveListener = addDisposableListener(window, 'mousemove', e => { const currentTop = e.clientY; @@ -340,6 +341,8 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget { const cur = this._unchangedRegion.visibleLineCountBottom.get(); this._unchangedRegion.isDragged.set(true, undefined); + const window = getWindow(this._nodes.bottom); + const mouseMoveListener = addDisposableListener(window, 'mousemove', e => { const currentTop = e.clientY; const delta = currentTop - startTop; diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index 418f0b990c9..507dbe2cc6f 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -101,6 +101,7 @@ export class TestCodeEditor extends CodeEditorWidget implements ICodeEditor { class TestEditorDomElement { parentElement: IContextKeyServiceTarget | null = null; ownerDocument = document; + document = document; setAttribute(attr: string, value: string): void { } removeAttribute(attr: string): void { } hasAttribute(attr: string): boolean { return false; } diff --git a/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts index 9b67cd2dfbe..0e608294028 100644 --- a/src/vs/platform/contextview/browser/contextMenuHandler.ts +++ b/src/vs/platform/contextview/browser/contextMenuHandler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IContextMenuDelegate } from 'vs/base/browser/contextmenu'; -import { $, addDisposableListener, EventType, getActiveElement, isAncestor } from 'vs/base/browser/dom'; +import { $, addDisposableListener, EventType, getActiveElement, getWindow, isAncestor } from 'vs/base/browser/dom'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { Menu } from 'vs/base/browser/ui/menu/menu'; import { ActionRunner, IRunEvent, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions'; @@ -95,6 +95,7 @@ export class ContextMenuHandler { menu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables); menu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables); + const window = getWindow(container); menuDisposables.add(addDisposableListener(window, EventType.BLUR, () => this.contextViewService.hideContextView(true))); menuDisposables.add(addDisposableListener(window, EventType.MOUSE_DOWN, (e: MouseEvent) => { if (e.defaultPrevented) { diff --git a/src/vs/platform/quickinput/browser/quickInputController.ts b/src/vs/platform/quickinput/browser/quickInputController.ts index 8578dc5ce1e..18d81a5e852 100644 --- a/src/vs/platform/quickinput/browser/quickInputController.ts +++ b/src/vs/platform/quickinput/browser/quickInputController.ts @@ -12,7 +12,7 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { Disposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; import Severity from 'vs/base/common/severity'; import { isString } from 'vs/base/common/types'; import { localize } from 'vs/nls'; @@ -58,17 +58,18 @@ export class QuickInputController extends Disposable { this.idPrefix = options.idPrefix; this.parentElement = options.container; this.styles = options.styles; - this.registerKeyModsListeners(); + this._register(Event.runAndSubscribe(dom.onDidRegisterWindow, ({ window, disposableStore }) => this.registerKeyModsListeners(window, disposableStore), { window, disposableStore: this._store })); } - private registerKeyModsListeners() { + private registerKeyModsListeners(window: Window, disposables: DisposableStore): void { const listener = (e: KeyboardEvent | MouseEvent) => { this.keyMods.ctrlCmd = e.ctrlKey || e.metaKey; this.keyMods.alt = e.altKey; }; - this._register(dom.addDisposableListener(window, dom.EventType.KEY_DOWN, listener, true)); - this._register(dom.addDisposableListener(window, dom.EventType.KEY_UP, listener, true)); - this._register(dom.addDisposableListener(window, dom.EventType.MOUSE_DOWN, listener, true)); + + for (const event of [dom.EventType.KEY_DOWN, dom.EventType.KEY_UP, dom.EventType.MOUSE_DOWN]) { + disposables.add(dom.addDisposableListener(window, event, listener, true)); + } } private getUI() { diff --git a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts index 1d482c3eba4..236f6d6fc32 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts @@ -84,7 +84,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork // Resolve untitled workspaces try { - const untitledWorkspacePaths = (await Promises.readdir(this.untitledWorkspacesHome.with({ scheme: Schemas.file }).fsPath)).map(folder => joinPath(this.untitledWorkspacesHome, folder, UNTITLED_WORKSPACE_NAME));// + const untitledWorkspacePaths = (await Promises.readdir(this.untitledWorkspacesHome.with({ scheme: Schemas.file }).fsPath)).map(folder => joinPath(this.untitledWorkspacesHome, folder, UNTITLED_WORKSPACE_NAME)); for (const untitledWorkspacePath of untitledWorkspacePaths) { const workspace = getWorkspaceIdentifier(untitledWorkspacePath); const resolvedWorkspace = await this.resolveLocalWorkspace(untitledWorkspacePath); diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 5c5ce04ad09..0aab96ebeaa 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -9,7 +9,7 @@ import { IContextKeyService, IContextKey, setConstant as setConstantContextKey } import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext, IsMobileContext } from 'vs/platform/contextkey/common/contextkeys'; import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EmbedderIdentifierContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext, ActiveEditorCanToggleReadonlyContext, applyAvailableEditorIds, TitleBarVisibleContext } from 'vs/workbench/common/contextkeys'; import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor'; -import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom'; +import { trackFocus, addDisposableListener, EventType, onDidRegisterWindow } from 'vs/base/browser/dom'; import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -235,7 +235,7 @@ export class WorkbenchContextKeysHandler extends Disposable { this._register(this.editorGroupService.onDidChangeEditorPartOptions(() => this.updateEditorAreaContextKeys())); - this._register(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(), true)); + this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposableStore }) => disposableStore.add(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(), true)), { window, disposableStore: this._store })); this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateWorkbenchStateContextKey())); this._register(this.contextService.onDidChangeWorkspaceFolders(() => { diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index f14c67db2cc..03b3864d665 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -1460,8 +1460,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } resizePart(part: Parts, sizeChangeWidth: number, sizeChangeHeight: number): void { - const sizeChangePxWidth = Math.sign(sizeChangeWidth) * computeScreenAwareSize(Math.abs(sizeChangeWidth)); - const sizeChangePxHeight = Math.sign(sizeChangeHeight) * computeScreenAwareSize(Math.abs(sizeChangeHeight)); + const sizeChangePxWidth = Math.sign(sizeChangeWidth) * computeScreenAwareSize(window, Math.abs(sizeChangeWidth)); + const sizeChangePxHeight = Math.sign(sizeChangeHeight) * computeScreenAwareSize(window, Math.abs(sizeChangeHeight)); let viewSize: IViewSize; diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index e044a7f0c8a..cf307fec7e5 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -442,6 +442,7 @@ export class BreadcrumbsControl { }, getAnchor: () => { if (!pickerAnchor) { + const window = dom.getWindow(this.domNode); const maxInnerWidth = window.innerWidth - 8 /*a little less the full widget*/; let maxHeight = Math.min(window.innerHeight * 0.7, 300); diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index db792c89da9..fa1f412e1b0 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/editordroptarget'; import { DataTransfers } from 'vs/base/browser/dnd'; -import { addDisposableListener, DragAndDropObserver, EventHelper, EventType, isAncestor } from 'vs/base/browser/dom'; +import { addDisposableListener, DragAndDropObserver, EventHelper, EventType, getWindow, isAncestor } from 'vs/base/browser/dom'; import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer'; import { RunOnceScheduler } from 'vs/base/common/async'; import { toDisposable } from 'vs/base/common/lifecycle'; @@ -601,7 +601,9 @@ export class EditorDropTarget extends Themable { private registerListeners(): void { this._register(addDisposableListener(this.container, EventType.DRAG_ENTER, e => this.onDragEnter(e))); this._register(addDisposableListener(this.container, EventType.DRAG_LEAVE, () => this.onDragLeave())); - [this.container, window].forEach(node => this._register(addDisposableListener(node as HTMLElement, EventType.DRAG_END, () => this.onDragEnd()))); + for (const target of [this.container, getWindow(this.container)]) { + this._register(addDisposableListener(target, EventType.DRAG_END, () => this.onDragEnd())); + } } private onDragEnter(event: DragEvent): void { diff --git a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts index 9a0d942078d..49955b1c058 100644 --- a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts @@ -129,6 +129,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService } if (!isMacintosh) { + const window = dom.getWindow(anchor); const availableHeightForMenu = window.screen.height - y; if (availableHeightForMenu < actions.length * (isWindows ? 45 : 32) /* guess of 1 menu item height */) { // this is a guess to detect whether the context menu would diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 8ab8d820eeb..742acba161d 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -238,10 +238,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { this.updateKeybindingsJsonSchema(); this._register(extensionService.onDidRegisterExtensions(() => this.updateKeybindingsJsonSchema())); - this._register(this._registerKeyListeners(window)); - this._register(dom.onDidRegisterWindow(({ window, disposableStore }) => { - disposableStore.add(this._registerKeyListeners(window)); - })); + this._register(Event.runAndSubscribe(dom.onDidRegisterWindow, ({ window, disposableStore }) => disposableStore.add(this._registerKeyListeners(window)), { window, disposableStore: this._store })); this._register(browser.onDidChangeFullscreen(() => { const keyboard: IKeyboard | null = (navigator).keyboard; From e9b6a7750d320eb5cb9c6f47f0372b3adac44b58 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2023 10:00:49 +0200 Subject: [PATCH 181/290] aux window - reduce global access to `document` object --- src/vs/base/browser/dnd.ts | 7 ++++--- src/vs/base/browser/touch.ts | 10 +++++++--- src/vs/base/browser/ui/dialog/dialog.ts | 2 +- src/vs/base/browser/ui/inputbox/inputBox.ts | 4 ++-- src/vs/base/browser/ui/list/listView.ts | 2 +- src/vs/base/browser/ui/sash/sash.ts | 2 +- src/vs/base/browser/ui/splitview/paneview.ts | 4 ++-- src/vs/base/browser/ui/splitview/splitview.ts | 4 ++-- src/vs/platform/actionWidget/browser/actionList.ts | 4 ++-- .../workbench/browser/actions/developerActions.ts | 13 +++++++------ .../workbench/browser/parts/editor/editorActions.ts | 4 +++- .../browser/parts/editor/editorGroupView.ts | 5 ++--- .../workbench/browser/parts/editor/editorPanes.ts | 5 ++--- src/vs/workbench/browser/parts/editor/editorPart.ts | 5 ++--- .../debug/browser/debugEditorContribution.ts | 5 +++-- .../notebook/browser/view/cellParts/cellDnd.ts | 4 ++-- .../notebook/browser/view/cellParts/codeCell.ts | 4 ++-- .../notebook/browser/view/cellParts/markupCell.ts | 4 ++-- .../contrib/preferences/browser/settingsWidgets.ts | 4 ++-- .../services/suggest/browser/simpleSuggestWidget.ts | 2 +- 20 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/vs/base/browser/dnd.ts b/src/vs/base/browser/dnd.ts index da00d44bd8d..e55b238b08d 100644 --- a/src/vs/base/browser/dnd.ts +++ b/src/vs/base/browser/dnd.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { addDisposableListener } from 'vs/base/browser/dom'; +import { addDisposableListener, getWindow } from 'vs/base/browser/dom'; import { Disposable } from 'vs/base/common/lifecycle'; import { Mimes } from 'vs/base/common/mime'; @@ -95,11 +95,12 @@ export function applyDragImage(event: DragEvent, label: string | null, clazz: st } if (event.dataTransfer) { - document.body.appendChild(dragImage); + const ownerDocument = getWindow(event).document; + ownerDocument.body.appendChild(dragImage); event.dataTransfer.setDragImage(dragImage, -10, -10); // Removes the element when the DND operation is done - setTimeout(() => document.body.removeChild(dragImage), 0); + setTimeout(() => ownerDocument.body.removeChild(dragImage), 0); } } diff --git a/src/vs/base/browser/touch.ts b/src/vs/base/browser/touch.ts index 0fe7149d05a..9b59c8d5b1a 100644 --- a/src/vs/base/browser/touch.ts +++ b/src/vs/base/browser/touch.ts @@ -6,6 +6,7 @@ import * as DomUtils from 'vs/base/browser/dom'; import * as arrays from 'vs/base/common/arrays'; import { memoize } from 'vs/base/common/decorators'; +import { Event as EventUtils } from 'vs/base/common/event'; import { Disposable, IDisposable, markAsSingleton, toDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; @@ -89,9 +90,12 @@ export class Gesture extends Disposable { this.activeTouches = {}; this.handle = null; this._lastSetTapCountTime = 0; - this._register(DomUtils.addDisposableListener(document, 'touchstart', (e: TouchEvent) => this.onTouchStart(e), { passive: false })); - this._register(DomUtils.addDisposableListener(document, 'touchend', (e: TouchEvent) => this.onTouchEnd(e))); - this._register(DomUtils.addDisposableListener(document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e), { passive: false })); + + this._register(EventUtils.runAndSubscribe(DomUtils.onDidRegisterWindow, ({ window, disposableStore }) => { + disposableStore.add(DomUtils.addDisposableListener(window.document, 'touchstart', (e: TouchEvent) => this.onTouchStart(e), { passive: false })); + disposableStore.add(DomUtils.addDisposableListener(window.document, 'touchend', (e: TouchEvent) => this.onTouchEnd(e))); + disposableStore.add(DomUtils.addDisposableListener(window.document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e), { passive: false })); + }, { window, disposableStore: this._store })); } public static addTarget(element: HTMLElement): IDisposable { diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index e42c66a81f0..68e559c5155 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -473,7 +473,7 @@ export class Dialog extends Disposable { this.modalElement = undefined; } - if (this.focusToReturn && isAncestor(this.focusToReturn, getWindow(this.container).document.body)) { + if (this.focusToReturn && isAncestor(this.focusToReturn, this.container.ownerDocument.body)) { this.focusToReturn.focus(); this.focusToReturn = undefined; } diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index af621b9047e..dc3c4d171d6 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -166,9 +166,9 @@ export class InputBox extends Widget { // from ScrollableElement to DOM this._register(this.scrollableElement.onScroll(e => this.input.scrollTop = e.scrollTop)); - const onSelectionChange = this._register(new DomEmitter(document, 'selectionchange')); + const onSelectionChange = this._register(new DomEmitter(container.ownerDocument, 'selectionchange')); const onAnchoredSelectionChange = Event.filter(onSelectionChange.event, () => { - const selection = document.getSelection(); + const selection = container.ownerDocument.getSelection(); return selection?.anchorNode === wrapper; }); diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index e01625478e6..9090f95fa79 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -1131,7 +1131,7 @@ export class ListView implements IListView { while (e && !e.classList.contains('monaco-workbench')) { e = e.parentElement; } - return e || document.body; + return e || this.domNode.ownerDocument; }; const container = getDragImageContainer(this.domNode); diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index ae21febbcc9..44fa17be826 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -516,7 +516,7 @@ export class Sash extends Disposable { return; } - const iframes = document.getElementsByTagName('iframe'); + const iframes = this.el.ownerDocument.getElementsByTagName('iframe'); for (const iframe of iframes) { iframe.classList.add(PointerEventsDisabledCssClass); // disable mouse events on iframes as long as we drag the sash } diff --git a/src/vs/base/browser/ui/splitview/paneview.ts b/src/vs/base/browser/ui/splitview/paneview.ts index 5bc229dcde0..4ce6aefe5b0 100644 --- a/src/vs/base/browser/ui/splitview/paneview.ts +++ b/src/vs/base/browser/ui/splitview/paneview.ts @@ -372,9 +372,9 @@ class PaneDraggable extends Disposable { e.dataTransfer?.setData(DataTransfers.TEXT, this.pane.draggableElement.textContent || ''); } - const dragImage = append(document.body, $('.monaco-drag-image', {}, this.pane.draggableElement.textContent || '')); + const dragImage = append(this.pane.element.ownerDocument.body, $('.monaco-drag-image', {}, this.pane.draggableElement.textContent || '')); e.dataTransfer.setDragImage(dragImage, -10, -10); - setTimeout(() => document.body.removeChild(dragImage), 0); + setTimeout(() => this.pane.element.ownerDocument.body.removeChild(dragImage), 0); this.context.draggable = this; } diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 1d8a80e76b5..ca8a714d8b3 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -887,8 +887,8 @@ export class SplitView resetSashDragState(this.sashDragState!.current, e.altKey)), - addDisposableListener(document.body, 'keyup', () => resetSashDragState(this.sashDragState!.current, false)) + addDisposableListener(this.el.ownerDocument.body, 'keydown', e => resetSashDragState(this.sashDragState!.current, e.altKey)), + addDisposableListener(this.el.ownerDocument.body, 'keyup', () => resetSashDragState(this.sashDragState!.current, false)) ); const resetSashDragState = (start: number, alt: boolean) => { diff --git a/src/vs/platform/actionWidget/browser/actionList.ts b/src/vs/platform/actionWidget/browser/actionList.ts index c4bab67a197..e88d666f106 100644 --- a/src/vs/platform/actionWidget/browser/actionList.ts +++ b/src/vs/platform/actionWidget/browser/actionList.ts @@ -248,7 +248,7 @@ export class ActionList extends Disposable { // For finding width dynamically (not using resize observer) const itemWidths: number[] = this._allMenuItems.map((_, index): number => { - const element = document.getElementById(this._list.getElementID(index)); + const element = this.domNode.ownerDocument.getElementById(this._list.getElementID(index)); if (element) { element.style.width = 'auto'; const width = element.getBoundingClientRect().width; @@ -262,7 +262,7 @@ export class ActionList extends Disposable { const width = Math.max(...itemWidths, minWidth); const maxVhPrecentage = 0.7; - const height = Math.min(heightWithHeaders, document.body.clientHeight * maxVhPrecentage); + const height = Math.min(heightWithHeaders, this.domNode.ownerDocument.body.clientHeight * maxVhPrecentage); this._list.layout(height, width); this.domNode.style.height = `${height}px`; diff --git a/src/vs/workbench/browser/actions/developerActions.ts b/src/vs/workbench/browser/actions/developerActions.ts index ed22baa17a4..49144b6102d 100644 --- a/src/vs/workbench/browser/actions/developerActions.ts +++ b/src/vs/workbench/browser/actions/developerActions.ts @@ -11,7 +11,7 @@ import { DomEmitter } from 'vs/base/browser/event'; import { Color } from 'vs/base/common/color'; import { Event } from 'vs/base/common/event'; import { IDisposable, toDisposable, dispose, DisposableStore, setDisposableTracker, DisposableTracker, DisposableInfo } from 'vs/base/common/lifecycle'; -import { getDomNodePagePosition, createStyleSheet, createCSSRule, append, $ } from 'vs/base/browser/dom'; +import { getDomNodePagePosition, createStyleSheet, createCSSRule, append, $, getActiveDocument } from 'vs/base/browser/dom'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Context } from 'vs/platform/contextkey/browser/contextKeyService'; @@ -63,15 +63,16 @@ class InspectContextKeysAction extends Action2 { createCSSRule('*', 'cursor: crosshair !important;', stylesheet); const hoverFeedback = document.createElement('div'); - document.body.appendChild(hoverFeedback); - disposables.add(toDisposable(() => document.body.removeChild(hoverFeedback))); + const activeDocument = getActiveDocument(); + activeDocument.body.appendChild(hoverFeedback); + disposables.add(toDisposable(() => activeDocument.body.removeChild(hoverFeedback))); hoverFeedback.style.position = 'absolute'; hoverFeedback.style.pointerEvents = 'none'; hoverFeedback.style.backgroundColor = 'rgba(255, 0, 0, 0.5)'; hoverFeedback.style.zIndex = '1000'; - const onMouseMove = disposables.add(new DomEmitter(document.body, 'mousemove', true)); + const onMouseMove = disposables.add(new DomEmitter(activeDocument, 'mousemove', true)); disposables.add(onMouseMove.event(e => { const target = e.target as HTMLElement; const position = getDomNodePagePosition(target); @@ -82,10 +83,10 @@ class InspectContextKeysAction extends Action2 { hoverFeedback.style.height = `${position.height}px`; })); - const onMouseDown = disposables.add(new DomEmitter(document.body, 'mousedown', true)); + const onMouseDown = disposables.add(new DomEmitter(activeDocument, 'mousedown', true)); Event.once(onMouseDown.event)(e => { e.preventDefault(); e.stopPropagation(); }, null, disposables); - const onMouseUp = disposables.add(new DomEmitter(document.body, 'mouseup', true)); + const onMouseUp = disposables.add(new DomEmitter(activeDocument, 'mouseup', true)); Event.once(onMouseUp.event)(e => { e.preventDefault(); e.stopPropagation(); diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 23d44d4f4db..9838d2b99c5 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -34,6 +34,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { ILogService } from 'vs/platform/log/common/log'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ActiveEditorAvailableEditorIdsContext, ActiveEditorContext, ActiveEditorGroupEmptyContext } from 'vs/workbench/common/contextkeys'; +import { getActiveDocument } from 'vs/base/browser/dom'; class ExecuteCommandAction extends Action2 { @@ -2276,7 +2277,8 @@ abstract class AbstractCreateEditorGroupAction extends Action2 { // of an editor having keyboard focus in an inactive editor group // (see https://github.com/microsoft/vscode/issues/189256) - const focusNewGroup = layoutService.hasFocus(Parts.EDITOR_PART) || document.activeElement === document.body; + const activeDocument = getActiveDocument(); + const focusNewGroup = layoutService.hasFocus(Parts.EDITOR_PART) || activeDocument.activeElement === activeDocument.body; const group = editorGroupService.addGroup(editorGroupService.activeGroup, this.direction); editorGroupService.activateGroup(group); diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 9a0b3c4eb67..8d5c3700684 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1449,9 +1449,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } private shouldRestoreFocus(target: Element): boolean { - const activeElement = document.activeElement; - - if (activeElement === document.body) { + const activeElement = target.ownerDocument.activeElement; + if (activeElement === target.ownerDocument.body) { return true; // always restore focus if nothing is focused currently } diff --git a/src/vs/workbench/browser/parts/editor/editorPanes.ts b/src/vs/workbench/browser/parts/editor/editorPanes.ts index 4f4c65d6d0b..47c073da34c 100644 --- a/src/vs/workbench/browser/parts/editor/editorPanes.ts +++ b/src/vs/workbench/browser/parts/editor/editorPanes.ts @@ -296,9 +296,8 @@ export class EditorPanes extends Disposable { return true; // restore focus if nothing was focused } - const activeElement = document.activeElement; - - if (!activeElement || activeElement === document.body) { + const activeElement = expectedActiveElement.ownerDocument.activeElement; + if (!activeElement || activeElement === expectedActiveElement.ownerDocument.body) { return true; // restore focus if nothing is focused currently } diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 98a6ebf94f2..18bd78a4f32 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -495,9 +495,8 @@ export class EditorPart extends Part implements IEditorPart { return false; } - const activeElement = document.activeElement; - - if (activeElement === document.body) { + const activeElement = target.ownerDocument.activeElement; + if (activeElement === target.ownerDocument.body) { return true; // always restore focus if nothing is focused currently } diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 753beae7e23..eab46b62426 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -316,11 +316,12 @@ export class DebugEditorContribution implements IDebugEditorContribution { private applyHoverConfiguration(model: ITextModel, stackFrame: IStackFrame | undefined): void { if (stackFrame && this.uriIdentityService.extUri.isEqual(model.uri, stackFrame.source.uri)) { + const ownerDocument = this.editor.getContainerDomNode().ownerDocument; if (this.altListener) { this.altListener.dispose(); } // When the alt key is pressed show regular editor hover and hide the debug hover #84561 - this.altListener = addDisposableListener(document, 'keydown', keydownEvent => { + this.altListener = addDisposableListener(ownerDocument, 'keydown', keydownEvent => { const standardKeyboardEvent = new StandardKeyboardEvent(keydownEvent); if (standardKeyboardEvent.keyCode === KeyCode.Alt) { this.altPressed = true; @@ -332,7 +333,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.showEditorHover(this.hoverPosition, false); } - const onKeyUp = new DomEmitter(document, 'keyup'); + const onKeyUp = new DomEmitter(ownerDocument, 'keyup'); const listener = Event.any(this.hostService.onDidChangeFocus, onKeyUp.event)(keyupEvent => { let standardKeyboardEvent = undefined; if (isKeyboardEvent(keyupEvent)) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts index 5531da7b673..ae080f9f65a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts @@ -75,8 +75,8 @@ export class CellDragAndDropController extends Disposable { this.listInsertionIndicator = DOM.append(notebookListContainer, $('.cell-list-insertion-indicator')); - this._register(DOM.addDisposableListener(document.body, DOM.EventType.DRAG_START, this.onGlobalDragStart.bind(this), true)); - this._register(DOM.addDisposableListener(document.body, DOM.EventType.DRAG_END, this.onGlobalDragEnd.bind(this), true)); + this._register(DOM.addDisposableListener(notebookListContainer.ownerDocument.body, DOM.EventType.DRAG_START, this.onGlobalDragStart.bind(this), true)); + this._register(DOM.addDisposableListener(notebookListContainer.ownerDocument.body, DOM.EventType.DRAG_END, this.onGlobalDragEnd.bind(this), true)); const addCellDragListener = (eventType: string, handler: (e: CellDragEvent) => void, useCapture = false) => { this._register(DOM.addDisposableListener( diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts index b110caed2fa..501569e9984 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts @@ -191,7 +191,7 @@ export class CodeCell extends Disposable { if ( this.notebookEditor.getActiveCell() === this.viewCell && this.viewCell.focusMode === CellFocusMode.Editor && - (this.notebookEditor.hasEditorFocus() || document.activeElement === document.body)) // Don't steal focus from other workbench parts, but if body has focus, we can take it + (this.notebookEditor.hasEditorFocus() || this.notebookEditor.getDomNode().ownerDocument.activeElement === this.notebookEditor.getDomNode().ownerDocument.body)) // Don't steal focus from other workbench parts, but if body has focus, we can take it { this.templateData.editor?.focus(); } @@ -338,7 +338,7 @@ export class CodeCell extends Disposable { // the document active element is inside the notebook editor or the document body (cell editor being disposed previously) return this.notebookEditor.getActiveCell() === this.viewCell && this.viewCell.focusMode === CellFocusMode.Editor - && (this.notebookEditor.hasEditorFocus() || document.activeElement === document.body); + && (this.notebookEditor.hasEditorFocus() || this.notebookEditor.getDomNode().ownerDocument.activeElement === this.notebookEditor.getDomNode().ownerDocument.body); } private updateEditorForFocusModeChange() { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts index 2fd197bf823..e11d95769cb 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts @@ -224,7 +224,7 @@ export class MarkupCell extends Disposable { override dispose() { // move focus back to the cell list otherwise the focus goes to body - if (this.notebookEditor.getActiveCell() === this.viewCell && this.viewCell.focusMode === CellFocusMode.Editor && (this.notebookEditor.hasEditorFocus() || document.activeElement === document.body)) { + if (this.notebookEditor.getActiveCell() === this.viewCell && this.viewCell.focusMode === CellFocusMode.Editor && (this.notebookEditor.hasEditorFocus() || this.notebookEditor.getDomNode().ownerDocument.activeElement === this.notebookEditor.getDomNode().ownerDocument.body)) { this.notebookEditor.focusContainer(); } @@ -407,7 +407,7 @@ export class MarkupCell extends Disposable { private focusEditorIfNeeded() { if (this.viewCell.focusMode === CellFocusMode.Editor && - (this.notebookEditor.hasEditorFocus() || document.activeElement === document.body) + (this.notebookEditor.hasEditorFocus() || this.notebookEditor.getDomNode().ownerDocument.activeElement === this.notebookEditor.getDomNode().ownerDocument.body) ) { // Don't steal focus from other workbench parts, but if body has focus, we can take it if (!this.editor) { return; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index 5a65487a491..153c429dc21 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -484,9 +484,9 @@ export class ListSettingWidget extends AbstractListSettingWidget if (ev.dataTransfer) { ev.dataTransfer.dropEffect = 'move'; const dragImage = this.getDragImage(item); - document.body.appendChild(dragImage); + rowElement.ownerDocument.body.appendChild(dragImage); ev.dataTransfer.setDragImage(dragImage, -10, -10); - setTimeout(() => document.body.removeChild(dragImage), 0); + setTimeout(() => rowElement.ownerDocument.body.removeChild(dragImage), 0); } })); this.listDisposables.add(DOM.addDisposableListener(rowElement, DOM.EventType.DRAG_OVER, (ev) => { diff --git a/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts b/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts index cad3f1f5eb0..7df145abc38 100644 --- a/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts +++ b/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.ts @@ -395,7 +395,7 @@ export class SimpleSuggestWidget implements IDisposable { // return; // } - const bodyBox = dom.getClientArea(document.body); + const bodyBox = dom.getClientArea(this._container.ownerDocument.body); const info = this._getLayoutInfo(); if (!size) { From f6bc90dc1f367dcd596209ae62add169b11845cf Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2023 12:05:20 +0200 Subject: [PATCH 182/290] aux window - reduce use of global `document` and prefer `ownerDocument` --- .../base/browser/ui/breadcrumbs/breadcrumbsWidget.ts | 2 +- src/vs/base/browser/ui/button/button.ts | 2 +- src/vs/base/browser/ui/contextview/contextview.ts | 2 +- src/vs/base/browser/ui/dialog/dialog.ts | 6 +++--- src/vs/base/browser/ui/findinput/findInput.ts | 2 +- src/vs/base/browser/ui/findinput/replaceInput.ts | 2 +- src/vs/base/browser/ui/inputbox/inputBox.ts | 4 ++-- src/vs/base/browser/ui/list/listPaging.ts | 3 ++- src/vs/base/browser/ui/list/listWidget.ts | 2 +- src/vs/base/browser/ui/splitview/paneview.ts | 4 ++-- src/vs/base/browser/ui/toggle/toggle.ts | 2 +- src/vs/base/browser/ui/tree/abstractTree.ts | 3 ++- .../contextview/browser/contextMenuHandler.ts | 2 +- .../history/browser/contextScopedHistoryWidget.ts | 2 +- src/vs/platform/list/browser/listService.ts | 3 ++- .../quickinput/browser/quickInputController.ts | 3 ++- src/vs/workbench/browser/actions/listCommands.ts | 5 +++-- src/vs/workbench/browser/actions/windowActions.ts | 8 ++++---- src/vs/workbench/browser/contextkeys.ts | 8 ++++---- src/vs/workbench/browser/layout.ts | 11 +++++++---- .../workbench/browser/parts/editor/editorGroupView.ts | 4 ++-- src/vs/workbench/browser/parts/editor/editorPanes.ts | 2 +- .../browser/parts/statusbar/statusbarModel.ts | 2 +- .../contrib/accessibility/browser/accessibleView.ts | 3 ++- src/vs/workbench/contrib/chat/browser/chatQuick.ts | 2 +- .../contrib/comments/browser/comments.contribution.ts | 3 ++- .../contrib/comments/browser/commentsView.ts | 3 ++- src/vs/workbench/contrib/debug/browser/debugHover.ts | 2 +- .../contrib/debug/browser/exceptionWidget.ts | 6 +++++- src/vs/workbench/contrib/files/browser/files.ts | 9 ++++++--- .../browser/contrib/clipboard/notebookClipboard.ts | 7 ++++--- .../contrib/notebook/browser/notebookEditor.ts | 6 +++++- .../contrib/notebook/browser/notebookEditorWidget.ts | 8 ++++---- .../notebook/browser/view/cellParts/cellStatusPart.ts | 4 ++-- .../notebook/browser/view/cellParts/cellToolbars.ts | 3 ++- .../notebook/browser/view/cellParts/markupCell.ts | 2 +- .../contrib/notebook/browser/view/notebookCellList.ts | 10 +++------- .../preferences/browser/preferences.contribution.ts | 3 ++- .../contrib/preferences/browser/settingsEditor2.ts | 10 ++++++---- .../contrib/preferences/browser/settingsWidgets.ts | 2 +- .../contrib/search/browser/searchActionsBase.ts | 2 +- .../contrib/search/browser/searchActionsNav.ts | 3 ++- .../searchEditor/browser/searchEditor.contribution.ts | 3 ++- .../welcomeGettingStarted/browser/gettingStarted.ts | 2 +- .../welcomeWalkthrough/browser/walkThroughPart.ts | 2 +- .../contrib/workspace/browser/workspaceTrustEditor.ts | 2 +- src/vs/workbench/electron-sandbox/window.ts | 7 ++++--- .../workbench/services/hover/browser/hoverService.ts | 9 +++++---- 48 files changed, 112 insertions(+), 85 deletions(-) diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index 8d7ad28d327..9324517f3ef 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -177,7 +177,7 @@ export class BreadcrumbsWidget { } isDOMFocused(): boolean { - let candidate = document.activeElement; + let candidate = this._domNode.ownerDocument.activeElement; while (candidate) { if (this._domNode === candidate) { return true; diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index 5682eefc506..13b4351f53c 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -281,7 +281,7 @@ export class Button extends Disposable implements IButton { } hasFocus(): boolean { - return this._element === document.activeElement; + return this._element === this._element.ownerDocument.activeElement; } } diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 04779bd11aa..816e91ac819 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -373,7 +373,7 @@ export class ContextView extends Disposable { private onDOMEvent(e: Event, onCapture: boolean): void { if (this.delegate) { if (this.delegate.onDOMEvent) { - this.delegate.onDOMEvent(e, document.activeElement); + this.delegate.onDOMEvent(e, this.view.ownerDocument.activeElement); } else if (onCapture && !DOM.isAncestor(e.target, this.container)) { this.hide(); } diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index 68e559c5155..ca469d2a4b5 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -198,8 +198,7 @@ export class Dialog extends Disposable { } async show(): Promise { - const window = getWindow(this.container); - this.focusToReturn = window.document.activeElement as HTMLElement; + this.focusToReturn = this.container.ownerDocument.activeElement as HTMLElement; return new Promise((resolve) => { clearNode(this.buttonsContainer); @@ -229,6 +228,7 @@ export class Dialog extends Disposable { }); // Handle keyboard events globally: Tab, Arrow-Left/Right + const window = getWindow(this.container); this._register(addDisposableListener(window, 'keydown', e => { const evt = new StandardKeyboardEvent(e); @@ -269,7 +269,7 @@ export class Dialog extends Disposable { const links = this.messageContainer.querySelectorAll('a'); for (const link of links) { focusableElements.push(link); - if (link === document.activeElement) { + if (link === link.ownerDocument.activeElement) { focusedIndex = focusableElements.length - 1; } } diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index 8707c671aac..76af849c278 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -163,7 +163,7 @@ export class FindInput extends Widget { const indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode]; this.onkeydown(this.domNode, (event: IKeyboardEvent) => { if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) { - const index = indexes.indexOf(document.activeElement); + const index = indexes.indexOf(this.domNode.ownerDocument.activeElement); if (index >= 0) { let newIndex: number = -1; if (event.equals(KeyCode.RightArrow)) { diff --git a/src/vs/base/browser/ui/findinput/replaceInput.ts b/src/vs/base/browser/ui/findinput/replaceInput.ts index e5476897176..6cd7d4fb1c6 100644 --- a/src/vs/base/browser/ui/findinput/replaceInput.ts +++ b/src/vs/base/browser/ui/findinput/replaceInput.ts @@ -140,7 +140,7 @@ export class ReplaceInput extends Widget { const indexes = [this.preserveCase.domNode]; this.onkeydown(this.domNode, (event: IKeyboardEvent) => { if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) { - const index = indexes.indexOf(document.activeElement); + const index = indexes.indexOf(this.domNode.ownerDocument.activeElement); if (index >= 0) { let newIndex: number = -1; if (event.equals(KeyCode.RightArrow)) { diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index dc3c4d171d6..652031e1f30 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -287,7 +287,7 @@ export class InputBox extends Widget { } public hasFocus(): boolean { - return document.activeElement === this.input; + return this.input.ownerDocument.activeElement === this.input; } public select(range: IRange | null = null): void { @@ -628,7 +628,7 @@ export class HistoryInputBox extends InputBox implements IHistoryNavigationWidge if (options.showHistoryHint && options.showHistoryHint() && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX) && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS) && this.history.getHistory().length) { const suffix = this.placeholder.endsWith(')') ? NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX : NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS; const suffixedPlaceholder = this.placeholder + suffix; - if (options.showPlaceholderOnFocus && document.activeElement !== this.input) { + if (options.showPlaceholderOnFocus && this.input.ownerDocument.activeElement !== this.input) { this.placeholder = suffixedPlaceholder; } else { diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index a3d2eb16cfc..4780d4eb4e9 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -144,7 +144,8 @@ export class PagedList implements IDisposable { } isDOMFocused(): boolean { - return this.list.getHTMLElement() === document.activeElement; + const element = this.getHTMLElement(); + return element === element.ownerDocument.activeElement; } domFocus(): void { diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 898f8af3175..d35e17838a6 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1880,7 +1880,7 @@ export class List implements ISpliceable, IDisposable { } isDOMFocused(): boolean { - return this.view.domNode === document.activeElement; + return this.view.domNode === this.view.domNode.ownerDocument.activeElement; } getHTMLElement(): HTMLElement { diff --git a/src/vs/base/browser/ui/splitview/paneview.ts b/src/vs/base/browser/ui/splitview/paneview.ts index 4ce6aefe5b0..5ae5a44f37d 100644 --- a/src/vs/base/browser/ui/splitview/paneview.ts +++ b/src/vs/base/browser/ui/splitview/paneview.ts @@ -645,7 +645,7 @@ export class PaneView extends Disposable { private focusPrevious(): void { const headers = this.getPaneHeaderElements(); - const index = headers.indexOf(document.activeElement as HTMLElement); + const index = headers.indexOf(this.element.ownerDocument.activeElement as HTMLElement); if (index === -1) { return; @@ -656,7 +656,7 @@ export class PaneView extends Disposable { private focusNext(): void { const headers = this.getPaneHeaderElements(); - const index = headers.indexOf(document.activeElement as HTMLElement); + const index = headers.indexOf(this.element.ownerDocument.activeElement as HTMLElement); if (index === -1) { return; diff --git a/src/vs/base/browser/ui/toggle/toggle.ts b/src/vs/base/browser/ui/toggle/toggle.ts index 76a74ccbcad..6668f07a175 100644 --- a/src/vs/base/browser/ui/toggle/toggle.ts +++ b/src/vs/base/browser/ui/toggle/toggle.ts @@ -252,7 +252,7 @@ export class Checkbox extends Widget { } hasFocus(): boolean { - return this.domNode === document.activeElement; + return this.domNode === this.domNode.ownerDocument.activeElement; } protected applyStyles(): void { diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 13e931b3b76..e3583691b22 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1781,7 +1781,8 @@ export abstract class AbstractTree implements IDisposable } isDOMFocused(): boolean { - return this.getHTMLElement() === document.activeElement; + const element = this.getHTMLElement(); + return element === element.ownerDocument.activeElement; } layout(height?: number, width?: number): void { diff --git a/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts index 0e608294028..fb591a63828 100644 --- a/src/vs/platform/contextview/browser/contextMenuHandler.ts +++ b/src/vs/platform/contextview/browser/contextMenuHandler.ts @@ -45,7 +45,7 @@ export class ContextMenuHandler { return; // Don't render an empty context menu } - this.focusToReturn = document.activeElement as HTMLElement; + this.focusToReturn = getActiveElement() as HTMLElement; let menu: Menu | undefined; diff --git a/src/vs/platform/history/browser/contextScopedHistoryWidget.ts b/src/vs/platform/history/browser/contextScopedHistoryWidget.ts index 53b9397651d..d1f0d0e026b 100644 --- a/src/vs/platform/history/browser/contextScopedHistoryWidget.ts +++ b/src/vs/platform/history/browser/contextScopedHistoryWidget.ts @@ -52,7 +52,7 @@ export function registerAndCreateHistoryNavigationContext(scopedContextKeyServic }; // Check for currently being focused - if (widget.element === document.activeElement) { + if (widget.element === widget.element.ownerDocument.activeElement) { onDidFocus(); } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 4ada5b87e82..24934d72817 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -92,7 +92,8 @@ export class ListService implements IListService { this.lists.push(registeredList); // Check for currently being focused - if (widget.getHTMLElement() === document.activeElement) { + const element = widget.getHTMLElement(); + if (element === element.ownerDocument.activeElement) { this.setLastFocusedList(widget); } diff --git a/src/vs/platform/quickinput/browser/quickInputController.ts b/src/vs/platform/quickinput/browser/quickInputController.ts index 18d81a5e852..b54708fbc6d 100644 --- a/src/vs/platform/quickinput/browser/quickInputController.ts +++ b/src/vs/platform/quickinput/browser/quickInputController.ts @@ -586,7 +586,8 @@ export class QuickInputController extends Disposable { return; } - const focusChanged = !dom.isAncestor(document.activeElement, this.ui?.container ?? null); + const container = this.ui?.container; + const focusChanged = container && !dom.isAncestor(container.ownerDocument.activeElement, container); this.controller = null; this.onHideEmitter.fire(); this.getUI().container.style.display = 'none'; diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index e17f1463d54..f97f3c7d387 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -24,8 +24,9 @@ function ensureDOMFocus(widget: ListWidget | undefined): void { // DOM focus is within another focusable control within the // list/tree item. therefor we should ensure that the // list/tree has DOM focus again after the command ran. - if (widget && widget.getHTMLElement() !== document.activeElement) { - widget.domFocus(); + const element = widget?.getHTMLElement(); + if (element && element !== element.ownerDocument.activeElement) { + widget?.domFocus(); } } diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index a0aaa04d13f..2bb59d0e392 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -34,6 +34,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { isFolderBackupInfo, isWorkspaceBackupInfo } from 'vs/platform/backup/common/backup'; +import { getActiveElement } from 'vs/base/browser/dom'; export const inRecentFilesPickerContextKey = 'inRecentFilesPicker'; @@ -406,10 +407,9 @@ class BlurAction extends Action2 { } run(): void { - const el = document.activeElement; - - if (el instanceof HTMLElement) { - el.blur(); + const activeElement = getActiveElement(); + if (activeElement instanceof HTMLElement) { + activeElement.blur(); } } } diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 0aab96ebeaa..e3acfe3755a 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -235,7 +235,7 @@ export class WorkbenchContextKeysHandler extends Disposable { this._register(this.editorGroupService.onDidChangeEditorPartOptions(() => this.updateEditorAreaContextKeys())); - this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposableStore }) => disposableStore.add(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(), true)), { window, disposableStore: this._store })); + this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposableStore }) => disposableStore.add(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(window.document), true)), { window, disposableStore: this._store })); this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateWorkbenchStateContextKey())); this._register(this.contextService.onDidChangeWorkspaceFolders(() => { @@ -329,17 +329,17 @@ export class WorkbenchContextKeysHandler extends Disposable { this.activeEditorGroupLocked.set(activeGroup.isLocked); } - private updateInputContextKeys(): void { + private updateInputContextKeys(ownerDocument: Document): void { function activeElementIsInput(): boolean { - return !!document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA'); + return !!ownerDocument.activeElement && (ownerDocument.activeElement.tagName === 'INPUT' || ownerDocument.activeElement.tagName === 'TEXTAREA'); } const isInputFocused = activeElementIsInput(); this.inputFocusedContext.set(isInputFocused); if (isInputFocused) { - const tracker = trackFocus(document.activeElement as HTMLElement); + const tracker = trackFocus(ownerDocument.activeElement as HTMLElement); Event.once(tracker.onDidBlur)(() => { this.inputFocusedContext.set(activeElementIsInput()); diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 03b3864d665..2708caa9350 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -1001,14 +1001,17 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } hasFocus(part: Parts): boolean { - const activeElement = document.activeElement; + const container = this.getContainer(part); + if (!container) { + return false; + } + + const activeElement = container.ownerDocument.activeElement; if (!activeElement) { return false; } - const container = this.getContainer(part); - - return !!container && isAncestorUsingFlowTo(activeElement, container); + return isAncestorUsingFlowTo(activeElement, container); } focusPart(part: Parts): void { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 8d5c3700684..ae9cf39e8b8 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -490,7 +490,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { options.sticky = this.model.isSticky(activeEditor); // preserve sticky state options.preserveFocus = true; // handle focus after editor is opened - const activeElement = document.activeElement; + const activeElement = this.editorContainer.ownerDocument.activeElement; // Show active editor (intentionally not using async to keep // `restoreEditors` from executing in same stack) @@ -501,7 +501,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // stolen accidentally on startup when the user already // clicked somewhere. - if (this.groupsView.activeGroup === this && activeElement === document.activeElement) { + if (this.groupsView.activeGroup === this && activeElement === this.editorContainer.ownerDocument.activeElement) { this.focus(); } }); diff --git a/src/vs/workbench/browser/parts/editor/editorPanes.ts b/src/vs/workbench/browser/parts/editor/editorPanes.ts index 47c073da34c..ff42c12e1f4 100644 --- a/src/vs/workbench/browser/parts/editor/editorPanes.ts +++ b/src/vs/workbench/browser/parts/editor/editorPanes.ts @@ -264,7 +264,7 @@ export class EditorPanes extends Disposable { const pane = this.doShowEditorPane(descriptor); // Remember current active element for deciding to restore focus later - const activeElement = document.activeElement; + const activeElement = this.editorPanesParent.ownerDocument.activeElement; // Apply input to pane const { changed, cancelled } = await this.doSetInput(pane, editor, options, context); diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts b/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts index 8e943eec515..4a6410c6acc 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts @@ -174,7 +174,7 @@ export class StatusbarViewModel extends Disposable { } private getFocusedEntry(): IStatusbarViewModelEntry | undefined { - return this._entries.find(entry => isAncestor(document.activeElement, entry.container)); + return this._entries.find(entry => isAncestor(entry.container.ownerDocument.activeElement, entry.container)); } private focusEntry(delta: number, restartPosition: number): void { diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 8a7d668a8a8..01185eae7c8 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -526,7 +526,8 @@ export class AccessibleView extends Disposable { } })); disposableStore.add(this._editorWidget.onDidBlurEditorWidget(() => { - if (document.activeElement !== this._toolbar.getElement()) { + const element = this._toolbar.getElement(); + if (element.ownerDocument.activeElement !== element) { this._contextViewService.hideContextView(); } })); diff --git a/src/vs/workbench/contrib/chat/browser/chatQuick.ts b/src/vs/workbench/contrib/chat/browser/chatQuick.ts index b88303f884c..ff0b2a3cc11 100644 --- a/src/vs/workbench/contrib/chat/browser/chatQuick.ts +++ b/src/vs/workbench/contrib/chat/browser/chatQuick.ts @@ -50,7 +50,7 @@ export class QuickChatService extends Disposable implements IQuickChatService { if (!widget) { return false; } - return dom.isAncestor(document.activeElement, widget); + return dom.isAncestor(widget.ownerDocument.activeElement, widget); } toggle(providerId?: string, query?: string | undefined): void { diff --git a/src/vs/workbench/contrib/comments/browser/comments.contribution.ts b/src/vs/workbench/contrib/comments/browser/comments.contribution.ts index 2f06cf6f809..5d0dbca0442 100644 --- a/src/vs/workbench/contrib/comments/browser/comments.contribution.ts +++ b/src/vs/workbench/contrib/comments/browser/comments.contribution.ts @@ -21,6 +21,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys'; import { CommentCommandId } from 'vs/workbench/contrib/comments/common/commentCommandIds'; import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode'; +import { getActiveElement } from 'vs/base/browser/dom'; Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ id: 'comments', @@ -118,7 +119,7 @@ export class CommentsAccessibilityHelpProvider implements IAccessibleContentProv return strings.format(noKbMsg, commandId); } provideContent(): string { - this._element = document.activeElement as HTMLElement; + this._element = getActiveElement() as HTMLElement; const content: string[] = []; content.push(this._descriptionForCommand(ToggleTabFocusModeAction.ID, CommentAccessibilityHelpNLS.introWidget, CommentAccessibilityHelpNLS.introWidgetNoKb) + '\n'); content.push(CommentAccessibilityHelpNLS.commentCommands); diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index 3ef5c946841..a177a4eb3a3 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -225,7 +225,8 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView { } public override focus(): void { - if (this.tree && this.tree.getHTMLElement() === document.activeElement) { + const element = this.tree?.getHTMLElement(); + if (element && element === element.ownerDocument.activeElement) { return; } diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index b1123165a11..cc2931dd90f 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -341,7 +341,7 @@ export class DebugHoverWidget implements IContentWidget { return; } - if (dom.isAncestor(document.activeElement, this.domNode)) { + if (dom.isAncestor(this.domNode.ownerDocument.activeElement, this.domNode)) { this.editor.focus(); } this._isVisible = false; diff --git a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts index b553cb5626e..03dcb8cc973 100644 --- a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts @@ -123,6 +123,10 @@ export class ExceptionWidget extends ZoneWidget { } override hasFocus(): boolean { - return dom.isAncestor(document.activeElement, this.container); + if (!this.container) { + return false; + } + + return dom.isAncestor(this.container.ownerDocument.activeElement, this.container); } } diff --git a/src/vs/workbench/contrib/files/browser/files.ts b/src/vs/workbench/contrib/files/browser/files.ts index 93474506645..9eaccff965a 100644 --- a/src/vs/workbench/contrib/files/browser/files.ts +++ b/src/vs/workbench/contrib/files/browser/files.ts @@ -62,7 +62,8 @@ export interface IExplorerView { function getFocus(listService: IListService): unknown | undefined { const list = listService.lastFocusedList; - if (list?.getHTMLElement() === document.activeElement) { + const element = list?.getHTMLElement(); + if (element && element === element.ownerDocument.activeElement) { let focus: unknown; if (list instanceof List) { const focused = list.getFocusedElements(); @@ -101,7 +102,8 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService, explorerService: IExplorerService): Array { const list = listService.lastFocusedList; - if (list?.getHTMLElement() === document.activeElement) { + const element = list?.getHTMLElement(); + if (element && element === element.ownerDocument.activeElement) { // Explorer if (list instanceof AsyncDataTree && list.getFocus().every(item => item instanceof ExplorerItem)) { // Explorer @@ -136,7 +138,8 @@ export function getMultiSelectedResources(resource: URI | object | undefined, li export function getOpenEditorsViewMultiSelection(listService: IListService, editorGroupService: IEditorGroupsService): Array | undefined { const list = listService.lastFocusedList; - if (list?.getHTMLElement() === document.activeElement) { + const element = list?.getHTMLElement(); + if (element && element === element.ownerDocument.activeElement) { // Open editors view if (list instanceof List) { const selection = coalesce(list.getSelectedElements().filter(s => s instanceof OpenEditor)); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts index 78948d62ba9..8a240876cba 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts @@ -30,6 +30,7 @@ import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ILogService } from 'vs/platform/log/common/log'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { showWindowLogActionId } from 'vs/workbench/services/log/common/logConstants'; +import { getActiveElement } from 'vs/base/browser/dom'; let _logging: boolean = false; function toggleLogging() { @@ -342,7 +343,7 @@ export class NotebookClipboardContribution extends Disposable { runCopyAction(accessor: ServicesAccessor) { const loggerService = accessor.get(ILogService); - const activeElement = document.activeElement; + const activeElement = getActiveElement(); if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { _log(loggerService, '[NotebookEditor] focus is on input or textarea element, bypass'); return false; @@ -364,7 +365,7 @@ export class NotebookClipboardContribution extends Disposable { } runPasteAction(accessor: ServicesAccessor) { - const activeElement = document.activeElement; + const activeElement = getActiveElement(); if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { return false; } @@ -385,7 +386,7 @@ export class NotebookClipboardContribution extends Disposable { } runCutAction(accessor: ServicesAccessor) { - const activeElement = document.activeElement; + const activeElement = getActiveElement(); if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { return false; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 45d2bfd68b1..92e3da3b294 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -174,8 +174,12 @@ export class NotebookEditor extends EditorPane implements INotebookEditorPane { } override hasFocus(): boolean { - const activeElement = document.activeElement; const value = this._widget.value; + if (!value) { + return false; + } + + const activeElement = value.getDomNode().ownerDocument.activeElement; return !!value && (DOM.isAncestor(activeElement, value.getDomNode() || DOM.isAncestor(activeElement, value.getOverflowContainerDomNode()))); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 7c1955bc425..e6ff93deb17 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1752,7 +1752,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD const element = this.viewModel.cellAt(focusRange.start); if (element) { const itemDOM = this._list.domElementOfElement(element); - const editorFocused = element.getEditState() === CellEditState.Editing && !!(document.activeElement && itemDOM && itemDOM.contains(document.activeElement)); + const editorFocused = element.getEditState() === CellEditState.Editing && !!(itemDOM && itemDOM.ownerDocument.activeElement && itemDOM.contains(itemDOM.ownerDocument.activeElement)); state.editorFocused = editorFocused; state.focus = focusRange.start; @@ -1959,7 +1959,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } private editorHasDomFocus(): boolean { - return DOM.isAncestor(document.activeElement, this.getDomNode()); + return DOM.isAncestor(this.getDomNode().ownerDocument.activeElement, this.getDomNode()); } updateEditorFocus() { @@ -2370,8 +2370,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } else { // focus container const itemDOM = this._list.domElementOfElement(cell); - if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) { - (document.activeElement as HTMLElement).blur(); + if (itemDOM && itemDOM.ownerDocument.activeElement && itemDOM.contains(itemDOM.ownerDocument.activeElement)) { + (itemDOM.ownerDocument.activeElement as HTMLElement).blur(); } cell.updateEditState(CellEditState.Preview, 'focusNotebookCell'); diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts index 4b052e9f813..9c73faa2c67 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts @@ -132,7 +132,7 @@ export class CellEditorStatusBar extends CellContentPart { if (this._editor) { // Focus Mode const updateFocusModeForEditorEvent = () => { - if (this._editor && (this._editor.hasWidgetFocus() || (document.activeElement && this.statusBarContainer.contains(document.activeElement)))) { + if (this._editor && (this._editor.hasWidgetFocus() || (this.statusBarContainer.ownerDocument.activeElement && this.statusBarContainer.contains(this.statusBarContainer.ownerDocument.activeElement)))) { element.focusMode = CellFocusMode.Editor; } else { const currentMode = element.focusMode; @@ -153,7 +153,7 @@ export class CellEditorStatusBar extends CellContentPart { // so we don't want to update the focus state too eagerly, it will be updated with onDidFocusEditorWidget if ( this._notebookEditor.hasEditorFocus() && - !(document.activeElement && this.statusBarContainer.contains(document.activeElement))) { + !(this.statusBarContainer.ownerDocument.activeElement && this.statusBarContainer.contains(this.statusBarContainer.ownerDocument.activeElement))) { updateFocusModeForEditorEvent(); } })); diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts index 694892adf88..9cdaa9b4f84 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts @@ -243,7 +243,8 @@ export class CellTitleToolbarPart extends CellOverlayPart { } private updateActions(toolbar: ToolBar, actions: { primary: IAction[]; secondary: IAction[] }) { - const hadFocus = DOM.isAncestor(document.activeElement, toolbar.getElement()); + const element = toolbar.getElement(); + const hadFocus = DOM.isAncestor(element.ownerDocument.activeElement, element); toolbar.setActions(actions.primary, actions.secondary); if (hadFocus) { this._notebookEditor.focus(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts index e11d95769cb..b8a9a6b9e0e 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts @@ -512,7 +512,7 @@ export class MarkupCell extends Disposable { // this is for a special case: // users click the status bar empty space, which we will then focus the editor // so we don't want to update the focus state too eagerly - if (document.activeElement?.contains(this.templateData.container)) { + if (this.templateData.container.ownerDocument.activeElement?.contains(this.templateData.container)) { this.focusSwitchDisposable.value = disposableTimeout(() => updateFocusMode(), 300); } else { updateFocusMode(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 4fd0e33392e..95368e59d7a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -522,7 +522,7 @@ export class NotebookCellList extends WorkbenchList implements ID return; } - const focusInside = DOM.isAncestor(document.activeElement, this.rowsContainer); + const focusInside = DOM.isAncestor(this.rowsContainer.ownerDocument.activeElement, this.rowsContainer); super.splice(start, deleteCount, elements); if (focusInside) { this.domFocus(); @@ -1230,12 +1230,12 @@ export class NotebookCellList extends WorkbenchList implements ID const focused = this.getFocusedElements()[0]; const focusedDomElement = focused && this.domElementOfElement(focused); - if (document.activeElement && focusedDomElement && focusedDomElement.contains(document.activeElement)) { + if (this.view.domNode.ownerDocument.activeElement && focusedDomElement && focusedDomElement.contains(this.view.domNode.ownerDocument.activeElement)) { // for example, when focus goes into monaco editor, if we refocus the list view, the editor will lose focus. return; } - if (!isMacintosh && document.activeElement && isContextMenuFocused()) { + if (!isMacintosh && this.view.domNode.ownerDocument.activeElement && !!DOM.findParentWithClass(this.view.domNode.ownerDocument.activeElement, 'context-view')) { return; } @@ -1467,7 +1467,3 @@ function getEditorAttachedPromise(element: ICellViewModel) { Event.once(element.onDidChangeEditorAttachState)(() => element.editorAttached ? resolve() : reject()); }); } - -function isContextMenuFocused() { - return !!DOM.findParentWithClass(document.activeElement, 'context-view'); -} diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 6bf05c15a82..4531a26a590 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -682,7 +682,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon return; } - if (document.activeElement?.classList.contains('monaco-list')) { + const activeElement = preferencesEditor.getContainer()?.ownerDocument.activeElement; + if (activeElement?.classList.contains('monaco-list')) { preferencesEditor.focusSettings(true); } } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 68435481031..6c62ce5175b 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -962,7 +962,7 @@ export class SettingsEditor2 extends EditorPane { })); this._register(this.settingsTree.onDidFocus(() => { - const classList = document.activeElement?.classList; + const classList = container.ownerDocument.activeElement?.classList; if (classList && classList.contains('monaco-list') && classList.contains('settings-editor-tree')) { this._currentFocusContext = SettingsFocusContext.SettingTree; this.settingRowFocused.set(true); @@ -1406,8 +1406,10 @@ export class SettingsEditor2 extends EditorPane { } private getActiveControlInSettingsTree(): HTMLElement | null { - return (document.activeElement && DOM.isAncestor(document.activeElement, this.settingsTree.getHTMLElement())) ? - document.activeElement : + const element = this.settingsTree.getHTMLElement(); + const activeElement = element.ownerDocument.activeElement; + return (activeElement && DOM.isAncestor(activeElement, element)) ? + activeElement : null; } @@ -1467,7 +1469,7 @@ export class SettingsEditor2 extends EditorPane { } private contextViewFocused(): boolean { - return !!DOM.findParentWithClass(document.activeElement, 'context-view'); + return !!DOM.findParentWithClass(this.rootElement.ownerDocument.activeElement, 'context-view'); } private refreshTree(): void { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index 153c429dc21..38aab1dbc5d 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -193,7 +193,7 @@ export abstract class AbstractListSettingWidget extend } protected renderList(): void { - const focused = DOM.isAncestor(document.activeElement, this.listElement); + const focused = DOM.isAncestor(this.listElement.ownerDocument.activeElement, this.listElement); DOM.clearNode(this.listElement); this.listDisposables.clear(); diff --git a/src/vs/workbench/contrib/search/browser/searchActionsBase.ts b/src/vs/workbench/contrib/search/browser/searchActionsBase.ts index 92cbc8b0e91..16fe2b25f11 100644 --- a/src/vs/workbench/contrib/search/browser/searchActionsBase.ts +++ b/src/vs/workbench/contrib/search/browser/searchActionsBase.ts @@ -16,7 +16,7 @@ export const category = { value: nls.localize('search', "Search"), original: 'Se export function isSearchViewFocused(viewsService: IViewsService): boolean { const searchView = getSearchView(viewsService); - const activeElement = document.activeElement; + const activeElement = searchView?.getContainer().ownerDocument.activeElement; return !!(searchView && activeElement && DOM.isAncestor(activeElement, searchView.getContainer())); } diff --git a/src/vs/workbench/contrib/search/browser/searchActionsNav.ts b/src/vs/workbench/contrib/search/browser/searchActionsNav.ts index 461079d71c8..b90ae42c06f 100644 --- a/src/vs/workbench/contrib/search/browser/searchActionsNav.ts +++ b/src/vs/workbench/contrib/search/browser/searchActionsNav.ts @@ -24,6 +24,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ToggleCaseSensitiveKeybinding, TogglePreserveCaseKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding } from 'vs/editor/contrib/find/browser/findModel'; import { category, getSearchView, openSearchView } from 'vs/workbench/contrib/search/browser/searchActionsBase'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; +import { getActiveElement } from 'vs/base/browser/dom'; //#region Actions: Changing Search Input Options registerAction2(class ToggleQueryDetailsAction extends Action2 { @@ -43,7 +44,7 @@ registerAction2(class ToggleQueryDetailsAction extends Action2 { }); } run(accessor: ServicesAccessor, ...args: any[]) { - const contextService = accessor.get(IContextKeyService).getContext(document.activeElement); + const contextService = accessor.get(IContextKeyService).getContext(getActiveElement()); if (contextService.getValue(SearchEditorConstants.InSearchEditor.serialize())) { (accessor.get(IEditorService).activeEditorPane as SearchEditor).toggleQueryDetails(args[0]?.show); } else if (contextService.getValue(Constants.SearchViewFocusedKey.serialize())) { diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts index 6c2829476ac..1457698d8a4 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts @@ -37,6 +37,7 @@ import { IWorkingCopyEditorHandler, IWorkingCopyEditorService } from 'vs/workben import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkingCopyIdentifier } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { getActiveElement } from 'vs/base/browser/dom'; const OpenInEditorCommandId = 'search.action.openInEditor'; @@ -241,7 +242,7 @@ registerAction2(class extends Action2 { } async run(accessor: ServicesAccessor) { - const contextService = accessor.get(IContextKeyService).getContext(document.activeElement); + const contextService = accessor.get(IContextKeyService).getContext(getActiveElement()); if (contextService.getValue(SearchEditorConstants.InSearchEditor.serialize())) { (accessor.get(IEditorService).activeEditorPane as SearchEditor).deleteResultBlock(); } diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts index 811b21608bb..ac70756c3ea 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts @@ -1574,7 +1574,7 @@ export class GettingStartedPage extends EditorPane { } override focus() { - const active = document.activeElement; + const active = this.container.ownerDocument.activeElement; let parent = this.container.parentElement; while (parent && parent !== active) { diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts index 3a411232561..002c6ef9c5f 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts @@ -224,7 +224,7 @@ export class WalkThroughPart extends EditorPane { } override focus(): void { - let active = document.activeElement; + let active = this.content.ownerDocument.activeElement; while (active && active !== this.content) { active = active.parentElement; } diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts index 59d1c84e515..f569b65a25c 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts @@ -716,7 +716,7 @@ export class WorkspaceTrustEditor extends EditorPane { if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow)) { const navOrder = [this.headerContainer, this.trustedContainer, this.untrustedContainer, this.configurationContainer]; const currentIndex = navOrder.findIndex(element => { - return isAncestor(document.activeElement, element); + return isAncestor(element.ownerDocument.activeElement, element); }); let newIndex = currentIndex; diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 89caff6467a..de1a0d80812 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { onUnexpectedError } from 'vs/base/common/errors'; import { equals } from 'vs/base/common/objects'; -import { EventType, EventHelper, addDisposableListener, ModifierKeyEmitter } from 'vs/base/browser/dom'; +import { EventType, EventHelper, addDisposableListener, ModifierKeyEmitter, getActiveElement } from 'vs/base/browser/dom'; import { Separator, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions'; import { IFileService } from 'vs/platform/files/common/files'; import { EditorResourceAccessor, IUntitledTextResourceEditorInput, SideBySideEditor, pathsToEditors, IResourceDiffEditorInput, IUntypedEditorInput, IEditorPane, isResourceEditorInput, IResourceMergeEditorInput } from 'vs/workbench/common/editor'; @@ -174,8 +174,9 @@ export class NativeWindow extends Disposable { // Support runKeybinding event ipcRenderer.on('vscode:runKeybinding', (event: unknown, request: INativeRunKeybindingInWindowRequest) => { - if (document.activeElement) { - this.keybindingService.dispatchByUserSettingsLabel(request.userSettingsLabel, document.activeElement); + const activeElement = getActiveElement(); + if (activeElement) { + this.keybindingService.dispatchByUserSettingsLabel(request.userSettingsLabel, activeElement); } }); diff --git a/src/vs/workbench/services/hover/browser/hoverService.ts b/src/vs/workbench/services/hover/browser/hoverService.ts index b5626640b35..cd9bbe9fcdf 100644 --- a/src/vs/workbench/services/hover/browser/hoverService.ts +++ b/src/vs/workbench/services/hover/browser/hoverService.ts @@ -13,7 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { HoverWidget } from 'vs/workbench/services/hover/browser/hoverWidget'; import { IContextViewProvider, IDelegate } from 'vs/base/browser/ui/contextview/contextview'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { addDisposableListener, EventType } from 'vs/base/browser/dom'; +import { addDisposableListener, EventType, getActiveElement } from 'vs/base/browser/dom'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver'; @@ -45,10 +45,11 @@ export class HoverService implements IHoverService { this._currentHoverOptions = options; this._lastHoverOptions = options; const trapFocus = options.trapFocus || this._accessibilityService.isScreenReaderOptimized(); + const activeElement = getActiveElement(); // HACK, remove this check when #189076 is fixed if (!skipLastFocusedUpdate) { - if (trapFocus && document.activeElement) { - this._lastFocusedElementBeforeOpen = document.activeElement as HTMLElement; + if (trapFocus && activeElement) { + this._lastFocusedElementBeforeOpen = activeElement as HTMLElement; } else { this._lastFocusedElementBeforeOpen = undefined; } @@ -79,7 +80,7 @@ export class HoverService implements IHoverService { } else { hoverDisposables.add(addDisposableListener(options.target, EventType.CLICK, () => this.hideHover())); } - const focusedElement = document.activeElement; + const focusedElement = getActiveElement(); if (focusedElement) { hoverDisposables.add(addDisposableListener(focusedElement, EventType.KEY_DOWN, e => this._keyDown(e, hover, !!options.hideOnKeyDown))); hoverDisposables.add(addDisposableListener(document, EventType.KEY_DOWN, e => this._keyDown(e, hover, !!options.hideOnKeyDown))); From 712a1b5455f0b9ca620472f5334652142dd97cf8 Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 17 Oct 2023 15:24:41 +0200 Subject: [PATCH 183/290] - remove diff locking - Remove unused variable and property in InlineChatLivePreviewWidget --- .../inlineChat/browser/inlineChatLivePreviewWidget.ts | 10 ---------- .../inlineChat/browser/inlineChatStrategies.ts | 11 ++--------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index e4a8b22b0aa..63e66be5f3d 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -46,7 +46,6 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { private readonly _diffEditor: IDiffEditor; private _dim: Dimension | undefined; private _isVisible: boolean = false; - private _isDiffLocked: boolean = false; constructor( editor: ICodeEditor, @@ -141,7 +140,6 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { override show(): void { assertType(this.editor.hasModel()); this._sessionStore.clear(); - this._isDiffLocked = false; this._isVisible = true; this._sessionStore.add(this._diffEditor.onDidUpdateDiff(() => { @@ -159,17 +157,9 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { this._updateFromChanges(this._session.wholeRange.value, this._session.lastTextModelChanges); } - lockToDiff(): void { - this._isDiffLocked = true; - } - private _updateFromChanges(range: Range, changes: readonly DetailedLineRangeMapping[]): void { assertType(this.editor.hasModel()); - if (this._isDiffLocked) { - return; - } - if (changes.length === 0 || this._session.textModel0.getValueLength() === 0) { // no change or changes to an empty file this._logService.debug('[IE] livePreview-mode: no diff'); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 95480e8fb06..8cdcaa4998d 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -238,7 +238,6 @@ export class LiveStrategy extends EditModeStrategy { protected readonly _session: Session, protected readonly _editor: ICodeEditor, protected readonly _widget: InlineChatWidget, - @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService configService: IConfigurationService, @IStorageService protected _storageService: IStorageService, @IBulkEditService protected readonly _bulkEditService: IBulkEditService, @@ -390,14 +389,13 @@ export class LivePreviewStrategy extends LiveStrategy { session: Session, editor: ICodeEditor, widget: InlineChatWidget, - @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService configService: IConfigurationService, @IStorageService storageService: IStorageService, @IBulkEditService bulkEditService: IBulkEditService, @IEditorWorkerService editorWorkerService: IEditorWorkerService, @IInstantiationService instaService: IInstantiationService, ) { - super(session, editor, widget, contextKeyService, configService, storageService, bulkEditService, editorWorkerService, instaService); + super(session, editor, widget, configService, storageService, bulkEditService, editorWorkerService, instaService); this._diffZone = new Lazy(() => instaService.createInstance(InlineChatLivePreviewWidget, editor, session)); this._previewZone = new Lazy(() => instaService.createInstance(InlineChatFileCreatePreviewWidget, editor)); @@ -431,11 +429,6 @@ export class LivePreviewStrategy extends LiveStrategy { } } - override async undoChanges(response: EditResponse): Promise { - this._diffZone.value.lockToDiff(); - super.undoChanges(response); - } - protected override _doToggleDiff(): void { const scrollState = StableEditorScrollState.capture(this._editor); if (this._diffEnabled) { @@ -447,7 +440,7 @@ export class LivePreviewStrategy extends LiveStrategy { } override hasFocus(): boolean { - return super.hasFocus() || this._diffZone.value.hasFocus() || this._previewZone.value.hasFocus(); + return super.hasFocus() || Boolean(this._diffZone.rawValue?.hasFocus()) || Boolean(this._previewZone.rawValue?.hasFocus()); } override getWidgetPosition(): Position | undefined { From 787ed646a3c7867edf7b932547de840125b8aba0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2023 15:43:35 +0200 Subject: [PATCH 184/290] aux window - add and use `DOM` utilities for checking active element (#195797) --- src/vs/base/browser/dom.ts | 16 ++++++++++++++++ .../browser/ui/breadcrumbs/breadcrumbsWidget.ts | 9 +-------- src/vs/base/browser/ui/button/button.ts | 4 ++-- .../base/browser/ui/contextview/contextview.ts | 8 ++++---- src/vs/base/browser/ui/dialog/dialog.ts | 4 ++-- src/vs/base/browser/ui/inputbox/inputBox.ts | 4 ++-- src/vs/base/browser/ui/list/listPaging.ts | 4 ++-- src/vs/base/browser/ui/list/listWidget.ts | 4 ++-- src/vs/base/browser/ui/toggle/toggle.ts | 3 ++- src/vs/base/browser/ui/tree/abstractTree.ts | 5 ++--- .../browser/contextScopedHistoryWidget.ts | 3 ++- src/vs/platform/list/browser/listService.ts | 5 ++--- .../quickinput/browser/quickInputController.ts | 2 +- src/vs/workbench/browser/actions/listCommands.ts | 3 ++- .../browser/parts/editor/editorGroupView.ts | 4 ++-- .../browser/parts/statusbar/statusbarModel.ts | 4 ++-- .../accessibility/browser/accessibleView.ts | 5 ++--- .../workbench/contrib/chat/browser/chatQuick.ts | 2 +- .../contrib/comments/browser/commentsView.ts | 2 +- .../contrib/debug/browser/debugHover.ts | 2 +- .../contrib/debug/browser/exceptionWidget.ts | 2 +- src/vs/workbench/contrib/files/browser/files.ts | 7 ++++--- .../contrib/notebook/browser/notebookEditor.ts | 4 +--- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../browser/view/cellParts/cellToolbars.ts | 3 +-- .../notebook/browser/view/notebookCellList.ts | 2 +- .../preferences/browser/settingsEditor2.ts | 2 +- .../preferences/browser/settingsWidgets.ts | 2 +- .../contrib/search/browser/searchActionsBase.ts | 3 +-- .../workspace/browser/workspaceTrustEditor.ts | 4 ++-- 30 files changed, 65 insertions(+), 59 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 97743d5a097..d8302103599 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -717,6 +717,22 @@ export function getActiveElement(): Element | null { return result; } +/** + * Returns whether the active element of the `document` that owns + * the `element` is `element`. + */ +export function isActiveElement(element: Element): boolean { + return element.ownerDocument.activeElement === element; +} + +/** + * Returns whether the active element of the `document` that owns + * the `ancestor` is contained in `ancestor`. + */ +export function isAncestorOfActiveElement(ancestor: Element): boolean { + return isAncestor(ancestor.ownerDocument.activeElement, ancestor); +} + /** * Returns the active document across all child windows. * Use this instead of `document` when reacting to dom events to handle multiple windows. diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index 9324517f3ef..3775611c73a 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -177,14 +177,7 @@ export class BreadcrumbsWidget { } isDOMFocused(): boolean { - let candidate = this._domNode.ownerDocument.activeElement; - while (candidate) { - if (this._domNode === candidate) { - return true; - } - candidate = candidate.parentElement; - } - return false; + return dom.isAncestorOfActiveElement(this._domNode); } getFocused(): BreadcrumbsItem { diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index 13b4351f53c..5550ff19c50 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IContextMenuProvider } from 'vs/base/browser/contextmenu'; -import { addDisposableListener, EventHelper, EventType, IFocusTracker, reset, trackFocus } from 'vs/base/browser/dom'; +import { addDisposableListener, EventHelper, EventType, IFocusTracker, isActiveElement, reset, trackFocus } from 'vs/base/browser/dom'; import { sanitize } from 'vs/base/browser/dompurify/dompurify'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { renderMarkdown, renderStringAsPlaintext } from 'vs/base/browser/markdownRenderer'; @@ -281,7 +281,7 @@ export class Button extends Disposable implements IButton { } hasFocus(): boolean { - return this._element === this._element.ownerDocument.activeElement; + return isActiveElement(this._element); } } diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 816e91ac819..d8156d1b3bb 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -195,13 +195,13 @@ export class ContextView extends Disposable { const toDisposeOnSetContainer = new DisposableStore(); ContextView.BUBBLE_UP_EVENTS.forEach(event => { - toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { + toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, e => { this.onDOMEvent(e, false); })); }); ContextView.BUBBLE_DOWN_EVENTS.forEach(event => { - toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { + toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, e => { this.onDOMEvent(e, true); }, true)); }); @@ -370,10 +370,10 @@ export class ContextView extends Disposable { return !!this.delegate; } - private onDOMEvent(e: Event, onCapture: boolean): void { + private onDOMEvent(e: UIEvent, onCapture: boolean): void { if (this.delegate) { if (this.delegate.onDOMEvent) { - this.delegate.onDOMEvent(e, this.view.ownerDocument.activeElement); + this.delegate.onDOMEvent(e, DOM.getWindow(e).document.activeElement); } else if (onCapture && !DOM.isAncestor(e.target, this.container)) { this.hide(); } diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index ca469d2a4b5..3842592da15 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, addDisposableListener, clearNode, EventHelper, EventType, getWindow, hide, isAncestor, show } from 'vs/base/browser/dom'; +import { $, addDisposableListener, clearNode, EventHelper, EventType, getWindow, hide, isActiveElement, isAncestor, show } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ButtonBar, ButtonWithDescription, IButtonStyles } from 'vs/base/browser/ui/button/button'; @@ -269,7 +269,7 @@ export class Dialog extends Disposable { const links = this.messageContainer.querySelectorAll('a'); for (const link of links) { focusableElements.push(link); - if (link === link.ownerDocument.activeElement) { + if (isActiveElement(link)) { focusedIndex = focusableElements.length - 1; } } diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 652031e1f30..da375f17187 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -287,7 +287,7 @@ export class InputBox extends Widget { } public hasFocus(): boolean { - return this.input.ownerDocument.activeElement === this.input; + return dom.isActiveElement(this.input); } public select(range: IRange | null = null): void { @@ -628,7 +628,7 @@ export class HistoryInputBox extends InputBox implements IHistoryNavigationWidge if (options.showHistoryHint && options.showHistoryHint() && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX) && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS) && this.history.getHistory().length) { const suffix = this.placeholder.endsWith(')') ? NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX : NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS; const suffixedPlaceholder = this.placeholder + suffix; - if (options.showPlaceholderOnFocus && this.input.ownerDocument.activeElement !== this.input) { + if (options.showPlaceholderOnFocus && !dom.isActiveElement(this.input)) { this.placeholder = suffixedPlaceholder; } else { diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 4780d4eb4e9..0175a15779d 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -12,6 +12,7 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import 'vs/css!./list'; import { IListContextMenuEvent, IListEvent, IListMouseEvent, IListRenderer, IListVirtualDelegate } from './list'; import { IListAccessibilityProvider, IListOptions, IListOptionsUpdate, IListStyles, List, TypeNavigationMode } from './listWidget'; +import { isActiveElement } from 'vs/base/browser/dom'; export interface IPagedRenderer extends IListRenderer { renderPlaceholder(index: number, templateData: TTemplateData): void; @@ -144,8 +145,7 @@ export class PagedList implements IDisposable { } isDOMFocused(): boolean { - const element = this.getHTMLElement(); - return element === element.ownerDocument.activeElement; + return isActiveElement(this.getHTMLElement()); } domFocus(): void { diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index d35e17838a6..60f2ee87f1e 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDragAndDropData } from 'vs/base/browser/dnd'; -import { asCssValueWithDefault, createStyleSheet, Dimension, EventHelper, getActiveElement, isMouseEvent } from 'vs/base/browser/dom'; +import { asCssValueWithDefault, createStyleSheet, Dimension, EventHelper, getActiveElement, isActiveElement, isMouseEvent } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Gesture } from 'vs/base/browser/touch'; @@ -1880,7 +1880,7 @@ export class List implements ISpliceable, IDisposable { } isDOMFocused(): boolean { - return this.view.domNode === this.view.domNode.ownerDocument.activeElement; + return isActiveElement(this.view.domNode); } getHTMLElement(): HTMLElement { diff --git a/src/vs/base/browser/ui/toggle/toggle.ts b/src/vs/base/browser/ui/toggle/toggle.ts index 6668f07a175..db5523e63b7 100644 --- a/src/vs/base/browser/ui/toggle/toggle.ts +++ b/src/vs/base/browser/ui/toggle/toggle.ts @@ -12,6 +12,7 @@ import { ThemeIcon } from 'vs/base/common/themables'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import 'vs/css!./toggle'; +import { isActiveElement } from 'vs/base/browser/dom'; export interface IToggleOpts extends IToggleStyles { readonly actionClassName?: string; @@ -252,7 +253,7 @@ export class Checkbox extends Widget { } hasFocus(): boolean { - return this.domNode === this.domNode.ownerDocument.activeElement; + return isActiveElement(this.domNode); } protected applyStyles(): void { diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index e3583691b22..cf8b2a58caa 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDragAndDropData } from 'vs/base/browser/dnd'; -import { $, append, clearNode, createStyleSheet, getWindow, h, hasParentWithClass } from 'vs/base/browser/dom'; +import { $, append, clearNode, createStyleSheet, getWindow, h, hasParentWithClass, isActiveElement } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -1781,8 +1781,7 @@ export abstract class AbstractTree implements IDisposable } isDOMFocused(): boolean { - const element = this.getHTMLElement(); - return element === element.ownerDocument.activeElement; + return isActiveElement(this.getHTMLElement()); } layout(height?: number, width?: number): void { diff --git a/src/vs/platform/history/browser/contextScopedHistoryWidget.ts b/src/vs/platform/history/browser/contextScopedHistoryWidget.ts index d1f0d0e026b..a1ba7444f2e 100644 --- a/src/vs/platform/history/browser/contextScopedHistoryWidget.ts +++ b/src/vs/platform/history/browser/contextScopedHistoryWidget.ts @@ -13,6 +13,7 @@ import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from ' import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { localize } from 'vs/nls'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { isActiveElement } from 'vs/base/browser/dom'; export const historyNavigationVisible = new RawContextKey('suggestWidgetVisible', false, localize('suggestWidgetVisible', "Whether suggestion are visible")); @@ -52,7 +53,7 @@ export function registerAndCreateHistoryNavigationContext(scopedContextKeyServic }; // Check for currently being focused - if (widget.element === widget.element.ownerDocument.activeElement) { + if (isActiveElement(widget.element)) { onDidFocus(); } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 24934d72817..f2dd5ce5c54 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createStyleSheet, isKeyboardEvent } from 'vs/base/browser/dom'; +import { createStyleSheet, isActiveElement, isKeyboardEvent } from 'vs/base/browser/dom'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { IListMouseEvent, IListRenderer, IListTouchEvent, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedListOptions, IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging'; @@ -92,8 +92,7 @@ export class ListService implements IListService { this.lists.push(registeredList); // Check for currently being focused - const element = widget.getHTMLElement(); - if (element === element.ownerDocument.activeElement) { + if (isActiveElement(widget.getHTMLElement())) { this.setLastFocusedList(widget); } diff --git a/src/vs/platform/quickinput/browser/quickInputController.ts b/src/vs/platform/quickinput/browser/quickInputController.ts index b54708fbc6d..acf5b64feb0 100644 --- a/src/vs/platform/quickinput/browser/quickInputController.ts +++ b/src/vs/platform/quickinput/browser/quickInputController.ts @@ -587,7 +587,7 @@ export class QuickInputController extends Disposable { } const container = this.ui?.container; - const focusChanged = container && !dom.isAncestor(container.ownerDocument.activeElement, container); + const focusChanged = container && !dom.isAncestorOfActiveElement(container); this.controller = null; this.onHideEmitter.fire(); this.getUI().container.style.display = 'none'; diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index f97f3c7d387..0585cdfaec4 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -18,6 +18,7 @@ import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { Table } from 'vs/base/browser/ui/table/tableWidget'; import { AbstractTree, TreeFindMode } from 'vs/base/browser/ui/tree/abstractTree'; +import { isActiveElement } from 'vs/base/browser/dom'; function ensureDOMFocus(widget: ListWidget | undefined): void { // it can happen that one of the commands is executed while @@ -25,7 +26,7 @@ function ensureDOMFocus(widget: ListWidget | undefined): void { // list/tree item. therefor we should ensure that the // list/tree has DOM focus again after the command ran. const element = widget?.getHTMLElement(); - if (element && element !== element.ownerDocument.activeElement) { + if (element && !isActiveElement(element)) { widget?.domFocus(); } } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index ae9cf39e8b8..bda45dfa508 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -11,7 +11,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { Emitter, Relay } from 'vs/base/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { Dimension, trackFocus, addDisposableListener, EventType, EventHelper, findParentWithClass, isAncestor, IDomNodePagePosition, isMouseEvent } from 'vs/base/browser/dom'; +import { Dimension, trackFocus, addDisposableListener, EventType, EventHelper, findParentWithClass, isAncestor, IDomNodePagePosition, isMouseEvent, isActiveElement } from 'vs/base/browser/dom'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; @@ -501,7 +501,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // stolen accidentally on startup when the user already // clicked somewhere. - if (this.groupsView.activeGroup === this && activeElement === this.editorContainer.ownerDocument.activeElement) { + if (this.groupsView.activeGroup === this && activeElement && isActiveElement(activeElement)) { this.focus(); } }); diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts b/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts index 4a6410c6acc..98c2fd7a37d 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarModel.ts @@ -5,7 +5,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { isStatusbarEntryLocation, IStatusbarEntryPriority, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar'; -import { hide, show, isAncestor } from 'vs/base/browser/dom'; +import { hide, show, isAncestorOfActiveElement } from 'vs/base/browser/dom'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Emitter } from 'vs/base/common/event'; @@ -174,7 +174,7 @@ export class StatusbarViewModel extends Disposable { } private getFocusedEntry(): IStatusbarViewModelEntry | undefined { - return this._entries.find(entry => isAncestor(entry.container.ownerDocument.activeElement, entry.container)); + return this._entries.find(entry => isAncestorOfActiveElement(entry.container)); } private focusEntry(delta: number, restartPosition: number): void { diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 01185eae7c8..21cd85094e7 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EventType, addDisposableListener } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, isActiveElement } from 'vs/base/browser/dom'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { alert } from 'vs/base/browser/ui/aria/aria'; @@ -526,8 +526,7 @@ export class AccessibleView extends Disposable { } })); disposableStore.add(this._editorWidget.onDidBlurEditorWidget(() => { - const element = this._toolbar.getElement(); - if (element.ownerDocument.activeElement !== element) { + if (!isActiveElement(this._toolbar.getElement())) { this._contextViewService.hideContextView(); } })); diff --git a/src/vs/workbench/contrib/chat/browser/chatQuick.ts b/src/vs/workbench/contrib/chat/browser/chatQuick.ts index ff0b2a3cc11..48f8a2e981a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatQuick.ts +++ b/src/vs/workbench/contrib/chat/browser/chatQuick.ts @@ -50,7 +50,7 @@ export class QuickChatService extends Disposable implements IQuickChatService { if (!widget) { return false; } - return dom.isAncestor(widget.ownerDocument.activeElement, widget); + return dom.isAncestorOfActiveElement(widget); } toggle(providerId?: string, query?: string | undefined): void { diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index a177a4eb3a3..630070ec866 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -226,7 +226,7 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView { public override focus(): void { const element = this.tree?.getHTMLElement(); - if (element && element === element.ownerDocument.activeElement) { + if (element && dom.isActiveElement(element)) { return; } diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index cc2931dd90f..e3a13a946d1 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -341,7 +341,7 @@ export class DebugHoverWidget implements IContentWidget { return; } - if (dom.isAncestor(this.domNode.ownerDocument.activeElement, this.domNode)) { + if (dom.isAncestorOfActiveElement(this.domNode)) { this.editor.focus(); } this._isVisible = false; diff --git a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts index 03dcb8cc973..1b920801dec 100644 --- a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts @@ -127,6 +127,6 @@ export class ExceptionWidget extends ZoneWidget { return false; } - return dom.isAncestor(this.container.ownerDocument.activeElement, this.container); + return dom.isAncestorOfActiveElement(this.container); } } diff --git a/src/vs/workbench/contrib/files/browser/files.ts b/src/vs/workbench/contrib/files/browser/files.ts index 9eaccff965a..4d452eb4e85 100644 --- a/src/vs/workbench/contrib/files/browser/files.ts +++ b/src/vs/workbench/contrib/files/browser/files.ts @@ -17,6 +17,7 @@ import { IEditableData } from 'vs/workbench/common/views'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ResourceFileEdit } from 'vs/editor/browser/services/bulkEditService'; import { ProgressLocation } from 'vs/platform/progress/common/progress'; +import { isActiveElement } from 'vs/base/browser/dom'; export interface IExplorerService { readonly _serviceBrand: undefined; @@ -63,7 +64,7 @@ export interface IExplorerView { function getFocus(listService: IListService): unknown | undefined { const list = listService.lastFocusedList; const element = list?.getHTMLElement(); - if (element && element === element.ownerDocument.activeElement) { + if (element && isActiveElement(element)) { let focus: unknown; if (list instanceof List) { const focused = list.getFocusedElements(); @@ -103,7 +104,7 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService, explorerService: IExplorerService): Array { const list = listService.lastFocusedList; const element = list?.getHTMLElement(); - if (element && element === element.ownerDocument.activeElement) { + if (element && isActiveElement(element)) { // Explorer if (list instanceof AsyncDataTree && list.getFocus().every(item => item instanceof ExplorerItem)) { // Explorer @@ -139,7 +140,7 @@ export function getMultiSelectedResources(resource: URI | object | undefined, li export function getOpenEditorsViewMultiSelection(listService: IListService, editorGroupService: IEditorGroupsService): Array | undefined { const list = listService.lastFocusedList; const element = list?.getHTMLElement(); - if (element && element === element.ownerDocument.activeElement) { + if (element && isActiveElement(element)) { // Open editors view if (list instanceof List) { const selection = coalesce(list.getSelectedElements().filter(s => s instanceof OpenEditor)); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 92e3da3b294..7bcd5a348d9 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -179,9 +179,7 @@ export class NotebookEditor extends EditorPane implements INotebookEditorPane { return false; } - const activeElement = value.getDomNode().ownerDocument.activeElement; - - return !!value && (DOM.isAncestor(activeElement, value.getDomNode() || DOM.isAncestor(activeElement, value.getOverflowContainerDomNode()))); + return !!value && (DOM.isAncestorOfActiveElement(value.getDomNode() || DOM.isAncestorOfActiveElement(value.getOverflowContainerDomNode()))); } override async setInput(input: NotebookEditorInput, options: INotebookEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken, noRetry?: boolean): Promise { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index e6ff93deb17..03772b8851d 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1959,7 +1959,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } private editorHasDomFocus(): boolean { - return DOM.isAncestor(this.getDomNode().ownerDocument.activeElement, this.getDomNode()); + return DOM.isAncestorOfActiveElement(this.getDomNode()); } updateEditorFocus() { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts index 9cdaa9b4f84..cb17a31e17a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts @@ -243,8 +243,7 @@ export class CellTitleToolbarPart extends CellOverlayPart { } private updateActions(toolbar: ToolBar, actions: { primary: IAction[]; secondary: IAction[] }) { - const element = toolbar.getElement(); - const hadFocus = DOM.isAncestor(element.ownerDocument.activeElement, element); + const hadFocus = DOM.isAncestorOfActiveElement(toolbar.getElement()); toolbar.setActions(actions.primary, actions.secondary); if (hadFocus) { this._notebookEditor.focus(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 95368e59d7a..2e7c3b805f8 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -522,7 +522,7 @@ export class NotebookCellList extends WorkbenchList implements ID return; } - const focusInside = DOM.isAncestor(this.rowsContainer.ownerDocument.activeElement, this.rowsContainer); + const focusInside = DOM.isAncestorOfActiveElement(this.rowsContainer); super.splice(start, deleteCount, elements); if (focusInside) { this.domFocus(); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 6c62ce5175b..0a9cb4fd924 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -1408,7 +1408,7 @@ export class SettingsEditor2 extends EditorPane { private getActiveControlInSettingsTree(): HTMLElement | null { const element = this.settingsTree.getHTMLElement(); const activeElement = element.ownerDocument.activeElement; - return (activeElement && DOM.isAncestor(activeElement, element)) ? + return (activeElement && DOM.isAncestorOfActiveElement(element)) ? activeElement : null; } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index 38aab1dbc5d..6675881177f 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -193,7 +193,7 @@ export abstract class AbstractListSettingWidget extend } protected renderList(): void { - const focused = DOM.isAncestor(this.listElement.ownerDocument.activeElement, this.listElement); + const focused = DOM.isAncestorOfActiveElement(this.listElement); DOM.clearNode(this.listElement); this.listDisposables.clear(); diff --git a/src/vs/workbench/contrib/search/browser/searchActionsBase.ts b/src/vs/workbench/contrib/search/browser/searchActionsBase.ts index 16fe2b25f11..537f3f9614d 100644 --- a/src/vs/workbench/contrib/search/browser/searchActionsBase.ts +++ b/src/vs/workbench/contrib/search/browser/searchActionsBase.ts @@ -16,8 +16,7 @@ export const category = { value: nls.localize('search', "Search"), original: 'Se export function isSearchViewFocused(viewsService: IViewsService): boolean { const searchView = getSearchView(viewsService); - const activeElement = searchView?.getContainer().ownerDocument.activeElement; - return !!(searchView && activeElement && DOM.isAncestor(activeElement, searchView.getContainer())); + return !!(searchView && DOM.isAncestorOfActiveElement(searchView.getContainer())); } export function appendKeyBindingLabel(label: string, inputKeyBinding: ResolvedKeybinding | undefined): string { diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts index f569b65a25c..37c5b161e4e 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, addDisposableListener, addStandardDisposableListener, append, clearNode, Dimension, EventHelper, EventType, isAncestor } from 'vs/base/browser/dom'; +import { $, addDisposableListener, addStandardDisposableListener, append, clearNode, Dimension, EventHelper, EventType, isAncestorOfActiveElement } from 'vs/base/browser/dom'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ButtonBar } from 'vs/base/browser/ui/button/button'; import { IMessage, InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -716,7 +716,7 @@ export class WorkspaceTrustEditor extends EditorPane { if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow)) { const navOrder = [this.headerContainer, this.trustedContainer, this.untrustedContainer, this.configurationContainer]; const currentIndex = navOrder.findIndex(element => { - return isAncestor(element.ownerDocument.activeElement, element); + return isAncestorOfActiveElement(element); }); let newIndex = currentIndex; From 8e995eab98b594a9737d450f71df34d848cf4f31 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 17 Oct 2023 10:06:14 -0700 Subject: [PATCH 185/290] fix #195288 --- .../codeEditor/browser/accessibility/accessibility.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css index 5839e9f9aec..cda82e4a998 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css @@ -54,6 +54,8 @@ } .accessible-view.hide { - visibility: hidden; + position: fixed; + top: -2000px; + left:-2000px; pointer-events: none; } From b0df4bae21374688cb12702c1bd331a1790016f7 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2023 11:11:19 -0700 Subject: [PATCH 186/290] Fix tree data progress and other progress types in chat agents (#195817) --- .../api/browser/mainThreadChatAgents.ts | 2 +- .../api/browser/mainThreadChatAgents2.ts | 59 ++++++++++++++++--- .../workbench/api/common/extHost.protocol.ts | 4 +- .../api/common/extHostChatAgents2.ts | 19 ++++-- .../contrib/chat/common/chatAgents.ts | 7 +-- .../contrib/chat/common/chatServiceImpl.ts | 4 +- 6 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents.ts b/src/vs/workbench/api/browser/mainThreadChatAgents.ts index a5d719829f5..150da6ae90c 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents.ts @@ -41,7 +41,7 @@ export class MainThreadChatAgents implements MainThreadChatAgentsShape { metadata: revive(metadata), invoke: async (request, progress, history, token) => { const requestId = Math.random(); - this._pendingProgress.set(requestId, progress); + this._pendingProgress.set(requestId, { report: progress }); try { const message = request.command ? `/${request.command} ${request.message}` : request.message; const result = await this._proxy.$invokeAgent(handle, requestId, message, { history }, token); diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index 438583607e9..a80992df95d 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -3,11 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { DeferredPromise } from 'vs/base/common/async'; +import { IMarkdownString } from 'vs/base/common/htmlContent'; import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; -import { IProgress } from 'vs/platform/progress/common/progress'; -import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IExtensionChatAgentMetadata, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; +import { UriComponents } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IChatResponseProgressFileTreeData, IExtensionChatAgentMetadata, ILocationDto, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel'; import { IChatFollowup, IChatProgress, IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; @@ -22,9 +26,12 @@ type AgentData = { export class MainThreadChatAgents2 extends Disposable implements MainThreadChatAgentsShape2 { private readonly _agents = this._register(new DisposableMap()); - private readonly _pendingProgress = new Map>(); + private readonly _pendingProgress = new Map void>(); private readonly _proxy: ExtHostChatAgentsShape2; + private _responsePartHandlePool = 0; + private readonly _activeResponsePartPromises = new Map>(); + constructor( extHostContext: IExtHostContext, @IChatAgentService private readonly _chatAgentService: IChatAgentService, @@ -61,7 +68,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA id: name, metadata: revive(metadata), invoke: async (request, progress, history, token) => { - const requestId = Math.random(); // Make this a guid + const requestId = generateUuid(); this._pendingProgress.set(requestId, progress); try { return await this._proxy.$invokeAgent(handle, request.sessionId, requestId, request, { history }, token) ?? {}; @@ -95,8 +102,46 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA this._chatAgentService.updateAgent(data.name, revive(metadataUpdate)); } - async $handleProgressChunk(requestId: number, chunk: IChatResponseProgressDto): Promise { - // TODO copy/move $acceptResponseProgress from MainThreadChat - this._pendingProgress.get(requestId)?.report(revive(chunk) as any); + async $handleProgressChunk(requestId: string, progress: IChatResponseProgressDto, responsePartHandle?: number): Promise { + if ('placeholder' in progress) { + const handle = ++this._responsePartHandlePool; + const responsePartId = `${requestId}_${handle}`; + const deferredContentPromise = new DeferredPromise(); + this._activeResponsePartPromises.set(responsePartId, deferredContentPromise); + this._pendingProgress.get(requestId)?.({ ...progress, resolvedContent: deferredContentPromise.p }); + return handle; + } else if (typeof responsePartHandle === 'number') { + // Complete an existing deferred promise with resolved content + const responsePartId = `${requestId}_${responsePartHandle}`; + const deferredContentPromise = this._activeResponsePartPromises.get(responsePartId); + if (deferredContentPromise && isCompleteInteractiveProgressTreeData(progress)) { + const withRevivedUris = revive<{ treeData: IChatResponseProgressFileTreeData }>(progress); + deferredContentPromise.complete(withRevivedUris); + this._activeResponsePartPromises.delete(responsePartId); + } else if (deferredContentPromise && 'content' in progress) { + deferredContentPromise.complete(progress.content); + this._activeResponsePartPromises.delete(responsePartId); + } + return responsePartHandle; + } + + // No need to support standalone tree data that's not attached to a placeholder in API + if (isCompleteInteractiveProgressTreeData(progress)) { + return; + } + + // TS won't let us change the type of `progress` + let revivedProgress: IChatProgress; + if ('documents' in progress) { + revivedProgress = { documents: revive(progress.documents) }; + } else if ('reference' in progress) { + revivedProgress = revive<{ reference: UriComponents | ILocationDto }>(progress); + } else if ('inlineReference' in progress) { + revivedProgress = revive<{ inlineReference: UriComponents | ILocationDto; name?: string }>(progress); + } else { + revivedProgress = progress; + } + + this._pendingProgress.get(requestId)?.(revivedProgress); } } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 160a072b71a..969de0075e2 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1174,7 +1174,7 @@ export interface MainThreadChatAgentsShape2 extends IDisposable { $registerAgent(handle: number, name: string, metadata: IExtensionChatAgentMetadata): void; $updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void; $unregisterAgent(handle: number): void; - $handleProgressChunk(requestId: number, chunk: IChatResponseProgressDto): Promise; + $handleProgressChunk(requestId: string, chunk: IChatResponseProgressDto, responsePartHandle?: number): Promise; } export interface ExtHostChatAgentsShape { @@ -1182,7 +1182,7 @@ export interface ExtHostChatAgentsShape { } export interface ExtHostChatAgentsShape2 { - $invokeAgent(handle: number, sessionId: string, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise; + $invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise; $provideSlashCommands(handle: number, token: CancellationToken): Promise; $provideFollowups(handle: number, sessionId: string, token: CancellationToken): Promise; $acceptFeedback(handle: number, sessionId: string, vote: InteractiveSessionVoteDirection): void; diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 22849d610cf..c202d7b1031 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -48,7 +48,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return agent.apiAgent; } - async $invokeAgent(handle: number, sessionId: string, requestId: number, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise { + async $invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise { const agent = this._agents.get(handle); if (!agent) { throw new Error(`[CHAT](${handle}) CANNOT invoke agent because the agent is not registered`); @@ -78,10 +78,21 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { slashCommand }, { history: context.history.map(typeConvert.ChatMessage.to) }, - new Progress(p => { + new Progress(progress => { throwIfDone(); - const convertedProgress = typeConvert.ChatResponseProgress.from(p); - this._proxy.$handleProgressChunk(requestId, convertedProgress); + const convertedProgress = typeConvert.ChatResponseProgress.from(progress); + if ('placeholder' in progress && 'resolvedContent' in progress) { + const resolvedContent = Promise.all([this._proxy.$handleProgressChunk(requestId, convertedProgress), progress.resolvedContent]); + raceCancellation(resolvedContent, token).then(res => { + if (!res) { + return; /* Cancelled */ + } + const [progressHandle, progressContent] = res; + this._proxy.$handleProgressChunk(requestId, progressContent, progressHandle ?? undefined); + }); + } else { + this._proxy.$handleProgressChunk(requestId, convertedProgress); + } }), token ); diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index 886c5aa60a7..6a4867cec7e 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -9,7 +9,6 @@ import { Iterable } from 'vs/base/common/iterator'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IProgress } from 'vs/platform/progress/common/progress'; import { IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; import { IChatFollowup, IChatProgress, IChatResponseErrorDetails, IChatResponseProgressFileTreeData } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables'; @@ -19,7 +18,7 @@ import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chat export interface IChatAgent { id: string; metadata: IChatAgentMetadata; - invoke(request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise; + invoke(request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatMessage[], token: CancellationToken): Promise; provideFollowups?(sessionId: string, token: CancellationToken): Promise; provideSlashCommands(token: CancellationToken): Promise; } @@ -66,7 +65,7 @@ export interface IChatAgentService { _serviceBrand: undefined; readonly onDidChangeAgents: Event; registerAgent(agent: IChatAgent): IDisposable; - invokeAgent(id: string, request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise; + invokeAgent(id: string, request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatMessage[], token: CancellationToken): Promise; getFollowups(id: string, sessionId: string, token: CancellationToken): Promise; getAgents(): Array; getAgent(id: string): IChatAgent | undefined; @@ -131,7 +130,7 @@ export class ChatAgentService extends Disposable implements IChatAgentService { return data?.agent; } - async invokeAgent(id: string, request: IChatAgentRequest, progress: IProgress, history: IChatMessage[], token: CancellationToken): Promise { + async invokeAgent(id: string, request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatMessage[], token: CancellationToken): Promise { const data = this._agents.get(id); if (!data) { throw new Error(`No agent with id ${id}`); diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 8791a463620..0e7382192dd 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -529,9 +529,7 @@ export class ChatService extends Disposable implements IChatService { requestProps.message = varResult.prompt; } - const agentResult = await this.chatAgentService.invokeAgent(agent.id, requestProps, new Progress(p => { - progressCallback(p); - }), history, token); + const agentResult = await this.chatAgentService.invokeAgent(agent.id, requestProps, progressCallback, history, token); rawResponse = { session: model.session!, errorDetails: agentResult.errorDetails, From 569cf2b3d9b19d9294a28daaba3be4b88dfcf812 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 11:30:53 -0700 Subject: [PATCH 187/290] More minor follow up style tweaks --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index d5d5a10dce4..cbab68d1e76 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -332,10 +332,12 @@ .interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups .monaco-button { display: block; color: var(--vscode-textLink-foreground); + font-size: 12px; } .interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups code { font-family: var(--monaco-monospace-font); + font-size: 11px; } .interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups .monaco-button .codicon-sparkle { From c1434a84e8845732f5eca2d6664427616884c3ce Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Oct 2023 20:38:13 +0200 Subject: [PATCH 188/290] voice - improve CSS for when recording is running (#195819) --- .../actions/media/voiceChatActions.css | 28 ---------- .../actions/voiceChatActions.ts | 56 ++++++++++++++----- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css b/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css index d12f2d06eb2..1f105070d1e 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/media/voiceChatActions.css @@ -3,31 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/* - * Show a "microphone" icon when recording is in progress that glows via outline. - */ -.monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled), -.monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled) { - color: var(--vscode-voiceRecording-background); - outline: 1px solid var(--vscode-voiceRecording-background); - outline-offset: -1px; - animation: pulseAnimation 1s infinite; - border-radius: 50%; -} - -@keyframes pulseAnimation { - 0% { - outline-width: 1px; - } - 50% { - outline-width: 3px; - outline-color: var(--vscode-voiceRecording-dimmedBackground); - } - 100% { - outline-width: 1px; - } -} - /* * Replace with "microphone" icon. */ @@ -41,10 +16,7 @@ */ .monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover, .monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):hover { - color: inherit; - outline: none; animation: none; - border-radius: 5px; } /* diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index d99b19e6e1c..33a5497c6b8 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -33,8 +33,11 @@ import { isExecuteActionContext } from 'vs/workbench/contrib/chat/browser/action import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { ISpeechService, SpeechToTextStatus } from 'vs/workbench/contrib/speech/common/speechService'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { registerColor, transparent } from 'vs/platform/theme/common/colorRegistry'; +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ACTIVITY_BAR_BADGE_BACKGROUND } from 'vs/workbench/common/theme'; +import { ColorScheme } from 'vs/platform/theme/common/theme'; +import { Color } from 'vs/base/common/color'; +import { contrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; const CONTEXT_VOICE_CHAT_GETTING_READY = new RawContextKey('voiceChatGettingReady', false, { type: 'boolean', description: localize('voiceChatGettingReady', "True when getting ready for receiving voice input from the microphone for voice chat.") }); const CONTEXT_VOICE_CHAT_IN_PROGRESS = new RawContextKey('voiceChatInProgress', false, { type: 'boolean', description: localize('voiceChatInProgress', "True when voice recording from microphone is in progress for voice chat.") }); @@ -61,20 +64,6 @@ interface IVoiceChatSessionController { clearInputPlaceholder(): void; } -export const VOICE_RECORDING_BACKGROUND = registerColor('voiceRecording.background', { - dark: ACTIVITY_BAR_BADGE_BACKGROUND, - light: ACTIVITY_BAR_BADGE_BACKGROUND, - hcDark: ACTIVITY_BAR_BADGE_BACKGROUND, - hcLight: ACTIVITY_BAR_BADGE_BACKGROUND -}, localize('voiceRecording.background', "Background color for voice recording icon when recording.")); - -export const VOICE_RECORDING_BACKGROUND_DIMMED = registerColor('voiceRecording.dimmedBackground', { - dark: transparent(ACTIVITY_BAR_BADGE_BACKGROUND, 0.4), - light: transparent(ACTIVITY_BAR_BADGE_BACKGROUND, 0.4), - hcDark: ACTIVITY_BAR_BADGE_BACKGROUND, - hcLight: ACTIVITY_BAR_BADGE_BACKGROUND -}, localize('voiceRecording.dimmedBackground', "Dimmed background color for voice recording icon when recording.")); - class VoiceChatSessionControllerFactory { static create(accessor: ServicesAccessor, context: 'inline'): Promise; @@ -680,3 +669,40 @@ export class StopVoiceChatAndSubmitAction extends Action2 { VoiceChatSessions.getInstance(accessor.get(IInstantiationService)).accept(); } } + +registerThemingParticipant((theme, collector) => { + let activeRecordingColor: Color | undefined; + let activeRecordingDimmedColor: Color | undefined; + if (theme.type === ColorScheme.LIGHT || theme.type === ColorScheme.DARK) { + activeRecordingColor = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND) ?? theme.getColor(focusBorder); + activeRecordingDimmedColor = activeRecordingColor?.transparent(0.4); + } else { + activeRecordingColor = theme.getColor(contrastBorder); + activeRecordingDimmedColor = theme.getColor(contrastBorder); + } + + // Show a "microphone" icon when recording is in progress that glows via outline. + collector.addRule(` + .monaco-workbench .interactive-input-part .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):not(:hover), + .monaco-workbench .inline-chat .monaco-action-bar .action-label.codicon-loading.codicon-modifier-spin:not(.disabled):not(:hover) { + color: ${activeRecordingColor}; + outline: 1px solid ${activeRecordingColor}; + outline-offset: -1px; + animation: pulseAnimation 1s infinite; + border-radius: 50%; + } + + @keyframes pulseAnimation { + 0% { + outline-width: 1px; + } + 50% { + outline-width: 3px; + outline-color: ${activeRecordingDimmedColor}; + } + 100% { + outline-width: 1px; + } + } + `); +}); From f75db45b2f6f3f176037c37e1494821e55b375be Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 17 Oct 2023 11:38:25 -0700 Subject: [PATCH 189/290] cli: support signing in with msft account (#195820) For https://github.com/microsoft/vscode-remote-release/issues/8908 --- cli/src/auth.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cli/src/auth.rs b/cli/src/auth.rs index 0214b335247..4ada6d22b1f 100644 --- a/cli/src/auth.rs +++ b/cli/src/auth.rs @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ use crate::{ - constants::{get_default_user_agent, PRODUCT_NAME_LONG}, + constants::{get_default_user_agent, IS_INTERACTIVE_CLI, PRODUCT_NAME_LONG}, debug, error, info, log, state::{LauncherPaths, PersistedState}, trace, @@ -37,7 +37,7 @@ struct DeviceCodeResponse { expires_in: i64, } -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] struct AuthenticationResponse { access_token: String, refresh_token: Option, @@ -76,7 +76,7 @@ impl AuthProvider { pub fn code_uri(&self) -> &'static str { match self { AuthProvider::Microsoft => { - "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode" + "https://login.microsoftonline.com/organizations/oauth2/v2.0/devicecode" } AuthProvider::Github => "https://github.com/login/device/code", } @@ -84,7 +84,7 @@ impl AuthProvider { pub fn grant_uri(&self) -> &'static str { match self { - AuthProvider::Microsoft => "https://login.microsoftonline.com/common/oauth2/v2.0/token", + AuthProvider::Microsoft => "https://login.microsoftonline.com/organizations/oauth2/v2.0/token", AuthProvider::Github => "https://github.com/login/oauth/access_token", } } @@ -670,7 +670,11 @@ impl Auth { } async fn prompt_for_provider(&self) -> Result { - if std::env::var("VSCODE_CLI_ALLOW_MS_AUTH").is_err() { + if !*IS_INTERACTIVE_CLI { + info!( + self.log, + "Using Github for authentication, pass the `--provider` option to change this." + ); return Ok(AuthProvider::Github); } From 5d945cf09763dd36ba4a9fad907d940add16a43d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:50:45 -0700 Subject: [PATCH 190/290] Make xterm.js multi-window aware Fixes #195577 --- package.json | 14 ++--- remote/package.json | 14 ++--- remote/web/package.json | 10 ++-- remote/web/yarn.lock | 40 ++++++------- remote/yarn.lock | 56 +++++++++---------- .../terminal/browser/terminalInstance.ts | 6 ++ yarn.lock | 56 +++++++++---------- 7 files changed, 101 insertions(+), 95 deletions(-) diff --git a/package.json b/package.json index bfe56304cee..0a4ec7729cd 100644 --- a/package.json +++ b/package.json @@ -96,14 +96,14 @@ "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "9.0.0", - "xterm": "5.4.0-beta.31", - "xterm-addon-canvas": "0.6.0-beta.31", + "xterm": "5.4.0-beta.32", + "xterm-addon-canvas": "0.6.0-beta.32", "xterm-addon-image": "0.6.0-beta.21", - "xterm-addon-search": "0.14.0-beta.30", - "xterm-addon-serialize": "0.12.0-beta.30", - "xterm-addon-unicode11": "0.7.0-beta.30", - "xterm-addon-webgl": "0.17.0-beta.30", - "xterm-headless": "5.4.0-beta.31", + "xterm-addon-search": "0.14.0-beta.31", + "xterm-addon-serialize": "0.12.0-beta.31", + "xterm-addon-unicode11": "0.7.0-beta.31", + "xterm-addon-webgl": "0.17.0-beta.31", + "xterm-headless": "5.4.0-beta.32", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index a144d3f85b2..dbb57afa152 100644 --- a/remote/package.json +++ b/remote/package.json @@ -26,14 +26,14 @@ "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "9.0.0", - "xterm": "5.4.0-beta.31", - "xterm-addon-canvas": "0.6.0-beta.31", + "xterm": "5.4.0-beta.32", + "xterm-addon-canvas": "0.6.0-beta.32", "xterm-addon-image": "0.6.0-beta.21", - "xterm-addon-search": "0.14.0-beta.30", - "xterm-addon-serialize": "0.12.0-beta.30", - "xterm-addon-unicode11": "0.7.0-beta.30", - "xterm-addon-webgl": "0.17.0-beta.30", - "xterm-headless": "5.4.0-beta.31", + "xterm-addon-search": "0.14.0-beta.31", + "xterm-addon-serialize": "0.12.0-beta.31", + "xterm-addon-unicode11": "0.7.0-beta.31", + "xterm-addon-webgl": "0.17.0-beta.31", + "xterm-headless": "5.4.0-beta.32", "yauzl": "^2.9.2", "yazl": "^2.4.3" } diff --git a/remote/web/package.json b/remote/web/package.json index 0fb5ee2bcfc..2634c6ff3b8 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,11 +11,11 @@ "tas-client-umd": "0.1.8", "vscode-oniguruma": "1.7.0", "vscode-textmate": "9.0.0", - "xterm": "5.4.0-beta.31", - "xterm-addon-canvas": "0.6.0-beta.31", + "xterm": "5.4.0-beta.32", + "xterm-addon-canvas": "0.6.0-beta.32", "xterm-addon-image": "0.6.0-beta.21", - "xterm-addon-search": "0.14.0-beta.30", - "xterm-addon-unicode11": "0.7.0-beta.30", - "xterm-addon-webgl": "0.17.0-beta.30" + "xterm-addon-search": "0.14.0-beta.31", + "xterm-addon-unicode11": "0.7.0-beta.31", + "xterm-addon-webgl": "0.17.0-beta.31" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index bd6e5adf267..6eb7304ba80 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,32 +68,32 @@ vscode-textmate@9.0.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c" integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg== -xterm-addon-canvas@0.6.0-beta.31: - version "0.6.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb" - integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ== +xterm-addon-canvas@0.6.0-beta.32: + version "0.6.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9" + integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w== xterm-addon-image@0.6.0-beta.21: version "0.6.0-beta.21" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== -xterm-addon-search@0.14.0-beta.30: - version "0.14.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea" - integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ== +xterm-addon-search@0.14.0-beta.31: + version "0.14.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274" + integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg== -xterm-addon-unicode11@0.7.0-beta.30: - version "0.7.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3" - integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw== +xterm-addon-unicode11@0.7.0-beta.31: + version "0.7.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3" + integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ== -xterm-addon-webgl@0.17.0-beta.30: - version "0.17.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f" - integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q== +xterm-addon-webgl@0.17.0-beta.31: + version "0.17.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa" + integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ== -xterm@5.4.0-beta.31: - version "5.4.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174" - integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA== +xterm@5.4.0-beta.32: + version "5.4.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a" + integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA== diff --git a/remote/yarn.lock b/remote/yarn.lock index 4b7185b4ffa..b14b646d31c 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -591,45 +591,45 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-canvas@0.6.0-beta.31: - version "0.6.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb" - integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ== +xterm-addon-canvas@0.6.0-beta.32: + version "0.6.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9" + integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w== xterm-addon-image@0.6.0-beta.21: version "0.6.0-beta.21" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== -xterm-addon-search@0.14.0-beta.30: - version "0.14.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea" - integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ== +xterm-addon-search@0.14.0-beta.31: + version "0.14.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274" + integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg== -xterm-addon-serialize@0.12.0-beta.30: - version "0.12.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.30.tgz#80c4101f45a463ef139705bcd3dcaf0811f51ea4" - integrity sha512-nZP0ip5bd9LBoCTN9vCnn4iLatF4RRwzLupQf9r2N9x1bULzTZ1kAXAQe5gghsXjSEDDtyY2LzGigqTd2KVAqQ== +xterm-addon-serialize@0.12.0-beta.31: + version "0.12.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.31.tgz#2a95dc1e12f4097e2894b04c9cb8fff0bc0b858c" + integrity sha512-h2rWR+Lfi1Iv4VkLUlrBMYh5Mdq8vux2BKyCJe6a1ZnEu5Dzb0VuiNxfTKXTCT5M83nMn7TCB9TX0E8z6bs7xw== -xterm-addon-unicode11@0.7.0-beta.30: - version "0.7.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3" - integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw== +xterm-addon-unicode11@0.7.0-beta.31: + version "0.7.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3" + integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ== -xterm-addon-webgl@0.17.0-beta.30: - version "0.17.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f" - integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q== +xterm-addon-webgl@0.17.0-beta.31: + version "0.17.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa" + integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ== -xterm-headless@5.4.0-beta.31: - version "5.4.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.31.tgz#9538553c7426222f94d7da7ed467e699ebaeeedd" - integrity sha512-EE/ZlsZcBE5VOkjQU/KdRL4gvSkfrC2P7VxrmK1+PLc6+QMjPxs60A4Pun3mIIS0MFfN23p6hmN22GAXVckCXA== +xterm-headless@5.4.0-beta.32: + version "5.4.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.32.tgz#0d5cd35e1a0372888055ff0b06dfe17457979a6c" + integrity sha512-DQduq8KSoQZyRrQAFB+FkcY2UMxCW39P1/duOpksebc6PT9pbGkyPe5s+AdUQGiYzriEpzVtKUzDcquoVmpPhA== -xterm@5.4.0-beta.31: - version "5.4.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174" - integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA== +xterm@5.4.0-beta.32: + version "5.4.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a" + integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA== yallist@^4.0.0: version "4.0.0" diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index a7c08bc63d8..32bcc05c715 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -863,6 +863,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // The container changed, reattach this._container = container; this._container.appendChild(this._wrapperElement); + + // If xterm is already attached, call open again to pick up any changes to the window. + if (this.xterm?.raw.element) { + this.xterm.raw.open(this.xterm.raw.element); + } + this.xterm?.refresh(); setTimeout(() => this._initDragAndDrop(container)); diff --git a/yarn.lock b/yarn.lock index 4a964f90843..020414666f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10285,45 +10285,45 @@ xtend@~4.0.0, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xterm-addon-canvas@0.6.0-beta.31: - version "0.6.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb" - integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ== +xterm-addon-canvas@0.6.0-beta.32: + version "0.6.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9" + integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w== xterm-addon-image@0.6.0-beta.21: version "0.6.0-beta.21" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== -xterm-addon-search@0.14.0-beta.30: - version "0.14.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea" - integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ== +xterm-addon-search@0.14.0-beta.31: + version "0.14.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274" + integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg== -xterm-addon-serialize@0.12.0-beta.30: - version "0.12.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.30.tgz#80c4101f45a463ef139705bcd3dcaf0811f51ea4" - integrity sha512-nZP0ip5bd9LBoCTN9vCnn4iLatF4RRwzLupQf9r2N9x1bULzTZ1kAXAQe5gghsXjSEDDtyY2LzGigqTd2KVAqQ== +xterm-addon-serialize@0.12.0-beta.31: + version "0.12.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.31.tgz#2a95dc1e12f4097e2894b04c9cb8fff0bc0b858c" + integrity sha512-h2rWR+Lfi1Iv4VkLUlrBMYh5Mdq8vux2BKyCJe6a1ZnEu5Dzb0VuiNxfTKXTCT5M83nMn7TCB9TX0E8z6bs7xw== -xterm-addon-unicode11@0.7.0-beta.30: - version "0.7.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3" - integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw== +xterm-addon-unicode11@0.7.0-beta.31: + version "0.7.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3" + integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ== -xterm-addon-webgl@0.17.0-beta.30: - version "0.17.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f" - integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q== +xterm-addon-webgl@0.17.0-beta.31: + version "0.17.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa" + integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ== -xterm-headless@5.4.0-beta.31: - version "5.4.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.31.tgz#9538553c7426222f94d7da7ed467e699ebaeeedd" - integrity sha512-EE/ZlsZcBE5VOkjQU/KdRL4gvSkfrC2P7VxrmK1+PLc6+QMjPxs60A4Pun3mIIS0MFfN23p6hmN22GAXVckCXA== +xterm-headless@5.4.0-beta.32: + version "5.4.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.32.tgz#0d5cd35e1a0372888055ff0b06dfe17457979a6c" + integrity sha512-DQduq8KSoQZyRrQAFB+FkcY2UMxCW39P1/duOpksebc6PT9pbGkyPe5s+AdUQGiYzriEpzVtKUzDcquoVmpPhA== -xterm@5.4.0-beta.31: - version "5.4.0-beta.31" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174" - integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA== +xterm@5.4.0-beta.32: + version "5.4.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a" + integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA== y18n@^3.2.1: version "3.2.2" From ddf6c14e17502e15e823470ac68c4bece7e238f7 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 17 Oct 2023 12:42:25 -0700 Subject: [PATCH 191/290] fix #195208 --- .../browser/parts/notifications/notificationsCenter.ts | 3 +++ .../browser/parts/notifications/notificationsCommands.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index 3d7b73c376a..c7e9ab26652 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -25,6 +25,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { assertAllDefined, assertIsDefined } from 'vs/base/common/types'; import { NotificationsCenterVisibleContext } from 'vs/workbench/common/contextkeys'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; export class NotificationsCenter extends Themable implements INotificationsCenterController { @@ -53,6 +54,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IKeybindingService private readonly keybindingService: IKeybindingService, @INotificationService private readonly notificationService: INotificationService, + @IAccessibleNotificationService private readonly accessibleNotificationService: IAccessibleNotificationService ) { super(themeService); @@ -329,6 +331,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente if (!notification.hasProgress) { notification.close(); } + this.accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); } } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts index 21a7891569b..d341f22ee65 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts @@ -19,6 +19,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ActionRunner, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { hash } from 'vs/base/common/hash'; import { firstOrDefault } from 'vs/base/common/arrays'; +import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; // Center export const SHOW_NOTIFICATIONS_CENTER = 'notifications.showList'; @@ -138,9 +139,11 @@ export function registerNotificationCommands(center: INotificationsCenterControl primary: KeyMod.CtrlCmd | KeyCode.Backspace }, handler: (accessor, args?) => { + const accessibleNotificationService = accessor.get(IAccessibleNotificationService); const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification && !notification.hasProgress) { notification.close(); + accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); } } }); From ce8fef79899c980a01dd004575e4a0dcb49ef7c6 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 17 Oct 2023 12:52:08 -0700 Subject: [PATCH 192/290] change default for alerts to always, ignore alerts when audio cues are enabled --- .../browser/accessibilityConfiguration.ts | 8 ++++---- .../browser/accessibleNotificationService.ts | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts index 2e2eb2e188a..86b8003c0dd 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts @@ -125,10 +125,10 @@ const configuration: IConfigurationNode = { ...baseProperty }, [AccessibilityAlertSettingId.Save]: { - 'markdownDescription': localize('alert.save', "When in screen reader mode, alerts when a file is saved. Also see {0}", '`#audioCues.save#`'), + 'markdownDescription': localize('alert.save', "When in screen reader mode, alerts when a file is saved. Note that this will be ignored when {0} is enabled.", '`#audioCues.save#`'), 'type': 'string', 'enum': ['userGesture', 'always', 'never'], - 'default': 'never', + 'default': 'always', 'enumDescriptions': [ localize('alert.save.userGesture', "Alerts when a file is saved via user gesture."), localize('alert.save.always', "Alerts whenever is a file is saved, including auto save."), @@ -137,10 +137,10 @@ const configuration: IConfigurationNode = { tags: ['accessibility'] }, [AccessibilityAlertSettingId.Format]: { - 'markdownDescription': localize('alert.format', "When in screen reader mode, alerts when a file or notebook cell is formatted. Also see {0}", '`#audioCues.format#`'), + 'markdownDescription': localize('alert.format', "When in screen reader mode, alerts when a file or notebook cell is formatted. Note that this will be ignored when {0} is enabled.", '`#audioCues.format#`'), 'type': 'string', 'enum': ['userGesture', 'always', 'never'], - 'default': 'never', + 'default': 'always', 'enumDescriptions': [ localize('alert.format.userGesture', "Alerts when a file is formatted via user gesture."), localize('alert.format.always', "Alerts whenever is a file is formatted, including auto save, on cell execution, and more."), diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts index 62d1c14ca23..7e8503931d9 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts @@ -50,16 +50,19 @@ export class AccessibleNotificationService extends Disposable implements IAccess if (!alertSetting) { return; } - const alertSettingValue: NotificationSetting = this._configurationService.getValue(alertSetting); - if (this._shouldNotify(alertSettingValue, userGesture)) { - this._logService.debug('AccessibleNotificationService alerting: ', alertMessage); - this._accessibilityService.alert(alertMessage); - } const audioCueSetting: NotificationSetting = this._configurationService.getValue(audioCue.settingsKey); if (this._shouldNotify(audioCueSetting, userGesture)) { this._logService.debug('AccessibleNotificationService playing sound: ', audioCue.name); + console.log('AccessibleNotificationService playing sound: ', audioCue.name); // Play sound bypasses the usual audio cue checks IE screen reader optimized, auto, etc. this._audioCueService.playSound(audioCue.sound.getSound(), true); + return; + } + const alertSettingValue: NotificationSetting = this._configurationService.getValue(alertSetting); + if (this._shouldNotify(alertSettingValue, userGesture)) { + this._logService.debug('AccessibleNotificationService alerting: ', alertMessage); + console.log('AccessibleNotificationService alerting: ', alertMessage); + this._accessibilityService.alert(alertMessage); } } From 99d8d7f17aaf3e9c3d80bc095a27363177838c3f Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 13:17:26 -0700 Subject: [PATCH 193/290] Fix command center border in hc themes (#195822) --- src/vs/workbench/common/theme.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 9d31beaefc2..d2ffebad5f9 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -911,7 +911,7 @@ export const COMMAND_CENTER_ACTIVEBACKGROUND = registerColor( ); // border: active and inactive. defaults to active background export const COMMAND_CENTER_BORDER = registerColor( - 'commandCenter.border', { dark: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcDark: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .60), light: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcLight: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .60) }, + 'commandCenter.border', { dark: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcDark: contrastBorder, light: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcLight: contrastBorder }, localize('commandCenter-border', "Border color of the command center"), false ); From 243e6cec5096b301259ca1f780e50b135f308d33 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 13:18:28 -0700 Subject: [PATCH 194/290] Tweak text preformat foreground and background (#195821) --- build/lib/stylelint/vscode-known-variables.json | 9 +++++---- extensions/theme-defaults/themes/dark_modern.json | 2 ++ extensions/theme-defaults/themes/light_modern.json | 2 ++ src/vs/platform/theme/common/colorRegistry.ts | 5 +++-- src/vs/workbench/contrib/chat/browser/media/chat.css | 4 ++++ .../preferences/browser/media/settingsEditor2.css | 9 +++++++++ 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 6a99e81b5a4..70475768de0 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -681,6 +681,7 @@ "--vscode-textCodeBlock-background", "--vscode-textLink-activeForeground", "--vscode-textLink-foreground", + "--vscode-textPreformat-background", "--vscode-textPreformat-foreground", "--vscode-textSeparator-foreground", "--vscode-titleBar-activeBackground", @@ -695,6 +696,8 @@ "--vscode-tree-indentGuidesStroke", "--vscode-tree-tableColumnsBorder", "--vscode-tree-tableOddRowsBackground", + "--vscode-voiceRecording-background", + "--vscode-voiceRecording-dimmedBackground", "--vscode-walkThrough-embeddedEditorBackground", "--vscode-walkthrough-stepTitle-foreground", "--vscode-welcomePage-background", @@ -706,9 +709,7 @@ "--vscode-widget-border", "--vscode-widget-shadow", "--vscode-window-activeBorder", - "--vscode-window-inactiveBorder", - "--vscode-voiceRecording-background", - "--vscode-voiceRecording-dimmedBackground" + "--vscode-window-inactiveBorder" ], "others": [ "--background-dark", @@ -782,4 +783,4 @@ "--z-index-notebook-sticky-scroll", "--zoom-factor" ] -} +} \ No newline at end of file diff --git a/extensions/theme-defaults/themes/dark_modern.json b/extensions/theme-defaults/themes/dark_modern.json index e1055e8a4e2..b7d24260f83 100644 --- a/extensions/theme-defaults/themes/dark_modern.json +++ b/extensions/theme-defaults/themes/dark_modern.json @@ -113,6 +113,8 @@ "textCodeBlock.background": "#2B2B2B", "textLink.activeForeground": "#40A6FF", "textLink.foreground": "#40A6FF", + "textPreformat.foreground": "#D0D0D0", + "textPreformat.background": "#3C3C3C", "textSeparator.foreground": "#21262D", "titleBar.activeBackground": "#181818", "titleBar.activeForeground": "#CCCCCC", diff --git a/extensions/theme-defaults/themes/light_modern.json b/extensions/theme-defaults/themes/light_modern.json index d5bf68ba831..a89defee385 100644 --- a/extensions/theme-defaults/themes/light_modern.json +++ b/extensions/theme-defaults/themes/light_modern.json @@ -131,6 +131,8 @@ "textCodeBlock.background": "#F8F8F8", "textLink.activeForeground": "#005FB8", "textLink.foreground": "#005FB8", + "textPreformat.foreground": "#3B3B3B", + "textPreformat.background": "#0000001F", "textSeparator.foreground": "#21262D", "titleBar.activeBackground": "#F8F8F8", "titleBar.activeForeground": "#1E1E1E", diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 9f66d2cd1a5..6f83635a148 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -227,8 +227,9 @@ export const selectionBackground = registerColor('selection.background', { light 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.")); -export const textPreformatForeground = registerColor('textPreformat.foreground', { light: '#A31515', dark: '#D7BA7D', hcDark: '#D7BA7D', hcLight: '#292929' }, nls.localize('textPreformatForeground', "Foreground color for preformatted text segments.")); -export const textBlockQuoteBackground = registerColor('textBlockQuote.background', { light: '#7f7f7f1a', dark: '#7f7f7f1a', hcDark: null, hcLight: '#F2F2F2' }, nls.localize('textBlockQuoteBackground', "Background color for block quotes in text.")); +export const textPreformatForeground = registerColor('textPreformat.foreground', { light: '#A31515', dark: '#D7BA7D', hcDark: '#000000', hcLight: '#FFFFFF' }, nls.localize('textPreformatForeground', "Foreground color for preformatted text segments.")); +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.")); export const textCodeBlockBackground = registerColor('textCodeBlock.background', { light: '#dcdcdc66', dark: '#0a0a0a66', hcDark: Color.black, hcLight: '#F2F2F2' }, nls.localize('textCodeBlockBackground', "Background color for code blocks in text.")); diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index cbab68d1e76..c36ac52db15 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -169,7 +169,11 @@ .interactive-item-container .monaco-tokenized-source, .interactive-item-container code { font-family: var(--monaco-monospace-font); + font-size: 12px; color: var(--vscode-textPreformat-foreground); + background-color: var(--vscode-textPreformat-background); + padding: 1px 3px; + border-radius: 4px; } .interactive-item-container.interactive-item-compact { diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index e5dd093c6bd..04c45a90360 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -531,7 +531,11 @@ line-height: 15px; /** For some reason, this is needed, otherwise will take up 20px height */ font-family: var(--monaco-monospace-font); + font-size: 12px; color: var(--vscode-textPreformat-foreground); + background-color: var(--vscode-textPreformat-background); + padding: 1px 3px; + border-radius: 4px; } .settings-editor > .settings-body .settings-tree-container .setting-item-contents .setting-item-markdown .monaco-tokenized-source { @@ -597,7 +601,12 @@ } .monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown code { + font-family: var(--monaco-monospace-font); + font-size: 12px; color: var(--vscode-textPreformat-foreground); + background-color: var(--vscode-textPreformat-background); + padding: 2px 5px; + border-radius: 4px; } .monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a, From 95d6813cacc2929483dc4e87886981e7cfccc5f2 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 17 Oct 2023 13:40:08 -0700 Subject: [PATCH 195/290] handle it all in shouldFocusTerminal --- .../terminalAccessibleBufferProvider.ts | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts index ac195f84cd6..fbe9c5ed18d 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts @@ -3,12 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/model'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver'; import { TerminalCapability, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ICurrentPartialCommand } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; @@ -29,17 +31,18 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements private _bufferTracker: BufferContentTracker, customHelp: () => string, @IModelService _modelService: IModelService, - @IConfigurationService _configurationService: IConfigurationService, + @IConfigurationService configurationService: IConfigurationService, @IContextKeyService _contextKeyService: IContextKeyService, - @ITerminalService _terminalService: ITerminalService + @ITerminalService _terminalService: ITerminalService, + @IKeybindingService private readonly _keybindingService: IKeybindingService ) { super(); this.options.customHelp = customHelp; - this.options.position = _configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom'; + this.options.position = configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom'; this.add(this._instance.onDisposed(() => this._onDidRequestClearProvider.fire(AccessibleViewProviderId.Terminal))); - this.add(_configurationService.onDidChangeConfiguration(e => { + this.add(configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(TerminalSettingId.AccessibleViewPreserveCursorPosition)) { - this.options.position = _configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom'; + this.options.position = configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom'; } })); this._focusedInstance = _terminalService.activeInstance; @@ -52,7 +55,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements } onKeyDown(e: IKeyboardEvent): void { - if (!this._instance.shouldProcessKeyEvent(e.browserEvent) || !isSingleLetterKey(e.browserEvent)) { + if (!isSingleLetterKey(e.browserEvent, this._keybindingService)) { return; } this._instance.focus(); @@ -124,6 +127,13 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements } export interface ICommandWithEditorLine { command: ITerminalCommand | ICurrentPartialCommand; lineNumber: number } -function isSingleLetterKey(event: KeyboardEvent): boolean { +function isSingleLetterKey(event: KeyboardEvent, keybindingService: IKeybindingService): boolean { + const standardKeyboardEvent = new StandardKeyboardEvent(event); + const resolveResult = keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); + + const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded; + if (keybindingService.inChordMode || isValidChord) { + return false; + } return event.key.length === 1 && !event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey; } From 78dbe65f578840cf8475c36df256562863a913bd Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 17 Oct 2023 13:42:35 -0700 Subject: [PATCH 196/290] revert some changes, handle everything in shouldFocusTerminal --- .../contrib/terminal/browser/terminal.ts | 6 - .../terminal/browser/terminalInstance.ts | 166 +++++++++--------- .../terminalAccessibleBufferProvider.ts | 4 +- 3 files changed, 87 insertions(+), 89 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index d7bc90e1e8b..ea1b9088874 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -993,12 +993,6 @@ export interface ITerminalInstance { * Gets a terminal contribution by its ID. */ getContribution(id: string): T | null; - - /** - * Whether the event should be handled by xterm.js or the workbench. - * @param event the event to process - */ - shouldProcessKeyEvent(event: KeyboardEvent): boolean; } export const enum XtermTerminalConstants { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 339a9e4ce5c..a7c08bc63d8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -908,8 +908,92 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._setAriaLabel(xterm.raw, this._instanceId, this._title); - xterm.raw.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => this.shouldProcessKeyEvent(event)); + xterm.raw.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => { + // Disable all input if the terminal is exiting + if (this._isExiting) { + return false; + } + const standardKeyboardEvent = new StandardKeyboardEvent(event); + const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); + + // Respect chords if the allowChords setting is set and it's not Escape. Escape is + // handled specially for Zen Mode's Escape, Escape chord, plus it's important in + // terminals generally + const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded && this._configHelper.config.allowChords && event.key !== 'Escape'; + if (this._keybindingService.inChordMode || isValidChord) { + event.preventDefault(); + return false; + } + + const SHOW_TERMINAL_CONFIG_PROMPT_KEY = 'terminal.integrated.showTerminalConfigPrompt'; + const EXCLUDED_KEYS = ['RightArrow', 'LeftArrow', 'UpArrow', 'DownArrow', 'Space', 'Meta', 'Control', 'Shift', 'Alt', '', 'Delete', 'Backspace', 'Tab']; + + // only keep track of input if prompt hasn't already been shown + if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && + !EXCLUDED_KEYS.includes(event.key) && + !event.ctrlKey && + !event.shiftKey && + !event.altKey) { + this._hasHadInput = true; + } + + // for keyboard events that resolve to commands described + // within commandsToSkipShell, either alert or skip processing by xterm.js + if (resolveResult.kind === ResultKind.KbFound && resolveResult.commandId && this._skipTerminalCommands.some(k => k === resolveResult.commandId) && !this._configHelper.config.sendKeybindingsToShell) { + // don't alert when terminal is opened or closed + if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && + this._hasHadInput && + !TERMINAL_CREATION_COMMANDS.includes(resolveResult.commandId)) { + this._notificationService.prompt( + Severity.Info, + nls.localize('keybindingHandling', "Some keybindings don't go to the terminal by default and are handled by {0} instead.", this._productService.nameLong), + [ + { + label: nls.localize('configureTerminalSettings', "Configure Terminal Settings"), + run: () => { + this._preferencesService.openSettings({ jsonEditor: false, query: `@id:${TerminalSettingId.CommandsToSkipShell},${TerminalSettingId.SendKeybindingsToShell},${TerminalSettingId.AllowChords}` }); + } + } as IPromptChoice + ] + ); + this._storageService.store(SHOW_TERMINAL_CONFIG_PROMPT_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); + } + event.preventDefault(); + return false; + } + + // Skip processing by xterm.js of keyboard events that match menu bar mnemonics + if (this._configHelper.config.allowMnemonics && !isMacintosh && event.altKey) { + return false; + } + + // If tab focus mode is on, tab is not passed to the terminal + if (TabFocus.getTabFocusMode() && event.key === 'Tab') { + return false; + } + + // Prevent default when shift+tab is being sent to the terminal to avoid it bubbling up + // and changing focus https://github.com/microsoft/vscode/issues/188329 + if (event.key === 'Tab' && event.shiftKey) { + event.preventDefault(); + return true; + } + + // Always have alt+F4 skip the terminal on Windows and allow it to be handled by the + // system + if (isWindows && event.altKey && event.key === 'F4' && !event.ctrlKey) { + return false; + } + + // Fallback to force ctrl+v to paste on browsers that do not support + // navigator.clipboard.readText + if (!BrowserFeatures.clipboard.readText && event.key === 'v' && event.ctrlKey) { + return false; + } + + return true; + }); this._register(dom.addDisposableListener(xterm.raw.element, 'mousedown', () => { // We need to listen to the mouseup event on the document since the user may release // the mouse button anywhere outside of _xterm.element. @@ -969,86 +1053,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } - shouldProcessKeyEvent(event: KeyboardEvent): boolean { - // Disable all input if the terminal is exiting - if (this._isExiting) { - return false; - } - - const standardKeyboardEvent = new StandardKeyboardEvent(event); - const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); - - // Respect chords if the allowChords setting is set and it's not Escape. Escape is - // handled specially for Zen Mode's Escape, Escape chord, plus it's important in - // terminals generally - const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded && this._configHelper.config.allowChords && event.key !== 'Escape'; - if (this._keybindingService.inChordMode || isValidChord) { - event.preventDefault(); - return false; - } - - const SHOW_TERMINAL_CONFIG_PROMPT_KEY = 'terminal.integrated.showTerminalConfigPrompt'; - const EXCLUDED_KEYS = ['RightArrow', 'LeftArrow', 'UpArrow', 'DownArrow', 'Space', 'Meta', 'Control', 'Shift', 'Alt', '', 'Delete', 'Backspace', 'Tab']; - - // only keep track of input if prompt hasn't already been shown - if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && - !EXCLUDED_KEYS.includes(event.key) && - !event.ctrlKey && - !event.shiftKey && - !event.altKey) { - this._hasHadInput = true; - } - - // for keyboard events that resolve to commands described - // within commandsToSkipShell, either alert or skip processing by xterm.js - if (resolveResult.kind === ResultKind.KbFound && resolveResult.commandId && this._skipTerminalCommands.some(k => k === resolveResult.commandId) && !this._configHelper.config.sendKeybindingsToShell) { - // don't alert when terminal is opened or closed - if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) && - this._hasHadInput && - !TERMINAL_CREATION_COMMANDS.includes(resolveResult.commandId)) { - this._notificationService.prompt( - Severity.Info, - nls.localize('keybindingHandling', "Some keybindings don't go to the terminal by default and are handled by {0} instead.", this._productService.nameLong), - [ - { - label: nls.localize('configureTerminalSettings', "Configure Terminal Settings"), - run: () => { - this._preferencesService.openSettings({ jsonEditor: false, query: `@id:${TerminalSettingId.CommandsToSkipShell},${TerminalSettingId.SendKeybindingsToShell},${TerminalSettingId.AllowChords}` }); - } - } as IPromptChoice - ] - ); - this._storageService.store(SHOW_TERMINAL_CONFIG_PROMPT_KEY, false, StorageScope.APPLICATION, StorageTarget.USER); - } - event.preventDefault(); - return false; - } - - // Skip processing by xterm.js of keyboard events that match menu bar mnemonics - if (this._configHelper.config.allowMnemonics && !isMacintosh && event.altKey) { - return false; - } - - // If tab focus mode is on, tab is not passed to the terminal - if (TabFocus.getTabFocusMode() && event.key === 'Tab') { - return false; - } - - // Always have alt+F4 skip the terminal on Windows and allow it to be handled by the - // system - if (isWindows && event.altKey && event.key === 'F4' && !event.ctrlKey) { - return false; - } - - // Fallback to force ctrl+v to paste on browsers that do not support - // navigator.clipboard.readText - if (!BrowserFeatures.clipboard.readText && event.key === 'v' && event.ctrlKey) { - return false; - } - - return true; - } - resetFocusContextKey(): void { this._terminalFocusContextKey.reset(); this._terminalShellIntegrationEnabledContextKey.reset(); diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts index fbe9c5ed18d..0b889427bc8 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts @@ -55,7 +55,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements } onKeyDown(e: IKeyboardEvent): void { - if (!isSingleLetterKey(e.browserEvent, this._keybindingService)) { + if (!shouldFocusTerminal(e.browserEvent, this._keybindingService)) { return; } this._instance.focus(); @@ -127,7 +127,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements } export interface ICommandWithEditorLine { command: ITerminalCommand | ICurrentPartialCommand; lineNumber: number } -function isSingleLetterKey(event: KeyboardEvent, keybindingService: IKeybindingService): boolean { +function shouldFocusTerminal(event: KeyboardEvent, keybindingService: IKeybindingService): boolean { const standardKeyboardEvent = new StandardKeyboardEvent(event); const resolveResult = keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); From d3264a27169bc9c8eacaf7904fabe651b7502a50 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 17 Oct 2023 13:44:21 -0700 Subject: [PATCH 197/290] rm something --- .../accessibility/browser/terminalAccessibleBufferProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts index 0b889427bc8..0540afae829 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts @@ -27,7 +27,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements readonly onDidRequestClearLastProvider = this._onDidRequestClearProvider.event; private _focusedInstance: ITerminalInstance | undefined; constructor( - private readonly _instance: Pick, + private readonly _instance: Pick, private _bufferTracker: BufferContentTracker, customHelp: () => string, @IModelService _modelService: IModelService, From 650555dbcfc7c83292f54e971cc8d2c10931ea0c Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 17 Oct 2023 14:05:44 -0700 Subject: [PATCH 198/290] fix #195716 --- src/vs/editor/common/standaloneStrings.ts | 6 ++++ .../browser/accessibilityContributions.ts | 34 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/common/standaloneStrings.ts b/src/vs/editor/common/standaloneStrings.ts index eb30df90850..5c084d90156 100644 --- a/src/vs/editor/common/standaloneStrings.ts +++ b/src/vs/editor/common/standaloneStrings.ts @@ -25,6 +25,12 @@ export namespace AccessibilityHelpNLS { export const tabFocusModeOffMsg = nls.localize("tabFocusModeOffMsg", "Pressing Tab in the current editor will insert the tab character. Toggle this behavior {0}."); export const tabFocusModeOffMsgNoKb = nls.localize("tabFocusModeOffMsgNoKb", "Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding."); export const showAccessibilityHelpAction = nls.localize("showAccessibilityHelpAction", "Show Accessibility Help"); + export const saveAudioCueDisabled = nls.localize("saveAudioCueDisabled", "`audioCues.save` is disabled, so an alert will occur when a file is saved."); + export const saveAudioCueAlways = nls.localize("saveAudioCueAlways", "`audioCues.save` is enabled, so will play whenever a file is saved."); + export const saveAudioCueUserGesture = nls.localize("saveAudioCueUserGesture", "`audioCues.save` is enabled, so will play when a file is saved via user gesture."); + export const formatAudioCueDisabled = nls.localize("formatAudioCueDisabled", "`audioCues.format` is disabled, so an alert will occur when a file is formatted."); + export const formatAudioCueAlways = nls.localize("formatAudioCueAlways", "`audioCues.format` is enabled, so will play whenever a file is formatted."); + export const formatAudioCueUserGesture = nls.localize("formatAudioCueUserGesture", "`audioCues.format` is enabled, so will play when a file is formatted via user gesture."); } export namespace InspectTokensNLS { diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts index 4d8919facea..5dd2eaac1df 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts @@ -41,6 +41,9 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys'; import { CommentAccessibilityHelpNLS } from 'vs/workbench/contrib/comments/browser/comments.contribution'; import { CommentCommandId } from 'vs/workbench/contrib/comments/common/commentCommandIds'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { AudioCue } from 'vs/platform/audioCues/browser/audioCueService'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; export class EditorAccessibilityHelpContribution extends Disposable { static ID: 'editorAccessibilityHelpContribution'; @@ -71,7 +74,9 @@ class EditorAccessibilityHelpProvider implements IAccessibleContentProvider { constructor( private readonly _editor: ICodeEditor, @IKeybindingService private readonly _keybindingService: IKeybindingService, - @IContextKeyService private readonly _contextKeyService: IContextKeyService + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IAccessibilityService private readonly _accessibilityService: IAccessibilityService ) { } @@ -92,6 +97,33 @@ class EditorAccessibilityHelpProvider implements IAccessibleContentProvider { content.push(AccessibilityHelpNLS.editableEditor); } } + const screenReaderOptimized = this._accessibilityService.isScreenReaderOptimized(); + const saveAudioCue = this._configurationService.getValue(AudioCue.save.settingsKey); + const formatAudioCue = this._configurationService.getValue(AudioCue.format.settingsKey); + if (screenReaderOptimized) { + switch (saveAudioCue) { + case 'never': + content.push(AccessibilityHelpNLS.saveAudioCueDisabled); + break; + case 'always': + content.push(AccessibilityHelpNLS.saveAudioCueAlways); + break; + case 'userGesture': + content.push(AccessibilityHelpNLS.saveAudioCueUserGesture); + break; + } + switch (formatAudioCue) { + case 'never': + content.push(AccessibilityHelpNLS.formatAudioCueDisabled); + break; + case 'always': + content.push(AccessibilityHelpNLS.formatAudioCueAlways); + break; + case 'userGesture': + content.push(AccessibilityHelpNLS.formatAudioCueUserGesture); + break; + } + } const commentCommandInfo = getCommentCommandInfo(this._keybindingService, this._contextKeyService, this._editor); if (commentCommandInfo) { From a28793a1af9db9afba0886d988c82ba346ff2af8 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 14:48:18 -0700 Subject: [PATCH 199/290] Update monospace font size --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- .../contrib/preferences/browser/media/settingsEditor2.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index c36ac52db15..5f5d22d3842 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -169,7 +169,7 @@ .interactive-item-container .monaco-tokenized-source, .interactive-item-container code { font-family: var(--monaco-monospace-font); - font-size: 12px; + font-size: 11px; color: var(--vscode-textPreformat-foreground); background-color: var(--vscode-textPreformat-background); padding: 1px 3px; diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index 04c45a90360..a2bfc42d085 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -531,7 +531,7 @@ line-height: 15px; /** For some reason, this is needed, otherwise will take up 20px height */ font-family: var(--monaco-monospace-font); - font-size: 12px; + font-size: 11px; color: var(--vscode-textPreformat-foreground); background-color: var(--vscode-textPreformat-background); padding: 1px 3px; From d279a8206caa92d7c5e55ecba5e22e8e83667b46 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 17 Oct 2023 14:55:54 -0700 Subject: [PATCH 200/290] feat: support welcome view in chat pane (#195830) --- src/vs/workbench/contrib/chat/browser/chatViewPane.ts | 4 ++++ src/vs/workbench/contrib/chat/common/chatService.ts | 1 + src/vs/workbench/contrib/chat/common/chatServiceImpl.ts | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index ba56b069fcc..9be6f027aba 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -82,6 +82,10 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { this.viewState.sessionId = model.sessionId; } + override shouldShowWelcome(): boolean { + return !this.chatService.hasProviders(); + } + protected override renderBody(parent: HTMLElement): void { try { super.renderBody(parent); diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index bb52eeaceef..38d48e94815 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -265,6 +265,7 @@ export interface IChatService { onDidSubmitSlashCommand: Event<{ slashCommand: string; sessionId: string }>; registerProvider(provider: IChatProvider): IDisposable; + hasProviders(): boolean; getProviderInfos(): IChatProviderInfo[]; startSession(providerId: string, token: CancellationToken): ChatModel | undefined; getSession(sessionId: string): IChatModel | undefined; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 0e7382192dd..cbeb0dad572 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -760,6 +760,10 @@ export class ChatService extends Disposable implements IChatService { }); } + hasProviders(): boolean { + return this._providers.size > 0; + } + getProviderInfos(): IChatProviderInfo[] { return Array.from(this._providers.values()).map(provider => { return { From 97afb0a422a8f347438243df943d7564d4cc9adb Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 15:01:32 -0700 Subject: [PATCH 201/290] Match pill dimensions to new styling --- src/vs/workbench/contrib/chat/browser/media/chat.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index c36ac52db15..329ef7136ed 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -427,9 +427,9 @@ .interactive-item-container .chat-resource-widget { background-color: var(--vscode-chat-slashCommandBackground); color: var(--vscode-chat-slashCommandForeground); - border-radius: 3px; + border-radius: 4px; white-space: nowrap; - padding: 1px; + padding: 1px 3px; } .interactive-session .chat-used-context.chat-used-context-collapsed .chat-used-context-list { From 65cc0f6d1ba5112df7213d868b3be86f3006d952 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 15:35:12 -0700 Subject: [PATCH 202/290] Use new styling in inline widget --- .../workbench/contrib/inlineChat/browser/inlineChat.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css index 92b75867291..9ffe8efc5bb 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css @@ -164,6 +164,15 @@ margin: unset; } +.monaco-editor .inline-chat .markdownMessage .message code { + font-family: var(--monaco-monospace-font); + font-size: 12px; + color: var(--vscode-textPreformat-foreground); + background-color: var(--vscode-textPreformat-background); + padding: 1px 3px; + border-radius: 4px; +} + .monaco-editor .inline-chat .markdownMessage .message .interactive-result-code-block { margin: 16px 0; } From 880cb517e1e1d8085cd87182c3e3c31c7f81845a Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Tue, 17 Oct 2023 15:55:55 -0700 Subject: [PATCH 203/290] Add more SBOMs (#195736) --- .../alpine/product-build-alpine.yml | 13 +++++++++++ .../cli/cli-compile-and-publish.yml | 23 +++++++++++++++++++ .../darwin/product-build-darwin.yml | 5 ++-- .../linux/product-build-linux.yml | 1 + .../linux/snap-build-linux.yml | 13 +++++++++++ .../azure-pipelines/web/product-build-web.yml | 11 +++++++++ .../win32/product-build-win32.yml | 5 ++-- 7 files changed, 67 insertions(+), 4 deletions(-) diff --git a/build/azure-pipelines/alpine/product-build-alpine.yml b/build/azure-pipelines/alpine/product-build-alpine.yml index 4e318644d08..77f97561426 100644 --- a/build/azure-pipelines/alpine/product-build-alpine.yml +++ b/build/azure-pipelines/alpine/product-build-alpine.yml @@ -138,6 +138,19 @@ steps: condition: and(succeededOrFailed(), notIn(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues')) displayName: Generate artifact prefix + - script: mkdir $(agent.builddirectory)/vscode-alpine-$(VSCODE_ARCH) + displayName: Make folder for SBOM + + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-alpine-$(VSCODE_ARCH) + PackageName: Visual Studio Code Server + + - publish: $(agent.builddirectory)/vscode-alpine-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM + artifact: $(ARTIFACT_PREFIX)sbom_vscode_alpine_$(VSCODE_ARCH) + - publish: $(SERVER_PATH) artifact: $(ARTIFACT_PREFIX)vscode_server_alpine_$(VSCODE_ARCH)_archive-unsigned displayName: Publish server archive diff --git a/build/azure-pipelines/cli/cli-compile-and-publish.yml b/build/azure-pipelines/cli/cli-compile-and-publish.yml index af9960d7f5b..05ad5538d87 100644 --- a/build/azure-pipelines/cli/cli-compile-and-publish.yml +++ b/build/azure-pipelines/cli/cli-compile-and-publish.yml @@ -106,3 +106,26 @@ steps: - publish: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} displayName: Publish ${{ parameters.VSCODE_CLI_ARTIFACT }} artifact + + # Make a folder for the SBOM for the specific artifact + - ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-') }}: + - powershell: mkdir $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }} + displayName: Make folder for SBOM (Windows) + + - ${{ else }}: + - script: mkdir $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }} + displayName: Make folder for SBOM (non-Windows) + + # The if cases above are for different OSes, + # but we're still in the branch where the cli is being published in general. + # Generate and publish an SBOM. + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM + inputs: + BuildComponentPath: $(Build.SourcesDirectory)/cli + BuildDropPath: $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }} + PackageName: Visual Studio Code CLI + + - publish: $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }}/_manifest + displayName: Publish SBOM + artifact: sbom_${{ parameters.VSCODE_CLI_ARTIFACT }} diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 35b207cb7f5..4a4c587c7aa 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -219,16 +219,17 @@ steps: - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 displayName: Generate SBOM (server) inputs: + BuildComponentPath: $(Build.SourcesDirectory)/remote BuildDropPath: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) PackageName: Visual Studio Code Server - publish: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)/_manifest displayName: Publish SBOM (client) - artifact: $(ARTIFACT_PREFIX)sbom_client_darwin_$(VSCODE_ARCH)_sbom + artifact: $(ARTIFACT_PREFIX)sbom_vscode_client_darwin_$(VSCODE_ARCH) - publish: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH)/_manifest displayName: Publish SBOM (server) - artifact: $(ARTIFACT_PREFIX)sbom_server_darwin_$(VSCODE_ARCH)_sbom + artifact: $(ARTIFACT_PREFIX)sbom_vscode_server_darwin_$(VSCODE_ARCH) - publish: $(CLIENT_PATH) artifact: $(ARTIFACT_PREFIX)unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 3923d7d105f..b2c993b4a14 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -331,6 +331,7 @@ steps: - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 displayName: Generate SBOM (server) inputs: + BuildComponentPath: $(Build.SourcesDirectory)/remote BuildDropPath: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) PackageName: Visual Studio Code Server diff --git a/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml index c74783da146..7f00653a4bd 100644 --- a/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -50,6 +50,19 @@ steps: echo "##vso[task.setvariable variable=SNAP_PATH]$SNAP_PATH" displayName: Prepare for publish + - script: mkdir -p $(agent.builddirectory)/vscode-snap-linux-$(VSCODE_ARCH) + displayName: Make folder for SBOM + + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-snap-linux-$(VSCODE_ARCH) + PackageName: Visual Studio Code Snap + + - publish: $(agent.builddirectory)/vscode-snap-linux-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM + artifact: $(ARTIFACT_PREFIX)sbom_vscode_client_linux_snap_$(VSCODE_ARCH) + - publish: $(SNAP_PATH) artifact: vscode_client_linux_$(VSCODE_ARCH)_snap displayName: Publish snap package diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index ecdfe91ed0b..74ebc3df8f5 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -107,6 +107,7 @@ steps: displayName: Build - task: AzureCLI@2 + displayName: Fetch secrets from Azure inputs: azureSubscription: "vscode-builds-subscription" scriptType: pscore @@ -151,6 +152,16 @@ steps: condition: and(succeededOrFailed(), notIn(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues')) displayName: Generate artifact prefix + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-web + PackageName: Visual Studio Code Web + + - publish: $(agent.builddirectory)/vscode-web/_manifest + displayName: Publish SBOM (client) + artifact: $(ARTIFACT_PREFIX)sbom_vscode_web + - publish: $(WEB_PATH) artifact: $(ARTIFACT_PREFIX)vscode_web_linux_standalone_archive-unsigned condition: and(succeededOrFailed(), ne(variables['WEB_PATH'], '')) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index ebfbc701146..ab0813b9f76 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -322,17 +322,18 @@ steps: - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 displayName: Generate SBOM (server) inputs: + BuildComponentPath: $(Build.SourcesDirectory)/remote BuildDropPath: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH) PackageName: Visual Studio Code Server condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - publish: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/_manifest displayName: Publish SBOM (client) - artifact: $(ARTIFACT_PREFIX)sbom_client_win32_$(VSCODE_ARCH) + artifact: $(ARTIFACT_PREFIX)sbom_vscode_client_win32_$(VSCODE_ARCH) - publish: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH)/_manifest displayName: Publish SBOM (server) - artifact: $(ARTIFACT_PREFIX)sbom_server_win32_$(VSCODE_ARCH) + artifact: $(ARTIFACT_PREFIX)sbom_vscode_server_win32_$(VSCODE_ARCH) condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - publish: $(CLIENT_PATH) From 5d896cae2feb876b5430bb85ad54a0e405fbc162 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 16:01:52 -0700 Subject: [PATCH 204/290] Revert font size change --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 18a2af99b69..329ef7136ed 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -169,7 +169,7 @@ .interactive-item-container .monaco-tokenized-source, .interactive-item-container code { font-family: var(--monaco-monospace-font); - font-size: 11px; + font-size: 12px; color: var(--vscode-textPreformat-foreground); background-color: var(--vscode-textPreformat-background); padding: 1px 3px; From 3d9e1b78dbdc40fb858ae6988d108d1f9814f879 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:02:44 -0700 Subject: [PATCH 205/290] Warn when enum-related fields set without enum (#195838) * Warn when enum-related fields set without enum * polish --- .../services/preferences/common/preferencesModels.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 512cca25488..89022b946b7 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -687,6 +687,10 @@ export class DefaultSettings extends Disposable { } } + if (!enumToUse && (prop.enumItemLabels || enumDescriptions || enumDescriptionsAreMarkdown)) { + console.error(`The setting ${key} has enum-related fields, but doesn't have an enum field. This setting may render improperly in the Settings editor.`); + } + result.push({ key, value, @@ -706,6 +710,7 @@ export class DefaultSettings extends Disposable { enum: enumToUse, enumDescriptions: enumDescriptions, enumDescriptionsAreMarkdown: enumDescriptionsAreMarkdown, + enumItemLabels: prop.enumItemLabels, uniqueItems: prop.uniqueItems, tags: prop.tags, disallowSyncIgnore: prop.disallowSyncIgnore, @@ -714,7 +719,6 @@ export class DefaultSettings extends Disposable { deprecationMessage: prop.markdownDeprecationMessage || prop.deprecationMessage, deprecationMessageIsMarkdown: !!prop.markdownDeprecationMessage, validator: createValidator(prop), - enumItemLabels: prop.enumItemLabels, allKeysAreBoolean, editPresentation: prop.editPresentation, order: prop.order, @@ -1058,7 +1062,7 @@ class SettingsContentBuilder { setting.descriptionRanges.push({ startLineNumber: this.lineCountWithOffset, startColumn: this.lastLine.indexOf(line) + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }); } - if (setting.enumDescriptions && setting.enumDescriptions.some(desc => !!desc)) { + if (setting.enum && setting.enumDescriptions?.some(desc => !!desc)) { setting.enumDescriptions.forEach((desc, i) => { const displayEnum = escapeInvisibleChars(String(setting.enum![i])); const line = desc ? From 3d01829e872d95605e8f93b225fce60daa867a91 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 17 Oct 2023 16:06:32 -0700 Subject: [PATCH 206/290] cli: increase socket search timeout (#195837) Fixes #195823 --- cli/src/tunnels/code_server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/tunnels/code_server.rs b/cli/src/tunnels/code_server.rs index e17e32f8840..06e42681799 100644 --- a/cli/src/tunnels/code_server.rs +++ b/cli/src/tunnels/code_server.rs @@ -510,7 +510,7 @@ impl<'a> ServerBuilder<'a> { let (mut origin, listen_rx) = monitor_server::(child, Some(log_file), plog, false); - let socket = match timeout(Duration::from_secs(8), listen_rx).await { + let socket = match timeout(Duration::from_secs(30), listen_rx).await { Err(e) => { origin.kill().await; Err(wrap(e, "timed out looking for socket")) From c1b146e35a54bc84d614b8eca91098ca4461093e Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 16:27:14 -0700 Subject: [PATCH 207/290] Restore chat code block background color --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 329ef7136ed..f835ffeffd2 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -264,7 +264,7 @@ .interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor, .interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor .margin, .interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor .monaco-editor-background { - background-color: var(--vscode-interactive-result-editor-background-color); + background-color: var(--vscode-interactive-result-editor-background-color) !important; } .interactive-item-compact .interactive-result-code-block { From e5b7340d189d6814b139401009b2f8ab3cda0ea1 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 17 Oct 2023 16:48:12 -0700 Subject: [PATCH 208/290] fix: rerender chat pane when provider is added (#195845) --- src/vs/workbench/contrib/chat/browser/chatViewPane.ts | 3 +++ src/vs/workbench/contrib/chat/common/chatService.ts | 1 + src/vs/workbench/contrib/chat/common/chatServiceImpl.ts | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index 9be6f027aba..d5ced73f860 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -66,6 +66,9 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { // View state for the ViewPane is currently global per-provider basically, but some other strictly per-model state will require a separate memento. this.memento = new Memento('interactive-session-view-' + this.chatViewOptions.providerId, this.storageService); this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState; + this._register(this.chatService.onDidRegisterProvider(({ providerId }) => { + if (providerId === this.chatViewOptions.providerId) { this.updateModel(); } + })); } private updateModel(model?: IChatModel | undefined): void { diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 38d48e94815..a065dc06655 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -264,6 +264,7 @@ export interface IChatService { transferredSessionData: IChatTransferredSessionData | undefined; onDidSubmitSlashCommand: Event<{ slashCommand: string; sessionId: string }>; + onDidRegisterProvider: Event<{ providerId: string }>; registerProvider(provider: IChatProvider): IDisposable; hasProviders(): boolean; getProviderInfos(): IChatProviderInfo[]; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index cbeb0dad572..848a64ded4b 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -150,6 +150,9 @@ export class ChatService extends Disposable implements IChatService { private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string }>()); public readonly onDidDisposeSession = this._onDidDisposeSession.event; + private readonly _onDidRegisterProvider = this._register(new Emitter<{ providerId: string }>()); + public readonly onDidRegisterProvider = this._onDidRegisterProvider.event; + constructor( @IStorageService private readonly storageService: IStorageService, @ILogService private readonly logService: ILogService, @@ -743,6 +746,7 @@ export class ChatService extends Disposable implements IChatService { this._providers.set(provider.id, provider); this._hasProvider.set(true); + this._onDidRegisterProvider.fire({ providerId: provider.id }); Array.from(this._sessionModels.values()) .filter(model => model.providerId === provider.id) From 070fd9bbae7e52ea57c1e23748bb7774a58ace8a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2023 17:18:05 -0700 Subject: [PATCH 209/290] Filtered blur shouldn't apply to info message (#195848) --- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index f835ffeffd2..1ed1ca11c89 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -362,7 +362,7 @@ color: var(--vscode-icon-foreground) !important; } -.interactive-item-container.filtered-response .value .rendered-markdown { +.interactive-item-container.filtered-response .value > .rendered-markdown { -webkit-mask-image: linear-gradient(rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.05)); mask-image: linear-gradient(rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.05)); } From 672033e15161cc7ec32af9c2a1cbf467b04fb887 Mon Sep 17 00:00:00 2001 From: Yuto Liyosa <75252297+MrYuto@users.noreply.github.com> Date: Wed, 18 Oct 2023 03:53:59 +0330 Subject: [PATCH 210/290] Resolve absolute file target links in tsconfig (#195514) (#195759) fix #195514 again --- .../src/languageFeatures/tsconfig.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/tsconfig.ts b/extensions/typescript-language-features/src/languageFeatures/tsconfig.ts index 34ed6828145..398c8c10ee2 100644 --- a/extensions/typescript-language-features/src/languageFeatures/tsconfig.ts +++ b/extensions/typescript-language-features/src/languageFeatures/tsconfig.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as jsonc from 'jsonc-parser'; -import { posix } from 'path'; +import { isAbsolute, posix } from 'path'; import * as vscode from 'vscode'; import { Utils } from 'vscode-uri'; import { coalesce } from '../utils/arrays'; @@ -95,6 +95,10 @@ class TsconfigLinkProvider implements vscode.DocumentLinkProvider { } private getFileTarget(document: vscode.TextDocument, node: jsonc.Node): vscode.Uri { + if (isAbsolute(node.value)) { + return vscode.Uri.file(node.value); + } + return vscode.Uri.joinPath(Utils.dirname(document.uri), node.value); } From 5c148ef006c85cd5dc3fb1574ea8fd9cceaa488d Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 17:24:59 -0700 Subject: [PATCH 211/290] More references list styling updates (#195847) --- .../contrib/chat/browser/chatListRenderer.ts | 2 +- .../contrib/chat/browser/media/chat.css | 20 ++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 9427302ee8d..b42d4685e25 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -620,7 +620,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 1ed1ca11c89..04abd853552 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -17,7 +17,7 @@ padding: 16px 20px 16px 20px; display: flex; flex-direction: column; - gap: 6px; + gap: 8px; color: var(--vscode-interactive-session-foreground); cursor: default; @@ -436,10 +436,17 @@ display: none; } +.interactive-session .chat-used-context { + display: flex; + flex-direction: column; + gap: 6px; +} + .interactive-session .chat-used-context-list { border: 1px solid var(--vscode-chat-requestBorder); border-radius: 4px; padding: 4px; + margin-bottom: 8px; } .interactive-session .chat-used-context-list .monaco-list .monaco-list-row { @@ -464,13 +471,16 @@ padding: 0; text-align: initial; justify-content: initial; - margin-bottom: 6px; } -.interactive-session .chat-used-context-label .monaco-text-button { - outline-offset: unset !important; +.interactive-session .chat-used-context-label .monaco-text-button:focus { + outline: none; +} + +.interactive-session .chat-used-context-label .monaco-text-button:focus-visible { + outline: 1px solid var(--vscode-focusBorder); } .interactive-session .chat-used-context .chat-used-context-label .monaco-button .codicon { - margin: 0 2px 0 0; + margin: 0 0 0 4px; } From 7a9b57fd528979141d50d3d8827b7da815fbca91 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2023 17:33:28 -0700 Subject: [PATCH 212/290] Look up correct result for chat user action (#195849) * Look up correct result for chat user action * Only reply followups are sent in the user action event --- .../api/browser/mainThreadChatAgents2.ts | 14 +++++------- .../workbench/api/common/extHost.protocol.ts | 4 ++-- .../api/common/extHostChatAgents2.ts | 22 ++++++++++++++----- .../browser/actions/chatCodeblockActions.ts | 2 ++ .../contrib/chat/browser/chatListRenderer.ts | 1 + .../contrib/chat/browser/chatWidget.ts | 9 +++++++- .../contrib/chat/common/chatModel.ts | 10 +++++---- .../contrib/chat/common/chatService.ts | 3 ++- .../contrib/chat/common/chatServiceImpl.ts | 3 +-- .../contrib/chat/common/chatViewModel.ts | 6 +++++ ...scode.proposed.interactiveUserActions.d.ts | 2 +- 11 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index a80992df95d..07a10a92e9c 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -8,7 +8,6 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; import { UriComponents } from 'vs/base/common/uri'; -import { generateUuid } from 'vs/base/common/uuid'; import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IChatResponseProgressFileTreeData, IExtensionChatAgentMetadata, ILocationDto, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel'; @@ -44,13 +43,13 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA this._proxy.$releaseSession(e.sessionId); })); this._register(this._chatService.onDidPerformUserAction(e => { - if (e.agentId) { + if (typeof e.agentId === 'string') { for (const [handle, agent] of this._agents) { if (agent.name === e.agentId) { if (e.action.kind === 'vote') { - this._proxy.$acceptFeedback(handle, e.sessionId, e.action.direction); + this._proxy.$acceptFeedback(handle, e.sessionId, e.requestId, e.action.direction); } else { - this._proxy.$acceptAction(handle, e.sessionId, e); + this._proxy.$acceptAction(handle, e.sessionId, e.requestId, e); } break; } @@ -68,12 +67,11 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA id: name, metadata: revive(metadata), invoke: async (request, progress, history, token) => { - const requestId = generateUuid(); - this._pendingProgress.set(requestId, progress); + this._pendingProgress.set(request.requestId, progress); try { - return await this._proxy.$invokeAgent(handle, request.sessionId, requestId, request, { history }, token) ?? {}; + return await this._proxy.$invokeAgent(handle, request.sessionId, request.requestId, request, { history }, token) ?? {}; } finally { - this._pendingProgress.delete(requestId); + this._pendingProgress.delete(request.requestId); } }, provideFollowups: async (sessionId, token): Promise => { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 969de0075e2..674cb4bb2a4 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1185,8 +1185,8 @@ export interface ExtHostChatAgentsShape2 { $invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise; $provideSlashCommands(handle: number, token: CancellationToken): Promise; $provideFollowups(handle: number, sessionId: string, token: CancellationToken): Promise; - $acceptFeedback(handle: number, sessionId: string, vote: InteractiveSessionVoteDirection): void; - $acceptAction(handle: number, sessionId: string, action: IChatUserActionEvent): void; + $acceptFeedback(handle: number, sessionId: string, requestId: string, vote: InteractiveSessionVoteDirection): void; + $acceptAction(handle: number, sessionId: string, requestId: string, action: IChatUserActionEvent): void; $releaseSession(sessionId: string): void; } diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index c202d7b1031..4044bb79786 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -30,6 +30,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { private readonly _proxy: MainThreadChatAgentsShape2; private readonly _previousResultMap: Map = new Map(); + private readonly _resultsBySessionAndRequestId: Map> = new Map(); constructor( mainContext: IMainContext, @@ -49,6 +50,10 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { } async $invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise { + // Clear the previous result so that $acceptFeedback or $acceptAction during a request will be ignored. + // We may want to support sending those during a request. + this._previousResultMap.delete(sessionId); + const agent = this._agents.get(handle); if (!agent) { throw new Error(`[CHAT](${handle}) CANNOT invoke agent because the agent is not registered`); @@ -100,6 +105,13 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return await raceCancellation(Promise.resolve(task).then((result) => { if (result) { this._previousResultMap.set(sessionId, result); + let sessionResults = this._resultsBySessionAndRequestId.get(sessionId); + if (!sessionResults) { + sessionResults = new Map(); + this._resultsBySessionAndRequestId.set(sessionId, sessionResults); + } + sessionResults.set(requestId, result); + return { errorDetails: result.errorDetails }; // TODO timings here } else { this._previousResultMap.delete(sessionId); @@ -124,6 +136,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { $releaseSession(sessionId: string): void { this._previousResultMap.delete(sessionId); + this._resultsBySessionAndRequestId.delete(sessionId); } async $provideSlashCommands(handle: number, token: CancellationToken): Promise { @@ -149,12 +162,12 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return agent.provideFollowups(result, token); } - $acceptFeedback(handle: number, sessionId: string, vote: InteractiveSessionVoteDirection): void { + $acceptFeedback(handle: number, sessionId: string, requestId: string, vote: InteractiveSessionVoteDirection): void { const agent = this._agents.get(handle); if (!agent) { return; } - const result = this._previousResultMap.get(sessionId); + const result = this._resultsBySessionAndRequestId.get(sessionId)?.get(requestId); if (!result) { return; } @@ -171,12 +184,12 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { agent.acceptFeedback(Object.freeze({ result, kind })); } - $acceptAction(handle: number, sessionId: string, action: IChatUserActionEvent): void { + $acceptAction(handle: number, sessionId: string, requestId: string, action: IChatUserActionEvent): void { const agent = this._agents.get(handle); if (!agent) { return; } - const result = this._previousResultMap.get(sessionId); + const result = this._resultsBySessionAndRequestId.get(sessionId)?.get(requestId); if (!result) { return; } @@ -302,7 +315,6 @@ class ExtHostChatAgent { that._iconPath = v; updateMetadataSoon(); }, - // onDidPerformAction get slashCommandProvider() { return that._slashCommandProvider; }, diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index c29335d7607..3356f592c73 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -110,6 +110,7 @@ export function registerChatCodeBlockActions() { providerId: context.element.providerId, agentId: context.element.agent?.id, sessionId: context.element.sessionId, + requestId: context.element.requestId, action: { kind: 'copy', responseId: context.element.providerResponseId, @@ -154,6 +155,7 @@ export function registerChatCodeBlockActions() { providerId: context.element.providerId, agentId: context.element.agent?.id, sessionId: context.element.sessionId, + requestId: context.element.requestId, action: { kind: 'copy', codeBlockIndex: context.codeBlockIndex, diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index b42d4685e25..af6ba1145eb 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -353,6 +353,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer this._onDidFocus.fire())); this._register(this.inputPart.onDidAcceptFollowup(e => { - // this.chatService.notifyUserAction if (!this.viewModel) { return; } + + if (!e.response) { + // Followups can be shown by the welcome message, then there is no response associated. + // At some point we probably want telemetry for these too. + return; + } + this.chatService.notifyUserAction({ providerId: this.viewModel.providerId, sessionId: this.viewModel.sessionId, + requestId: e.response.requestId, agentId: e.response?.agent?.id, action: { kind: 'followUp', diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 43f64cd6bd7..8b928207f83 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -53,6 +53,7 @@ export interface IChatResponseModel { readonly id: string; readonly providerId: string; readonly providerResponseId: string | undefined; + readonly requestId: string; readonly username: string; readonly avatarIconUri?: URI; readonly session: IChatModel; @@ -294,6 +295,7 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel _response: IMarkdownString | ReadonlyArray, public readonly session: ChatModel, public readonly agent: IChatAgent | undefined, + public readonly requestId: string, private _isComplete: boolean = false, private _isCanceled = false, private _vote?: InteractiveSessionVoteDirection, @@ -565,7 +567,7 @@ export class ChatModel extends Disposable implements IChatModel { const request = new ChatRequestModel(this, parsedRequest, raw.providerRequestId); if (raw.response || raw.responseErrorDetails) { const agent = raw.agent && this.chatAgentService.getAgents().find(a => a.id === raw.agent!.id); // TODO do something reasonable if this agent has disappeared since the last session - request.response = new ChatResponseModel(raw.response ?? [new MarkdownString(raw.response)], this, agent, true, raw.isCanceled, raw.vote, raw.providerRequestId, raw.responseErrorDetails, raw.followups); + request.response = new ChatResponseModel(raw.response ?? [new MarkdownString(raw.response)], this, agent, request.id, true, raw.isCanceled, raw.vote, raw.providerRequestId, raw.responseErrorDetails, raw.followups); if (raw.usedContext) { // @ulugbekna: if this's a new vscode sessions, doc versions are incorrect anyway? request.response.updateContent(raw.usedContext); } @@ -652,7 +654,7 @@ export class ChatModel extends Disposable implements IChatModel { } const request = new ChatRequestModel(this, message); - request.response = new ChatResponseModel([], this, chatAgent); + request.response = new ChatResponseModel([], this, chatAgent, request.id); this._requests.push(request); this._onDidChange.fire({ kind: 'addRequest', request }); @@ -665,7 +667,7 @@ export class ChatModel extends Disposable implements IChatModel { } if (!request.response) { - request.response = new ChatResponseModel([], this, undefined); + request.response = new ChatResponseModel([], this, undefined, request.id); } if (request.response.isComplete) { @@ -710,7 +712,7 @@ export class ChatModel extends Disposable implements IChatModel { } if (!request.response) { - request.response = new ChatResponseModel([], this, undefined); + request.response = new ChatResponseModel([], this, undefined, request.id); } request.response.setErrorDetails(rawResponse.errorDetails); diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index a065dc06655..369840dfe8e 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -212,7 +212,7 @@ export interface IChatCommandAction { export interface IChatFollowupAction { kind: 'followUp'; - followup: IChatFollowup; + followup: IChatReplyFollowup; } export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction; @@ -222,6 +222,7 @@ export interface IChatUserActionEvent { providerId: string; agentId: string | undefined; sessionId: string; + requestId: string; } export interface IChatDynamicRequest { diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 848a64ded4b..04fad070cd9 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -12,7 +12,6 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle' import { revive } from 'vs/base/common/marshalling'; import { StopWatch } from 'vs/base/common/stopwatch'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { generateUuid } from 'vs/base/common/uuid'; import { localize } from 'vs/nls'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -521,7 +520,7 @@ export class ChatService extends Disposable implements IChatService { request = model.addRequest(parsedRequest, agent); const requestProps: IChatAgentRequest = { sessionId, - requestId: generateUuid(), + requestId: request.id, message, variables: {}, command: agentSlashCommandPart?.command.name ?? '', diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index 365303eaf7b..dbf12f34f08 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -88,6 +88,8 @@ export interface IChatResponseViewModel { readonly dataId: string; readonly providerId: string; readonly providerResponseId: string | undefined; + /** The ID of the associated IChatRequestViewModel */ + readonly requestId: string; readonly username: string; readonly avatarIconUri?: URI; readonly agent?: IChatAgent; @@ -326,6 +328,10 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi return this._model.vote; } + get requestId() { + return this._model.requestId; + } + renderData: IChatResponseRenderData | undefined = undefined; currentRenderedHeight: number | undefined; diff --git a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts index f9b400c1d94..e038f1f2ed6 100644 --- a/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts +++ b/src/vscode-dts/vscode.proposed.interactiveUserActions.d.ts @@ -64,7 +64,7 @@ declare module 'vscode' { export interface InteractiveSessionFollowupAction { // eslint-disable-next-line local/vscode-dts-string-type-literals kind: 'followUp'; - followup: InteractiveSessionFollowup; + followup: InteractiveSessionReplyFollowup; } export type InteractiveSessionUserAction = InteractiveSessionVoteAction | InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction; From 8e17fcac92090f85499b57e7b66ccc9e5891f698 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 17:40:58 -0700 Subject: [PATCH 213/290] Update input placeholder color in dark modern --- extensions/theme-defaults/themes/dark_modern.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/theme-defaults/themes/dark_modern.json b/extensions/theme-defaults/themes/dark_modern.json index b7d24260f83..b4cd0a9f721 100644 --- a/extensions/theme-defaults/themes/dark_modern.json +++ b/extensions/theme-defaults/themes/dark_modern.json @@ -49,7 +49,7 @@ "input.background": "#313131", "input.border": "#3C3C3C", "input.foreground": "#CCCCCC", - "input.placeholderForeground": "#9D9D9D", + "input.placeholderForeground": "#818181", "inputOption.activeBackground": "#2489DB82", "inputOption.activeBorder": "#2488DB", "keybindingLabel.foreground": "#CCCCCC", From 49671031d136ff9bd62c65367c4eac684f0bada6 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 17 Oct 2023 18:15:34 -0700 Subject: [PATCH 214/290] Increase link contrast in dark modern --- extensions/theme-defaults/themes/dark_modern.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/theme-defaults/themes/dark_modern.json b/extensions/theme-defaults/themes/dark_modern.json index b7d24260f83..32f82f053cc 100644 --- a/extensions/theme-defaults/themes/dark_modern.json +++ b/extensions/theme-defaults/themes/dark_modern.json @@ -111,8 +111,8 @@ "textBlockQuote.background": "#2B2B2B", "textBlockQuote.border": "#616161", "textCodeBlock.background": "#2B2B2B", - "textLink.activeForeground": "#40A6FF", - "textLink.foreground": "#40A6FF", + "textLink.activeForeground": "#4daafc", + "textLink.foreground": "#4daafc", "textPreformat.foreground": "#D0D0D0", "textPreformat.background": "#3C3C3C", "textSeparator.foreground": "#21262D", From 5cbc3f8a1dc6abc2cbb49f402520227f2f3fee6f Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2023 21:02:04 -0700 Subject: [PATCH 215/290] Add missing requestIDs (#195857) --- .../browser/actions/chatCodeblockActions.ts | 19 +++++++++++-------- .../chat/browser/actions/chatTitleActions.ts | 12 +++++++----- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index 3356f592c73..f43739183dd 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -28,7 +28,7 @@ import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatAct import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart'; import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; -import { IChatCopyAction, IChatService, IChatUserActionEvent, IDocumentContext, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatCopyAction, IChatService, IDocumentContext, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; import { CTX_INLINE_CHAT_VISIBLE } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations'; @@ -106,7 +106,7 @@ export function registerChatCodeBlockActions() { if (isResponseVM(context.element)) { const chatService = accessor.get(IChatService); - chatService.notifyUserAction({ + chatService.notifyUserAction({ providerId: context.element.providerId, agentId: context.element.agent?.id, sessionId: context.element.sessionId, @@ -330,13 +330,14 @@ export function registerChatCodeBlockActions() { private notifyUserAction(accessor: ServicesAccessor, context: ICodeBlockActionContext) { if (isResponseVM(context.element)) { const chatService = accessor.get(IChatService); - chatService.notifyUserAction({ + chatService.notifyUserAction({ providerId: context.element.providerId, agentId: context.element.agent?.id, sessionId: context.element.sessionId, + requestId: context.element.requestId, action: { kind: 'insert', - responseId: context.element.providerResponseId, + responseId: context.element.providerResponseId!, codeBlockIndex: context.codeBlockIndex, totalCharacters: context.code.length, } @@ -378,13 +379,14 @@ export function registerChatCodeBlockActions() { editorService.openEditor({ contents: context.code, languageId: context.languageId, resource: undefined }); if (isResponseVM(context.element)) { - chatService.notifyUserAction({ + chatService.notifyUserAction({ providerId: context.element.providerId, agentId: context.element.agent?.id, sessionId: context.element.sessionId, + requestId: context.element.requestId, action: { kind: 'insert', - responseId: context.element.providerResponseId, + responseId: context.element.providerResponseId!, codeBlockIndex: context.codeBlockIndex, totalCharacters: context.code.length, newFile: true @@ -463,13 +465,14 @@ export function registerChatCodeBlockActions() { terminal.sendText(context.code, false, true); if (isResponseVM(context.element)) { - chatService.notifyUserAction({ + chatService.notifyUserAction({ providerId: context.element.providerId, agentId: context.element.agent?.id, sessionId: context.element.sessionId, + requestId: context.element.requestId, action: { kind: 'runInTerminal', - responseId: context.element.providerResponseId, + responseId: context.element.providerResponseId!, codeBlockIndex: context.codeBlockIndex, languageId: context.languageId, } diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts index b2c5828ece2..4d9bf1fe75b 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts @@ -16,7 +16,7 @@ import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/ import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions'; import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; import { CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_FILTERED, CONTEXT_RESPONSE_VOTE } from 'vs/workbench/contrib/chat/common/chatContextKeys'; -import { IChatService, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatService, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; import { isRequestVM, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellEditType, CellKind, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -52,14 +52,15 @@ export function registerChatTitleActions() { } const chatService = accessor.get(IChatService); - chatService.notifyUserAction({ + chatService.notifyUserAction({ providerId: item.providerId, agentId: item.agent?.id, sessionId: item.sessionId, + requestId: item.requestId, action: { kind: 'vote', direction: InteractiveSessionVoteDirection.Up, - responseId: item.providerResponseId, + responseId: item.providerResponseId!, } }); item.setVote(InteractiveSessionVoteDirection.Up); @@ -94,14 +95,15 @@ export function registerChatTitleActions() { } const chatService = accessor.get(IChatService); - chatService.notifyUserAction({ + chatService.notifyUserAction({ providerId: item.providerId, agentId: item.agent?.id, sessionId: item.sessionId, + requestId: item.requestId, action: { kind: 'vote', direction: InteractiveSessionVoteDirection.Down, - responseId: item.providerResponseId, + responseId: item.providerResponseId!, } }); item.setVote(InteractiveSessionVoteDirection.Down); From 58bdf2c7c40be6f4494ae35a09528708832cf357 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2023 06:51:06 +0200 Subject: [PATCH 216/290] :up: distro (#195858) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6301522d2f2..8f91ee4159f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.84.0", - "distro": "0f218422a902175f8b82cbf0f13fa4feb278f22a", + "distro": "b30d9687a6941b0d17b73334fc5a0f12590bff90", "author": { "name": "Microsoft Corporation" }, From 493d20b9a27307773007f33da92591fc0a03b4f9 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2023 22:04:02 -0700 Subject: [PATCH 217/290] Fix accepting the welcome message followup (#195862) --- src/vs/workbench/contrib/chat/browser/chatWidget.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index fb9d7b92dcd..65e2434e130 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -416,6 +416,8 @@ export class ChatWidget extends Disposable implements IChatWidget { return; } + this.acceptInput(e.followup.message); + if (!e.response) { // Followups can be shown by the welcome message, then there is no response associated. // At some point we probably want telemetry for these too. @@ -432,7 +434,6 @@ export class ChatWidget extends Disposable implements IChatWidget { followup: e.followup }, }); - this.acceptInput(e.followup.message); })); this._register(this.inputPart.onDidChangeHeight(() => this.bodyDimension && this.layout(this.bodyDimension.height, this.bodyDimension.width))); } From 7ff40aa77dd883eaa451d345880937ad56714708 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Oct 2023 22:07:25 -0700 Subject: [PATCH 218/290] Revert "fix: rerender chat pane when provider is added (#195845)" (#195860) This reverts commit e5b7340d189d6814b139401009b2f8ab3cda0ea1. --- src/vs/workbench/contrib/chat/browser/chatViewPane.ts | 3 --- src/vs/workbench/contrib/chat/common/chatService.ts | 1 - src/vs/workbench/contrib/chat/common/chatServiceImpl.ts | 4 ---- 3 files changed, 8 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index d5ced73f860..9be6f027aba 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -66,9 +66,6 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { // View state for the ViewPane is currently global per-provider basically, but some other strictly per-model state will require a separate memento. this.memento = new Memento('interactive-session-view-' + this.chatViewOptions.providerId, this.storageService); this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState; - this._register(this.chatService.onDidRegisterProvider(({ providerId }) => { - if (providerId === this.chatViewOptions.providerId) { this.updateModel(); } - })); } private updateModel(model?: IChatModel | undefined): void { diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 369840dfe8e..d3e13df3fe3 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -265,7 +265,6 @@ export interface IChatService { transferredSessionData: IChatTransferredSessionData | undefined; onDidSubmitSlashCommand: Event<{ slashCommand: string; sessionId: string }>; - onDidRegisterProvider: Event<{ providerId: string }>; registerProvider(provider: IChatProvider): IDisposable; hasProviders(): boolean; getProviderInfos(): IChatProviderInfo[]; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 04fad070cd9..2b09ccbe24b 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -149,9 +149,6 @@ export class ChatService extends Disposable implements IChatService { private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string }>()); public readonly onDidDisposeSession = this._onDidDisposeSession.event; - private readonly _onDidRegisterProvider = this._register(new Emitter<{ providerId: string }>()); - public readonly onDidRegisterProvider = this._onDidRegisterProvider.event; - constructor( @IStorageService private readonly storageService: IStorageService, @ILogService private readonly logService: ILogService, @@ -745,7 +742,6 @@ export class ChatService extends Disposable implements IChatService { this._providers.set(provider.id, provider); this._hasProvider.set(true); - this._onDidRegisterProvider.fire({ providerId: provider.id }); Array.from(this._sessionModels.values()) .filter(model => model.providerId === provider.id) From 198bbdf35eff992267104ced9bb575152cd645a7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2023 09:33:39 +0200 Subject: [PATCH 219/290] aux window - avoid more global `window` (#195869) * aux window - avoid more global `window` * aux window - avoid more global `document` --- src/vs/base/browser/dom.ts | 9 +-------- src/vs/workbench/browser/layout.ts | 6 +++--- .../parts/notifications/notificationsCenter.ts | 6 +++--- .../browser/parts/notifications/notificationsList.ts | 6 +++--- .../parts/notifications/notificationsToasts.ts | 6 +++--- .../contrib/accessibility/browser/accessibleView.ts | 4 ++-- .../contrib/codeEditor/browser/toggleWordWrap.ts | 11 ++++++++--- .../workbench/contrib/debug/browser/linkDetector.ts | 3 ++- src/vs/workbench/contrib/debug/browser/repl.ts | 10 ++++++---- .../contrib/files/browser/views/explorerView.ts | 2 +- .../contrib/files/browser/views/explorerViewer.ts | 7 ++++--- .../workbench/contrib/markers/browser/markersView.ts | 4 ++-- .../browser/contrib/clipboard/notebookClipboard.ts | 4 ++-- .../contrib/notebook/browser/notebookEditorWidget.ts | 2 +- .../workbench/contrib/scm/browser/scm.contribution.ts | 7 ++++--- src/vs/workbench/contrib/search/browser/searchView.ts | 4 ++-- .../welcomeWalkthrough/browser/walkThroughPart.ts | 4 ++-- 17 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index d8302103599..024e9988544 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -602,14 +602,7 @@ export function getLargestChildWidth(parent: HTMLElement, children: HTMLElement[ // ---------------------------------------------------------------------------------------- export function isAncestor(testChild: Node | null, testAncestor: Node | null): boolean { - while (testChild) { - if (testChild === testAncestor) { - return true; - } - testChild = testChild.parentNode; - } - - return false; + return Boolean(testAncestor?.contains(testChild)); } const parentFlowToDataKey = 'parentFlowToElementId'; diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 2708caa9350..51a6a96f7bc 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -5,7 +5,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { EventType, addDisposableListener, getClientArea, Dimension, position, size, IDimension, isAncestorUsingFlowTo, computeScreenAwareSize, getActiveDocument, getWindows } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, getClientArea, Dimension, position, size, IDimension, isAncestorUsingFlowTo, computeScreenAwareSize, getActiveDocument, getWindows, getActiveWindow } from 'vs/base/browser/dom'; import { onDidChangeFullscreen, isFullscreen, isWCOEnabled } from 'vs/base/browser/browser'; import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; import { isWindows, isLinux, isMacintosh, isWeb, isNative, isIOS } from 'vs/base/common/platform'; @@ -1463,8 +1463,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } resizePart(part: Parts, sizeChangeWidth: number, sizeChangeHeight: number): void { - const sizeChangePxWidth = Math.sign(sizeChangeWidth) * computeScreenAwareSize(window, Math.abs(sizeChangeWidth)); - const sizeChangePxHeight = Math.sign(sizeChangeHeight) * computeScreenAwareSize(window, Math.abs(sizeChangeHeight)); + const sizeChangePxWidth = Math.sign(sizeChangeWidth) * computeScreenAwareSize(getActiveWindow(), Math.abs(sizeChangeWidth)); + const sizeChangePxHeight = Math.sign(sizeChangeHeight) * computeScreenAwareSize(getActiveWindow(), Math.abs(sizeChangeHeight)); let viewSize: IViewSize; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index c7e9ab26652..51115350f94 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -14,7 +14,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { INotificationsCenterController, NotificationActionRunner } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { isAncestor, Dimension } from 'vs/base/browser/dom'; +import { Dimension, isAncestorOfActiveElement } from 'vs/base/browser/dom'; import { widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { localize } from 'vs/nls'; @@ -222,7 +222,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente notificationsList.updateNotificationsList(e.index, 1, [e.item]); break; case NotificationChangeType.REMOVE: - focusEditor = isAncestor(document.activeElement, notificationsCenterContainer); + focusEditor = isAncestorOfActiveElement(notificationsCenterContainer); notificationsList.updateNotificationsList(e.index, 1); e.item.updateVisibility(false); break; @@ -247,7 +247,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente return; // already hidden } - const focusEditor = isAncestor(document.activeElement, this.notificationsCenterContainer); + const focusEditor = isAncestorOfActiveElement(this.notificationsCenterContainer); // Hide this._isVisible = false; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index 727e2e866a3..5ac8c173685 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/notificationsList'; import { localize } from 'vs/nls'; -import { isAncestor, trackFocus } from 'vs/base/browser/dom'; +import { isAncestorOfActiveElement, trackFocus } from 'vs/base/browser/dom'; import { WorkbenchList } from 'vs/platform/list/browser/listService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IListAccessibilityProvider, IListOptions } from 'vs/base/browser/ui/list/listWidget'; @@ -133,7 +133,7 @@ export class NotificationsList extends Disposable { updateNotificationsList(start: number, deleteCount: number, items: INotificationViewItem[] = []) { const [list, listContainer] = assertAllDefined(this.list, this.listContainer); - const listHasDOMFocus = isAncestor(document.activeElement, listContainer); + const listHasDOMFocus = isAncestorOfActiveElement(listContainer); // Remember focus and relative top of that item const focusedIndex = list.getFocus()[0]; @@ -223,7 +223,7 @@ export class NotificationsList extends Disposable { return false; // not created yet } - return isAncestor(document.activeElement, this.listContainer); + return isAncestorOfActiveElement(this.listContainer); } layout(width: number, maxHeight?: number): void { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index 35785314672..f6fa63e49f2 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/notificationsToasts'; import { localize } from 'vs/nls'; import { INotificationsModel, NotificationChangeType, INotificationChangeEvent, INotificationViewItem, NotificationViewItemContentChangeKind } from 'vs/workbench/common/notifications'; import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { isAncestor, addDisposableListener, EventType, Dimension, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; +import { addDisposableListener, EventType, Dimension, scheduleAtNextAnimationFrame, isAncestorOfActiveElement } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList'; import { Event, Emitter } from 'vs/base/common/event'; @@ -322,7 +322,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast // UI const notificationToast = this.mapNotificationToToast.get(item); if (notificationToast) { - const toastHasDOMFocus = isAncestor(document.activeElement, notificationToast.container); + const toastHasDOMFocus = isAncestorOfActiveElement(notificationToast.container); if (toastHasDOMFocus) { focusEditor = !(this.focusNext() || this.focusPrevious()); // focus next if any, otherwise focus editor } @@ -380,7 +380,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast } hide(): void { - const focusEditor = this.notificationsToastsContainer ? isAncestor(document.activeElement, this.notificationsToastsContainer) : false; + const focusEditor = this.notificationsToastsContainer ? isAncestorOfActiveElement(this.notificationsToastsContainer) : false; this.removeToasts(); diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index f7090c8f8e8..c73385b4246 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EventType, addDisposableListener, isActiveElement } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, getActiveWindow, isActiveElement } from 'vs/base/browser/dom'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { alert } from 'vs/base/browser/ui/aria/aria'; @@ -264,7 +264,7 @@ export class AccessibleView extends Disposable { return; } const delegate: IContextViewDelegate = { - getAnchor: () => { return { x: (window.innerWidth / 2) - ((Math.min(this._layoutService.dimension.width * 0.62 /* golden cut */, DIMENSIONS.MAX_WIDTH)) / 2), y: this._layoutService.offset.quickPickTop }; }, + getAnchor: () => { return { x: (getActiveWindow().innerWidth / 2) - ((Math.min(this._layoutService.dimension.width * 0.62 /* golden cut */, DIMENSIONS.MAX_WIDTH)) / 2), y: this._layoutService.offset.quickPickTop }; }, render: (container) => { container.classList.add('accessible-view-container'); return this._render(provider!, container, showAccessibleViewHelp); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index 85be3c855a2..d3849333ddc 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -21,6 +21,8 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { Event } from 'vs/base/common/event'; +import { addDisposableListener, onDidRegisterWindow } from 'vs/base/browser/dom'; const transientWordWrapState = 'transientWordWrapState'; const isWordWrapMinifiedKey = 'isWordWrapMinified'; @@ -255,7 +257,7 @@ function canToggleWordWrap(codeEditorService: ICodeEditorService, editor: ICodeE return true; } -class EditorWordWrapContextKeyTracker implements IWorkbenchContribution { +class EditorWordWrapContextKeyTracker extends Disposable implements IWorkbenchContribution { private readonly _canToggleWordWrap: IContextKey; private readonly _editorWordWrap: IContextKey; @@ -267,8 +269,11 @@ class EditorWordWrapContextKeyTracker implements IWorkbenchContribution { @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @IContextKeyService private readonly _contextService: IContextKeyService, ) { - window.addEventListener('focus', () => this._update(), true); - window.addEventListener('blur', () => this._update(), true); + super(); + this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposableStore }) => { + disposableStore.add(addDisposableListener(window, 'focus', () => this._update(), true)); + disposableStore.add(addDisposableListener(window, 'blur', () => this._update(), true)); + }, { window, disposableStore: this._store })); this._editorService.onDidActiveEditorChange(() => this._update()); this._canToggleWordWrap = CAN_TOGGLE_WORD_WRAP.bindTo(this._contextService); this._editorWordWrap = EDITOR_WORD_WRAP.bindTo(this._contextService); diff --git a/src/vs/workbench/contrib/debug/browser/linkDetector.ts b/src/vs/workbench/contrib/debug/browser/linkDetector.ts index abfca65cb23..484f3286dba 100644 --- a/src/vs/workbench/contrib/debug/browser/linkDetector.ts +++ b/src/vs/workbench/contrib/debug/browser/linkDetector.ts @@ -18,6 +18,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { localize } from 'vs/nls'; import { ITunnelService } from 'vs/platform/tunnel/common/tunnel'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { getWindow } from 'vs/base/browser/dom'; const CONTROL_CODES = '\\u0000-\\u0020\\u007f-\\u009f'; const WEB_LINK_REGEX = new RegExp('(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\\/\\/|data:|www\\.)[^\\s' + CONTROL_CODES + '"]{2,}[^\\s' + CONTROL_CODES + '"\')}\\],:;.!?]', 'ug'); @@ -201,7 +202,7 @@ export class LinkDetector { link.onmousemove = (event) => { link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey); }; link.onmouseleave = () => link.classList.remove('pointer'); link.onclick = (event) => { - const selection = window.getSelection(); + const selection = getWindow(link).getSelection(); if (!selection || selection.type === 'Range') { return; // do not navigate when user is selecting } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 7be4e8eb0bd..9805ab089a4 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -570,16 +570,18 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget { this._register(registerNavigableContainer({ focusNotifiers: [this, this.filterWidget], focusNextWidget: () => { + const element = this.tree?.getHTMLElement(); if (this.filterWidget.hasFocus()) { this.tree?.domFocus(); - } else if (this.tree?.getHTMLElement() === document.activeElement) { + } else if (element && dom.isActiveElement(element)) { this.focus(); } }, focusPreviousWidget: () => { + const element = this.tree?.getHTMLElement(); if (this.replInput.hasTextFocus()) { this.tree?.domFocus(); - } else if (this.tree?.getHTMLElement() === document.activeElement) { + } else if (element && dom.isActiveElement(element)) { this.focusFilter(); } } @@ -648,7 +650,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget { this._register(tree.onContextMenu(e => this.onContextMenu(e))); let lastSelectedString: string; this._register(tree.onMouseClick(() => { - const selection = window.getSelection(); + const selection = dom.getWindow(this.treeContainer).getSelection(); if (!selection || selection.type !== 'Range' || lastSelectedString === selection.toString()) { // only focus the input if the user is not currently selecting. this.replInput.focus(); @@ -1070,7 +1072,7 @@ registerAction2(class extends Action2 { async run(accessor: ServicesAccessor, element: IReplElement): Promise { const clipboardService = accessor.get(IClipboardService); const debugService = accessor.get(IDebugService); - const nativeSelection = window.getSelection(); + const nativeSelection = dom.getActiveWindow().getSelection(); const selectedText = nativeSelection?.toString(); if (selectedText && selectedText.length > 0) { return clipboardService.writeText(selectedText); diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index d3d8d5c7e59..ca2b5d06823 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -325,7 +325,7 @@ export class ExplorerView extends ViewPane implements IExplorerView { } hasFocus(): boolean { - return DOM.isAncestor(document.activeElement, this.container); + return DOM.isAncestorOfActiveElement(this.container); } getContext(respectMultiSelection: boolean): ExplorerItem[] { diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index bfebab5f73d..d567ec80916 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -621,11 +621,12 @@ export class FilesRenderer implements ICompressibleTreeRenderer { const contextKeyService = accessor.get(IContextKeyService); - const context = contextKeyService.getContext(document.activeElement); + const context = contextKeyService.getContext(getActiveElement()); const repositoryId = context.getValue('scmRepository'); if (!repositoryId) { @@ -336,7 +337,7 @@ const viewNextCommitCommand = { handler: (accessor: ServicesAccessor) => { const contextKeyService = accessor.get(IContextKeyService); const scmService = accessor.get(ISCMService); - const context = contextKeyService.getContext(document.activeElement); + const context = contextKeyService.getContext(getActiveElement()); const repositoryId = context.getValue('scmRepository'); const repository = repositoryId ? scmService.getRepository(repositoryId) : undefined; repository?.input.showNextHistoryValue(); @@ -349,7 +350,7 @@ const viewPreviousCommitCommand = { handler: (accessor: ServicesAccessor) => { const contextKeyService = accessor.get(IContextKeyService); const scmService = accessor.get(ISCMService); - const context = contextKeyService.getContext(document.activeElement); + const context = contextKeyService.getContext(getActiveElement()); const repositoryId = context.getValue('scmRepository'); const repository = repositoryId ? scmService.getRepository(repositoryId) : undefined; repository?.input.showPreviousHistoryValue(); diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index f1434f91db9..6bc3f38e680 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -1072,7 +1072,7 @@ export class SearchView extends ViewPane { } private updateTextFromFindWidget(controller: CommonFindController, { allowSearchOnType = true }): boolean { - if (!this.searchConfig.seedWithNearestWord && (window.getSelection()?.toString() ?? '') === '') { + if (!this.searchConfig.seedWithNearestWord && (dom.getActiveWindow().getSelection()?.toString() ?? '') === '') { return false; } @@ -1275,7 +1275,7 @@ export class SearchView extends ViewPane { } private getSearchTextFromEditor(allowUnselectedWord: boolean, editor?: IEditor): string | null { - if (dom.isAncestor(document.activeElement, this.getContainer())) { + if (dom.isAncestorOfActiveElement(this.getContainer())) { return null; } diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts index 002c6ef9c5f..29f5aace84c 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts @@ -32,7 +32,7 @@ import { UILabelProvider } from 'vs/base/common/keybindingLabels'; import { OS, OperatingSystem } from 'vs/base/common/platform'; import { deepClone } from 'vs/base/common/objects'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { addDisposableListener, Dimension, safeInnerHtml, size } from 'vs/base/browser/dom'; +import { addDisposableListener, Dimension, getWindow, safeInnerHtml, size } from 'vs/base/browser/dom'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -156,7 +156,7 @@ export class WalkThroughPart extends EditorPane { this.content.addEventListener('click', event => { for (let node = event.target as HTMLElement; node; node = node.parentNode as HTMLElement) { if (node instanceof HTMLAnchorElement && node.href) { - const baseElement = window.document.getElementsByTagName('base')[0] || window.location; + const baseElement = node.ownerDocument.getElementsByTagName('base')[0] || getWindow(node).location; if (baseElement && node.href.indexOf(baseElement.href) >= 0 && node.hash) { const scrollTarget = this.content.querySelector(node.hash); const innerContent = this.content.firstElementChild; From ae2dd44a30ae5211685ae5d0b4713850af8ceda2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2023 10:38:24 +0200 Subject: [PATCH 220/290] voice - fix issue with missing provider registration event (#195873) --- .../contrib/chat/electron-sandbox/chat.contribution.ts | 8 ++++++-- src/vs/workbench/contrib/speech/common/speechService.ts | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts b/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts index 409022e8651..b382598b7bb 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts @@ -32,9 +32,13 @@ class VoiceChatActionsContributor extends Disposable implements IWorkbenchContri constructor(@ISpeechService speechService: ISpeechService) { super(); - this._register(Event.once(speechService.onDidRegisterSpeechProvider)(() => { + if (speechService.hasSpeechProvider) { registerVoiceChatActions(); - })); + } else { + this._register(Event.once(speechService.onDidRegisterSpeechProvider)(() => { + registerVoiceChatActions(); + })); + } } } diff --git a/src/vs/workbench/contrib/speech/common/speechService.ts b/src/vs/workbench/contrib/speech/common/speechService.ts index c071ce0746d..021a676e580 100644 --- a/src/vs/workbench/contrib/speech/common/speechService.ts +++ b/src/vs/workbench/contrib/speech/common/speechService.ts @@ -47,6 +47,8 @@ export interface ISpeechService { readonly onDidRegisterSpeechProvider: Event; readonly onDidUnregisterSpeechProvider: Event; + readonly hasSpeechProvider: boolean; + registerSpeechProvider(identifier: string, provider: ISpeechProvider): IDisposable; createSpeechToTextSession(token: CancellationToken): ISpeechToTextSession; @@ -62,6 +64,8 @@ export class SpeechService implements ISpeechService { private readonly _onDidUnregisterSpeechProvider = new Emitter(); readonly onDidUnregisterSpeechProvider = this._onDidUnregisterSpeechProvider.event; + get hasSpeechProvider(): boolean { return this.providers.size > 0; } + private readonly providers = new Map(); constructor(@ILogService private readonly logService: ILogService) { } From 6db41844bc97b1a86841724c3c38b44001f22d59 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 18 Oct 2023 11:39:22 +0200 Subject: [PATCH 221/290] * show a diff zone per "change region" * don't show whole range highlights anymore --- .../browser/inlineChatController.ts | 47 +++++---- .../browser/inlineChatLivePreviewWidget.ts | 84 +++++++--------- .../browser/inlineChatStrategies.ts | 95 +++++++++++++------ .../contrib/inlineChat/browser/utils.ts | 8 +- 4 files changed, 132 insertions(+), 102 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index c10fb758a41..5f6b0882d69 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -8,14 +8,14 @@ import { Barrier, raceCancellationError } from 'vs/base/common/async'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Emitter, Event } from 'vs/base/common/event'; -import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { StopWatch } from 'vs/base/common/stopwatch'; import { assertType } from 'vs/base/common/types'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon'; -import { ModelDecorationOptions, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; +import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { IModelService } from 'vs/editor/common/services/model'; import { InlineCompletionsController } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController'; @@ -39,7 +39,6 @@ import { generateUuid } from 'vs/base/common/uuid'; import { TextEdit } from 'vs/editor/common/languages'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IModelDeltaDecoration } from 'vs/editor/common/model'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', @@ -93,12 +92,12 @@ export class InlineChatController implements IEditorContribution { return editor.getContribution(INLINE_CHAT_ID); } - private static _decoBlock = ModelDecorationOptions.register({ - description: 'inline-chat', - showIfCollapsed: false, - isWholeLine: true, - className: 'inline-chat-block-selection', - }); + // private static _decoBlock = ModelDecorationOptions.register({ + // description: 'inline-chat', + // showIfCollapsed: false, + // isWholeLine: true, + // className: 'inline-chat-block-selection', + // }); private static _promptHistory: string[] = []; private _historyOffset: number = -1; @@ -335,22 +334,22 @@ export class InlineChatController implements IEditorContribution { this._sessionStore.clear(); - const wholeRangeDecoration = this._editor.createDecorationsCollection(); - const updateWholeRangeDecoration = () => { + // const wholeRangeDecoration = this._editor.createDecorationsCollection(); + // const updateWholeRangeDecoration = () => { - const range = this._activeSession!.wholeRange.value; - const decorations: IModelDeltaDecoration[] = []; - if (!range.isEmpty()) { - decorations.push({ - range, - options: InlineChatController._decoBlock - }); - } - wholeRangeDecoration.set(decorations); - }; - this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear())); - this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration)); - updateWholeRangeDecoration(); + // const range = this._activeSession!.wholeRange.value; + // const decorations: IModelDeltaDecoration[] = []; + // if (!range.isEmpty()) { + // decorations.push({ + // range, + // options: InlineChatController._decoBlock + // }); + // } + // wholeRangeDecoration.set(decorations); + // }; + // this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear())); + // this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration)); + // updateWholeRangeDecoration(); this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []); this._updatePlaceholder(); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index 63e66be5f3d..11b1281498c 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Dimension, h } from 'vs/base/browser/dom'; -import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { MutableDisposable } from 'vs/base/common/lifecycle'; import { assertType } from 'vs/base/common/types'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; @@ -35,14 +35,14 @@ import { ILanguageService } from 'vs/editor/common/languages/language'; import { FoldingController } from 'vs/editor/contrib/folding/browser/folding'; import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { generateUuid } from 'vs/base/common/uuid'; export class InlineChatLivePreviewWidget extends ZoneWidget { - private static readonly _hideId = 'overlayDiff'; + private readonly _hideId = `overlayDiff:${generateUuid()}`; private readonly _elements = h('div.inline-chat-diff-widget@domNode'); - private readonly _sessionStore = this._disposables.add(new DisposableStore()); private readonly _diffEditor: IDiffEditor; private _dim: Dimension | undefined; private _isVisible: boolean = false; @@ -50,6 +50,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { constructor( editor: ICodeEditor, private readonly _session: Session, + onDidChangeDiff: (() => void) | undefined, @IInstantiationService instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, @ILogService private readonly _logService: ILogService, @@ -92,6 +93,10 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { lineDecorationsWidth: editor.getLayoutInfo().decorationsWidth }); + if (onDidChangeDiff) { + this._disposables.add(this._diffEditor.onDidUpdateDiff(() => { onDidChangeDiff(); })); + } + const highlighter = WordHighlighterContribution.get(editor); if (highlighter) { this._disposables.add(highlighter.linkWordHighlighters(this._diffEditor.getModifiedEditor())); @@ -132,33 +137,17 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { override hide(): void { this._cleanupFullDiff(); - this._sessionStore.clear(); super.hide(); this._isVisible = false; } override show(): void { - assertType(this.editor.hasModel()); - this._sessionStore.clear(); - this._isVisible = true; - - this._sessionStore.add(this._diffEditor.onDidUpdateDiff(() => { - const result = this._diffEditor.getDiffComputationResult(); - const hasFocus = this._diffEditor.hasTextFocus(); - this._updateFromChanges(this._session.wholeRange.value, result?.changes2 ?? []); - // TODO@jrieken find a better fix for this. this is the challenge: - // the _doShowForChanges method invokes show of the zone widget which removes and adds the - // zone and overlay parts. this dettaches and reattaches the dom nodes which means they lose - // focus - if (hasFocus) { - this._diffEditor.focus(); - } - })); - this._updateFromChanges(this._session.wholeRange.value, this._session.lastTextModelChanges); + throw new Error('use showForChanges'); } - private _updateFromChanges(range: Range, changes: readonly DetailedLineRangeMapping[]): void { - assertType(this.editor.hasModel()); + showForChanges(changes: readonly DetailedLineRangeMapping[]): void { + const hasFocus = this._diffEditor.hasTextFocus(); + this._isVisible = true; if (changes.length === 0 || this._session.textModel0.getValueLength() === 0) { // no change or changes to an empty file @@ -167,16 +156,26 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { } else { // complex changes this._logService.debug('[IE] livePreview-mode: full diff'); - this._renderChangesWithFullDiff(changes, range); + this._renderChangesWithFullDiff(changes); + } + + // TODO@jrieken find a better fix for this. this is the challenge: + // the `_updateFromChanges` method invokes show of the zone widget which removes and adds the + // zone and overlay parts. this dettaches and reattaches the dom nodes which means they lose + // focus + if (hasFocus) { + this._diffEditor.focus(); } } + // --- full diff - private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[], range: Range) { + private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[]) { + assertType(this.editor.hasModel()); - const modified = this.editor.getModel()!; - const ranges = this._computeHiddenRanges(modified, range, changes); + const modified = this.editor.getModel(); + const ranges = this._computeHiddenRanges(modified, changes); this._hideEditorRanges(this.editor, [ranges.modifiedHidden]); this._hideEditorRanges(this._diffEditor.getOriginalEditor(), ranges.originalDiffHidden); @@ -187,25 +186,20 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { const lineCountModified = ranges.modifiedHidden.length; const lineCountOriginal = ranges.originalHidden.length; - const lineHeightDiff = Math.max(lineCountModified, lineCountOriginal); - const lineHeightPadding = (this.editor.getOption(EditorOption.lineHeight) / 12) /* padding-top/bottom*/; - const heightInLines = lineHeightDiff + lineHeightPadding; + const heightInLines = Math.max(lineCountModified, lineCountOriginal); super.show(ranges.anchor, heightInLines); this._logService.debug(`[IE] diff SHOWING at ${ranges.anchor} with ${heightInLines} lines height`); } private _cleanupFullDiff() { - this.editor.setHiddenAreas([], InlineChatLivePreviewWidget._hideId); - this._diffEditor.getOriginalEditor().setHiddenAreas([], InlineChatLivePreviewWidget._hideId); - this._diffEditor.getModifiedEditor().setHiddenAreas([], InlineChatLivePreviewWidget._hideId); + this.editor.setHiddenAreas([], this._hideId); + this._diffEditor.getOriginalEditor().setHiddenAreas([], this._hideId); + this._diffEditor.getModifiedEditor().setHiddenAreas([], this._hideId); super.hide(); } - private _computeHiddenRanges(model: ITextModel, range: Range, changes: readonly DetailedLineRangeMapping[]) { - if (changes.length === 0) { - changes = [new DetailedLineRangeMapping(LineRange.fromRange(range), LineRange.fromRange(range), undefined)]; - } + private _computeHiddenRanges(model: ITextModel, changes: readonly DetailedLineRangeMapping[]) { let originalLineRange = changes[0].original; let modifiedLineRange = changes[0].modified; @@ -214,16 +208,8 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { modifiedLineRange = modifiedLineRange.join(changes[i].modified); } - const startDelta = modifiedLineRange.startLineNumber - range.startLineNumber; - if (startDelta > 0) { - modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber - startDelta, modifiedLineRange.endLineNumberExclusive); - originalLineRange = new LineRange(originalLineRange.startLineNumber - startDelta, originalLineRange.endLineNumberExclusive); - } - - const endDelta = range.endLineNumber - (modifiedLineRange.endLineNumberExclusive - 1); - if (endDelta > 0) { - modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber, modifiedLineRange.endLineNumberExclusive + endDelta); - originalLineRange = new LineRange(originalLineRange.startLineNumber, originalLineRange.endLineNumberExclusive + endDelta); + if (originalLineRange.isEmpty) { + originalLineRange = new LineRange(originalLineRange.startLineNumber, originalLineRange.endLineNumberExclusive + 1); } const originalDiffHidden = invertLineRange(originalLineRange, this._session.textModel0); @@ -256,7 +242,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { } else { hiddenRanges = lineRanges.map(lineRangeAsRange); } - editor.setHiddenAreas(hiddenRanges, InlineChatLivePreviewWidget._hideId); + editor.setHiddenAreas(hiddenRanges, this._hideId); this._logService.debug(`[IE] diff HIDING ${hiddenRanges} for ${editor.getId()} with ${String(editor.getModel()?.uri)}`); } @@ -276,7 +262,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { const newDim = new Dimension(widthInPixel, heightInPixel); if (!Dimension.equals(this._dim, newDim)) { this._dim = newDim; - this._diffEditor.layout(this._dim.with(undefined, this._dim.height - 12 /* padding */)); + this._diffEditor.layout(this._dim.with(undefined, this._dim.height)); this._logService.debug('[IE] diff LAYOUT', this._dim); } } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 8cdcaa4998d..946a46f1251 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -3,15 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { equals, tail } from 'vs/base/common/arrays'; import { Event } from 'vs/base/common/event'; import { Lazy } from 'vs/base/common/lazy'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; -import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; +import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon'; import { TextEdit } from 'vs/editor/common/languages'; import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model'; @@ -242,7 +243,7 @@ export class LiveStrategy extends EditModeStrategy { @IStorageService protected _storageService: IStorageService, @IBulkEditService protected readonly _bulkEditService: IBulkEditService, @IEditorWorkerService protected readonly _editorWorkerService: IEditorWorkerService, - @IInstantiationService private readonly _instaService: IInstantiationService, + @IInstantiationService protected readonly _instaService: IInstantiationService, ) { super(); this._diffEnabled = configService.getValue('inlineChat.showDiff'); @@ -382,8 +383,9 @@ export class LiveStrategy extends EditModeStrategy { export class LivePreviewStrategy extends LiveStrategy { - private readonly _diffZone: Lazy; private readonly _previewZone: Lazy; + private readonly _diffZonePool: InlineChatLivePreviewWidget[] = []; + private _currentLineRangeGroups: DetailedLineRangeMapping[][] = []; constructor( session: Session, @@ -397,30 +399,82 @@ export class LivePreviewStrategy extends LiveStrategy { ) { super(session, editor, widget, configService, storageService, bulkEditService, editorWorkerService, instaService); - this._diffZone = new Lazy(() => instaService.createInstance(InlineChatLivePreviewWidget, editor, session)); this._previewZone = new Lazy(() => instaService.createInstance(InlineChatFileCreatePreviewWidget, editor)); } override dispose(): void { - this._diffZone.rawValue?.hide(); - this._diffZone.rawValue?.dispose(); + for (const zone of this._diffZonePool) { + zone.hide(); + zone.dispose(); + } this._previewZone.rawValue?.hide(); this._previewZone.rawValue?.dispose(); super.dispose(); } - override async renderProgressChanges(): Promise { - if (!this._diffZone.value.isVisible) { - this._diffZone.value.show(); + + private async _renderDiffZones() { + const diff = await this._editorWorkerService.computeDiff(this._session.textModel0.uri, this._session.textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced'); + if (!diff || diff.changes.length === 0) { + return; } + + const groups: DetailedLineRangeMapping[][] = []; + let group = [diff.changes[0]]; + groups.push(group); + + for (let i = 1; i < diff.changes.length; i++) { + const last = tail(group); + const next = diff.changes[i]; + + // when the distance between the two changes is less than 75% of the total number of lines changed + // they get merged into the same group + const treshold = Math.ceil((next.modified.length + last.modified.length) * .75); + if (next.modified.startLineNumber - last.modified.endLineNumberExclusive <= treshold) { + group.push(next); + } else { + group = [next]; + groups.push(group); + } + } + + const beforeAndNowAreEqual = equals(this._currentLineRangeGroups, groups, (groupA, groupB) => { + return equals(groupA, groupB, (mappingA, mappingB) => { + return mappingA.original.equals(mappingB.original) && mappingA.modified.equals(mappingB.modified); + }); + }); + + if (beforeAndNowAreEqual) { + return; + } + + this._currentLineRangeGroups = groups; + + const handleDiff = () => { + this._renderDiffZones(); + }; + + // create enough zones + while (groups.length > this._diffZonePool.length) { + this._diffZonePool.push(this._instaService.createInstance(InlineChatLivePreviewWidget, this._editor, this._session, this._diffZonePool.length === 0 ? handleDiff : undefined)); + } + for (let i = 0; i < groups.length; i++) { + this._diffZonePool[i].showForChanges(groups[i]); + } + // hide unused zones + for (let i = groups.length; i < this._diffZonePool.length; i++) { + this._diffZonePool[i].hide(); + } + } + + override async renderProgressChanges(): Promise { + return this._renderDiffZones(); } override async renderChanges(response: EditResponse) { this._updateSummaryMessage(); - if (this._diffEnabled) { - this._diffZone.value.show(); - } + await this._renderDiffZones(); if (response.singleCreateFileEdit) { this._previewZone.value.showCreation(this._session.wholeRange.value.collapseToEnd(), response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits)); @@ -429,25 +483,12 @@ export class LivePreviewStrategy extends LiveStrategy { } } - protected override _doToggleDiff(): void { - const scrollState = StableEditorScrollState.capture(this._editor); - if (this._diffEnabled) { - this._diffZone.value.show(); - } else { - this._diffZone.value.hide(); - } - scrollState.restore(this._editor); - } - override hasFocus(): boolean { - return super.hasFocus() || Boolean(this._diffZone.rawValue?.hasFocus()) || Boolean(this._previewZone.rawValue?.hasFocus()); + return super.hasFocus() || Boolean(this._previewZone.rawValue?.hasFocus()) || this._diffZonePool.some(zone => zone.isVisible && zone.hasFocus()); } override getWidgetPosition(): Position | undefined { - if (this._session.lastTextModelChanges.length) { - return this._session.wholeRange.value.getStartPosition().delta(-1); - } - return this._session.wholeRange.value.getStartPosition().delta(-1); + return undefined; } } diff --git a/src/vs/workbench/contrib/inlineChat/browser/utils.ts b/src/vs/workbench/contrib/inlineChat/browser/utils.ts index 880c7778b11..a2a77ac6f2d 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/utils.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/utils.ts @@ -12,8 +12,12 @@ export function invertLineRange(range: LineRange, model: ITextModel): LineRange[ return []; } const result: LineRange[] = []; - result.push(new LineRange(1, range.startLineNumber)); - result.push(new LineRange(range.endLineNumberExclusive, model.getLineCount() + 1)); + if (range.startLineNumber > 1) { + result.push(new LineRange(1, range.startLineNumber)); + } + if (range.endLineNumberExclusive < model.getLineCount() + 1) { + result.push(new LineRange(range.endLineNumberExclusive, model.getLineCount() + 1)); + } return result.filter(r => !r.isEmpty); } From 8c810ad98d21be2184dd3e9233d5c91f5ff102c2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2023 11:42:59 +0200 Subject: [PATCH 222/290] chat - relayout when input toolbar changes (#195877) --- .../workbench/contrib/chat/browser/chatInputPart.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 7576aadb922..e81c2705d7a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -79,6 +79,9 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge private inputEditorHasText: IContextKey; private providerId: string | undefined; + private cachedDimensions: dom.Dimension | undefined; + private cachedToolbarWidth: number | undefined; + readonly inputUri = URI.parse(`${ChatInputPart.INPUT_SCHEME}:input-${ChatInputPart._counter++}`); constructor( @@ -251,6 +254,11 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge })); this.toolbar.getElement().classList.add('interactive-execute-toolbar'); this.toolbar.context = { widget }; + this._register(this.toolbar.onDidChangeMenuItems(() => { + if (this.cachedDimensions && typeof this.cachedToolbarWidth === 'number' && this.cachedToolbarWidth !== this.toolbar.getItemsWidth()) { + this.layout(this.cachedDimensions.height, this.cachedDimensions.width); + } + })); if (this.options.renderStyle === 'compact') { const toolbarSide = this._register(this.instantiationService.createInstance(MenuWorkbenchToolBar, inputAndSideToolbar, MenuId.ChatInputSide, { @@ -285,6 +293,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } layout(height: number, width: number): number { + this.cachedDimensions = new dom.Dimension(width, height); + return this._layout(height, width); } @@ -301,7 +311,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge const editorBorder = 2; const editorPadding = 8; - const executeToolbarWidth = this.toolbar.getItemsWidth(); + const executeToolbarWidth = this.cachedToolbarWidth = this.toolbar.getItemsWidth(); const sideToolbarWidth = this.options.renderStyle === 'compact' ? 20 : 0; const initialEditorScrollWidth = this._inputEditor.getScrollWidth(); From f6e7767e8993f369f3ae467a3ea29a5134a79d79 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 18 Oct 2023 11:56:12 +0200 Subject: [PATCH 223/290] tweak position and margin --- .../browser/inlineChatController.ts | 2 +- .../browser/inlineChatStrategies.ts | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 5f6b0882d69..c5d59349076 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -687,7 +687,6 @@ export class InlineChatController implements IEditorContribution { assertType(this._strategy); const { response } = this._activeSession.lastExchange!; - this._showWidget(false); let status: string | undefined; @@ -751,6 +750,7 @@ export class InlineChatController implements IEditorContribution { await this._strategy.renderChanges(response); } this._chatAccessibilityService.acceptResponse(status); + this._showWidget(false); return State.WAIT_FOR_INPUT; } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 946a46f1251..4fa8470f957 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -361,19 +361,11 @@ export class LiveStrategy extends EditModeStrategy { } override getWidgetPosition(): Position | undefined { - const lastTextModelChanges = this._session.lastTextModelChanges; - let lastLineOfLocalEdits: number | undefined; - for (const change of lastTextModelChanges) { - const changeEndLineNumber = change.modified.endLineNumberExclusive - 1; - if (typeof lastLineOfLocalEdits === 'undefined' || lastLineOfLocalEdits < changeEndLineNumber) { - lastLineOfLocalEdits = changeEndLineNumber; - } - } - return lastLineOfLocalEdits ? new Position(lastLineOfLocalEdits, 1) : undefined; + return undefined; } override needsMargin(): boolean { - return !Boolean(this._session.lastTextModelChanges.length); + return true; } hasFocus(): boolean { @@ -488,6 +480,13 @@ export class LivePreviewStrategy extends LiveStrategy { } override getWidgetPosition(): Position | undefined { + for (let i = this._diffZonePool.length - 1; i >= 0; i--) { + const zone = this._diffZonePool[i]; + if (zone.isVisible && zone.position) { + // above last view zone + return zone.position.delta(-1); + } + } return undefined; } } From e47adcbf4bfdbe76aa6240d7186f2723d236d066 Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Wed, 18 Oct 2023 12:07:15 +0200 Subject: [PATCH 224/290] Adapt context menu and commands --- .../browser/actions/layoutActions.ts | 99 +++++++++++++------ .../parts/editor/editor.contribution.ts | 7 +- 2 files changed, 76 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index d4387fb9ea5..a1024ebff97 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -470,49 +470,87 @@ export class ToggleStatusbarVisibilityAction extends Action2 { registerAction2(ToggleStatusbarVisibilityAction); -// --- Base Class Toggle Boolean Setting Action +// --- Hide Editor Tabs -abstract class BaseToggleBooleanSettingAction extends Action2 { +export class HideEditorTabsAction extends Action2 { - protected abstract get settingId(): string; - - override run(accessor: ServicesAccessor): Promise { - const configurationService = accessor.get(IConfigurationService); - - const oldettingValue = configurationService.getValue(this.settingId); - const newSettingValue = !oldettingValue; - - return configurationService.updateValue(this.settingId, newSettingValue); - } -} - -// --- Toggle Tabs Visibility - -export class ToggleTabsVisibilityAction extends BaseToggleBooleanSettingAction { - - static readonly ID = 'workbench.action.toggleTabsVisibility'; + static readonly ID = 'workbench.action.hideEditorTabs'; constructor() { super({ - id: ToggleTabsVisibilityAction.ID, + id: HideEditorTabsAction.ID, title: { - value: localize('toggleTabs', "Toggle Editor Tab Visibility"), - original: 'Toggle Editor Tab Visibility' + value: localize('hideEditorTabs', "Hide Editor Tabs"), + original: 'Hide Editor Tabs' }, category: Categories.View, + precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none').negate(), f1: true }); } - protected override get settingId(): string { - return 'workbench.editor.showTabs'; + override run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + return configurationService.updateValue('workbench.editor.showTabs', 'none'); } } -registerAction2(ToggleTabsVisibilityAction); +registerAction2(HideEditorTabsAction); + +// --- Show Multiple Editor Tabs + +export class ShowMultipleEditorTabsAction extends Action2 { + + static readonly ID = 'workbench.action.showMultipleEditorTabs'; + + constructor() { + super({ + id: ShowMultipleEditorTabsAction.ID, + title: { + value: localize('showMultipleEditorTabs', "Show Multiple Editor Tabs"), + original: 'Show Multiple Editor Tabs' + }, + category: Categories.View, + precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple').negate(), + f1: true + }); + } + + override run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + return configurationService.updateValue('workbench.editor.showTabs', 'multiple'); + } +} +registerAction2(ShowMultipleEditorTabsAction); + +// --- Show Single Editor Tab + +export class ShowSingleEditorTabAction extends Action2 { + + static readonly ID = 'workbench.action.showEditorTab'; + + constructor() { + super({ + id: ShowSingleEditorTabAction.ID, + title: { + value: localize('showSingleEditorTab', "Show Single Editor Tab"), + original: 'Show Single Editor Tab' + }, + category: Categories.View, + precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single').negate(), + f1: true + }); + } + + override run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + return configurationService.updateValue('workbench.editor.showTabs', 'single'); + } +} +registerAction2(ShowSingleEditorTabAction); // --- Toggle Pinned Tabs On Separate Row -export class ToggleSeparatePinnedTabsAction extends BaseToggleBooleanSettingAction { +export class ToggleSeparatePinnedTabsAction extends Action2 { static readonly ID = 'workbench.action.toggleSeparatePinnedEditorTabs'; @@ -529,8 +567,13 @@ export class ToggleSeparatePinnedTabsAction extends BaseToggleBooleanSettingActi }); } - protected override get settingId(): string { - return 'workbench.editor.pinnedTabsOnSeparateRow'; + override run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + + const oldettingValue = configurationService.getValue('workbench.editor.pinnedTabsOnSeparateRow'); + const newSettingValue = !oldettingValue; + + return configurationService.updateValue('workbench.editor.pinnedTabsOnSeparateRow', newSettingValue); } } registerAction2(ToggleSeparatePinnedTabsAction); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 18cbd10b7d3..cca074fe569 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -66,7 +66,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { UntitledTextEditorInputSerializer, UntitledTextEditorWorkingCopyEditorHandler } from 'vs/workbench/services/untitled/common/untitledTextEditorHandler'; import { DynamicEditorConfigurations } from 'vs/workbench/browser/parts/editor/editorConfiguration'; -import { ToggleSeparatePinnedTabsAction, ToggleTabsVisibilityAction } from 'vs/workbench/browser/actions/layoutActions'; +import { HideEditorTabsAction, ShowMultipleEditorTabsAction, ShowSingleEditorTabAction, ToggleSeparatePinnedTabsAction } from 'vs/workbench/browser/actions/layoutActions'; import product from 'vs/platform/product/common/product'; //#region Editor Registrations @@ -355,7 +355,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '2_split', order: 20 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 }); -MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleTabsVisibilityAction.ID, title: localize('toggleTabs', "Editor Tabs"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '3_config', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ShowSingleEditorTabAction.ID, title: localize('showSingleTab', "Show Single Tab") }, group: '3_config', order: 10, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar") }, group: '3_config', order: 15, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none').negate() }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleSeparatePinnedTabsAction.ID, title: localize('toggleSeparatePinnedEditorTabs', "Separate Pinned Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.pinnedTabsOnSeparateRow') }, when: EditorPinnedAndUnpinnedTabsContext, group: '3_config', order: 20 }); // Editor Title Context Menu @@ -374,6 +375,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_ED MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '5_split', order: 40 }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_IN_GROUP, title: localize('splitInGroup', "Split in Group") }, group: '6_split_in_group', order: 10, when: ActiveEditorCanSplitInGroupContext }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: JOIN_EDITOR_IN_GROUP, title: localize('joinInGroup', "Join in Group") }, group: '6_split_in_group', order: 10, when: SideBySideEditorActiveContext }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: ShowMultipleEditorTabsAction.ID, title: localize('showMultipleTabs', "Show Multiple Tabs") }, group: '7_config', order: 10, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single') }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar") }, group: '7_config', order: 20, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none').negate() }); // Editor Title Menu MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_DIFF_SIDE_BY_SIDE, title: localize('inlineView', "Inline View"), toggled: ContextKeyExpr.equals('config.diffEditor.renderSideBySide', false) }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') }); From 303a246f0655b5108ea6e5aeeb9f694affabba7d Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 18 Oct 2023 12:12:31 +0200 Subject: [PATCH 225/290] remove `Session#lastTextModelChanges` because it is often stale. Instead compute on demand --- .../inlineChat/browser/inlineChatActions.ts | 6 +-- .../browser/inlineChatController.ts | 43 ++++++++----------- .../inlineChat/browser/inlineChatSession.ts | 17 ++------ .../browser/inlineChatStrategies.ts | 14 +++--- .../inlineChat/browser/inlineChatWidget.ts | 31 +++++++------ .../test/browser/inlineChatController.test.ts | 8 ++-- 6 files changed, 52 insertions(+), 67 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts index 03802665d4b..2f2cb558da9 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts @@ -331,7 +331,7 @@ export class DiscardAction extends AbstractInlineChatAction { } async runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController, _editor: ICodeEditor, ..._args: any[]): Promise { - ctrl.cancelSession(); + await ctrl.cancelSession(); } } @@ -357,7 +357,7 @@ export class DiscardToClipboardAction extends AbstractInlineChatAction { override async runInlineChatCommand(accessor: ServicesAccessor, ctrl: InlineChatController): Promise { const clipboardService = accessor.get(IClipboardService); - const changedText = ctrl.cancelSession(); + const changedText = await ctrl.cancelSession(); if (changedText !== undefined) { clipboardService.writeText(changedText); } @@ -381,7 +381,7 @@ export class DiscardUndoToNewFileAction extends AbstractInlineChatAction { override async runInlineChatCommand(accessor: ServicesAccessor, ctrl: InlineChatController, editor: ICodeEditor, ..._args: any[]): Promise { const editorService = accessor.get(IEditorService); - const changedText = ctrl.cancelSession(); + const changedText = await ctrl.cancelSession(); if (changedText !== undefined) { const input: IUntitledTextResourceEditorInput = { forceUntitled: true, resource: undefined, contents: changedText, languageId: editor.getModel()?.getLanguageId() }; editorService.openEditor(input, SIDE_GROUP); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index c5d59349076..5ca18ef7a67 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -15,9 +15,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon'; -import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; -import { IModelService } from 'vs/editor/common/services/model'; import { InlineCompletionsController } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController'; import { localize } from 'vs/nls'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -129,7 +127,6 @@ export class InlineChatController implements IEditorContribution { @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService, @ILogService private readonly _logService: ILogService, @IConfigurationService private readonly _configurationService: IConfigurationService, - @IModelService private readonly _modelService: IModelService, @IDialogService private readonly _dialogService: IDialogService, @IContextKeyService contextKeyService: IContextKeyService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @@ -572,7 +569,7 @@ export class InlineChatController implements IEditorContribution { throw new Error('Progress in NOT supported in non-live mode'); } progressEdits.push(data.edits); - await this._makeChanges(progressEdits, false); + await this._makeChanges(data.edits, false); await this._strategy?.renderProgressChanges(); } }); @@ -594,8 +591,9 @@ export class InlineChatController implements IEditorContribution { response = new MarkdownResponse(this._activeSession.textModelN.uri, reply); } else if (reply) { const editResponse = new EditResponse(this._activeSession.textModelN.uri, this._activeSession.textModelN.getAlternativeVersionId(), reply, progressEdits); - if (editResponse.allLocalEdits.length > progressEdits.length) { - await this._makeChanges(editResponse.allLocalEdits, true); + const offset = editResponse.allLocalEdits.length - progressEdits.length; + for (let i = offset; i < editResponse.allLocalEdits.length; i++) { + await this._makeChanges(editResponse.allLocalEdits[i], true); } response = editResponse; } else { @@ -648,26 +646,11 @@ export class InlineChatController implements IEditorContribution { return State.SHOW_RESPONSE; } - private async _makeChanges(allEdits: TextEdit[][], computeMoreMinimalEdits: boolean) { + private async _makeChanges(lastEdits: TextEdit[], computeMoreMinimalEdits: boolean) { assertType(this._activeSession); assertType(this._strategy); - if (allEdits.length === 0) { - return; - } - - // diff-changes from model0 -> modelN+1 - { - const lastEdits = allEdits[allEdits.length - 1]; - const textModelNplus1 = this._modelService.createModel(createTextBufferFactoryFromSnapshot(this._activeSession.textModelN.createSnapshot()), null, undefined, true); - textModelNplus1.applyEdits(lastEdits.map(TextEdit.asEditOperation)); - const diff = await this._editorWorkerService.computeDiff(this._activeSession.textModel0.uri, textModelNplus1.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced'); - this._activeSession.lastTextModelChanges = diff?.changes ?? []; - textModelNplus1.dispose(); - } - // make changes from modelN -> modelN+1 - const lastEdits = allEdits[allEdits.length - 1]; const moreMinimalEdits = computeMoreMinimalEdits ? await this._editorWorkerService.computeHumanReadableDiff(this._activeSession.textModelN.uri, lastEdits) : undefined; const editOperations = (moreMinimalEdits ?? lastEdits).map(TextEdit.asEditOperation); this._log('edits from PROVIDER and after making them MORE MINIMAL', this._activeSession.provider.debugName, lastEdits, moreMinimalEdits); @@ -909,11 +892,19 @@ export class InlineChatController implements IEditorContribution { this._messages.fire(Message.ACCEPT_SESSION); } - cancelSession() { - const result = this._activeSession?.asChangedText(); - if (this._activeSession?.lastExchange && InlineChatController.isEditOrMarkdownResponse(this._activeSession.lastExchange.response)) { - this._activeSession.provider.handleInlineChatResponseFeedback?.(this._activeSession.session, this._activeSession.lastExchange.response.raw, InlineChatResponseFeedbackKind.Undone); + async cancelSession() { + + let result: string | undefined; + if (this._activeSession) { + + const diff = await this._editorWorkerService.computeDiff(this._activeSession.textModel0.uri, this._activeSession.textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced'); + result = this._activeSession.asChangedText(diff?.changes ?? []); + + if (this._activeSession.lastExchange && InlineChatController.isEditOrMarkdownResponse(this._activeSession.lastExchange.response)) { + this._activeSession.provider.handleInlineChatResponseFeedback?.(this._activeSession.session, this._activeSession.lastExchange.response.raw, InlineChatResponseFeedbackKind.Undone); + } } + this._messages.fire(Message.CANCEL_SESSION); return result; } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index 8de79727cea..b5daf7c9c27 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -23,9 +23,9 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Iterable } from 'vs/base/common/iterator'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { isCancellationError } from 'vs/base/common/errors'; -import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { raceCancellation } from 'vs/base/common/async'; +import { LineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; export type Recording = { when: Date; @@ -112,7 +112,6 @@ export class Session { private _lastInput: SessionPrompt | undefined; private _lastExpansionState: ExpansionState | undefined; - private _lastTextModelChanges: readonly DetailedLineRangeMapping[] | undefined; private _isUnstashed: boolean = false; private readonly _exchange: SessionExchange[] = []; private readonly _startTime = new Date(); @@ -187,26 +186,18 @@ export class Session { return this._exchange[this._exchange.length - 1]; } - get lastTextModelChanges() { - return this._lastTextModelChanges ?? []; - } - - set lastTextModelChanges(changes: readonly DetailedLineRangeMapping[]) { - this._lastTextModelChanges = changes; - } - get hasChangedText(): boolean { return !this.textModel0.equalsTextBuffer(this.textModelN.getTextBuffer()); } - asChangedText(): string | undefined { - if (!this._lastTextModelChanges || this._lastTextModelChanges.length === 0) { + asChangedText(changes: readonly LineRangeMapping[]): string | undefined { + if (changes.length === 0) { return undefined; } let startLine = Number.MAX_VALUE; let endLine = Number.MIN_VALUE; - for (const change of this._lastTextModelChanges) { + for (const change of changes) { startLine = Math.min(startLine, change.modified.startLineNumber); endLine = Math.max(endLine, change.modified.endLineNumberExclusive); } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 4fa8470f957..9821f36e6a3 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -12,7 +12,7 @@ import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; -import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; +import { DetailedLineRangeMapping, LineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon'; import { TextEdit } from 'vs/editor/common/languages'; import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model'; @@ -133,7 +133,7 @@ export class PreviewStrategy extends EditModeStrategy { override async renderChanges(response: EditResponse): Promise { if (response.allLocalEdits.length > 0) { const allEditOperation = response.allLocalEdits.map(edits => edits.map(TextEdit.asEditOperation)); - this._widget.showEditsPreview(this._session.textModel0, allEditOperation, this._session.lastTextModelChanges); + await this._widget.showEditsPreview(this._session.textModel0, this._session.textModelN, allEditOperation); } else { this._widget.hideEditsPreview(); } @@ -327,9 +327,9 @@ export class LiveStrategy extends EditModeStrategy { } override async renderChanges(response: EditResponse) { - + const diff = await this._editorWorkerService.computeDiff(this._session.textModel0.uri, this._session.textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced'); + this._updateSummaryMessage(diff?.changes ?? []); this._inlineDiffDecorations.update(); - this._updateSummaryMessage(); if (response.singleCreateFileEdit) { this._widget.showCreatePreview(response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits)); @@ -344,9 +344,9 @@ export class LiveStrategy extends EditModeStrategy { } } - protected _updateSummaryMessage() { + protected _updateSummaryMessage(mappings: readonly LineRangeMapping[]) { let linesChanged = 0; - for (const change of this._session.lastTextModelChanges) { + for (const change of mappings) { linesChanged += change.changedLineCount; } let message: string; @@ -440,6 +440,7 @@ export class LivePreviewStrategy extends LiveStrategy { return; } + this._updateSummaryMessage(diff.changes); this._currentLineRangeGroups = groups; const handleDiff = () => { @@ -465,7 +466,6 @@ export class LivePreviewStrategy extends LiveStrategy { override async renderChanges(response: EditResponse) { - this._updateSummaryMessage(); await this._renderDiffZones(); if (response.singleCreateFileEdit) { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index db86fea8ea0..a4223bb8d8d 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -36,7 +36,6 @@ import { FileKind } from 'vs/platform/files/common/files'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { LanguageSelector } from 'vs/editor/common/languageSelector'; import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; -import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { invertLineRange, lineRangeAsRange } from 'vs/workbench/contrib/inlineChat/browser/utils'; import { ICodeEditorViewState, ScrollType } from 'vs/editor/common/editorCommon'; import { LineRange } from 'vs/editor/common/core/lineRange'; @@ -62,6 +61,7 @@ import { MenuId } from 'vs/platform/actions/common/actions'; import { editorForeground, inputBackground, editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { CodeBlockPart } from 'vs/workbench/contrib/chat/browser/codeBlockPart'; import { Lazy } from 'vs/base/common/lazy'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; const defaultAriaLabel = localize('aria-label', "Inline Chat Input"); @@ -215,7 +215,8 @@ export class InlineChatWidget { @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, - @IAccessibleViewService private readonly _accessibleViewService: IAccessibleViewService + @IAccessibleViewService private readonly _accessibleViewService: IAccessibleViewService, + @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService ) { // input editor logic @@ -664,27 +665,29 @@ export class InlineChatWidget { // --- preview - showEditsPreview(textModelv0: ITextModel, allEdits: ISingleEditOperation[][], changes: readonly DetailedLineRangeMapping[]) { - if (changes.length === 0) { + async showEditsPreview(textModel0: ITextModel, textModelN: ITextModel, allEdits: ISingleEditOperation[][]) { + + const diff = await this._editorWorkerService.computeDiff(textModel0.uri, textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced'); + if (!diff || diff.changes.length === 0) { this.hideEditsPreview(); return; } this._elements.previewDiff.classList.remove('hidden'); - const languageSelection: ILanguageSelection = { languageId: textModelv0.getLanguageId(), onDidChange: Event.None }; - const modified = this._modelService.createModel(createTextBufferFactoryFromSnapshot(textModelv0.createSnapshot()), languageSelection, undefined, true); + const languageSelection: ILanguageSelection = { languageId: textModel0.getLanguageId(), onDidChange: Event.None }; + const modified = this._modelService.createModel(createTextBufferFactoryFromSnapshot(textModel0.createSnapshot()), languageSelection, undefined, true); for (const edits of allEdits) { modified.applyEdits(edits, false); } - this._previewDiffEditor.value.setModel({ original: textModelv0, modified }); + this._previewDiffEditor.value.setModel({ original: textModel0, modified }); // joined ranges - let originalLineRange = changes[0].original; - let modifiedLineRange = changes[0].modified; - for (let i = 1; i < changes.length; i++) { - originalLineRange = originalLineRange.join(changes[i].original); - modifiedLineRange = modifiedLineRange.join(changes[i].modified); + let originalLineRange = diff.changes[0].original; + let modifiedLineRange = diff.changes[0].modified; + for (let i = 1; i < diff.changes.length; i++) { + originalLineRange = originalLineRange.join(diff.changes[i].original); + modifiedLineRange = modifiedLineRange.join(diff.changes[i].modified); } // apply extra padding @@ -695,10 +698,10 @@ export class InlineChatWidget { const newEndLineModified = Math.min(modifiedLineRange.endLineNumberExclusive + pad, modified.getLineCount()); modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber, newEndLineModified); - const newEndLineOriginal = Math.min(originalLineRange.endLineNumberExclusive + pad, textModelv0.getLineCount()); + const newEndLineOriginal = Math.min(originalLineRange.endLineNumberExclusive + pad, textModel0.getLineCount()); originalLineRange = new LineRange(originalLineRange.startLineNumber, newEndLineOriginal); - const hiddenOriginal = invertLineRange(originalLineRange, textModelv0); + const hiddenOriginal = invertLineRange(originalLineRange, textModel0); const hiddenModified = invertLineRange(modifiedLineRange, modified); this._previewDiffEditor.value.getOriginalEditor().setHiddenAreas(hiddenOriginal.map(lineRangeAsRange), 'diff-hidden'); this._previewDiffEditor.value.getModifiedEditor().setHiddenAreas(hiddenModified.map(lineRangeAsRange), 'diff-hidden'); diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts index bb25fb4e308..822c5f8064c 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts @@ -173,7 +173,7 @@ suite('InteractiveChatController', function () { const run = ctrl.run({ message: 'Hello', autoSend: true }); await p; assert.ok(ctrl.getWidgetPosition() !== undefined); - ctrl.cancelSession(); + await ctrl.cancelSession(); await run; @@ -205,7 +205,7 @@ suite('InteractiveChatController', function () { assert.ok(session); assert.deepStrictEqual(session.wholeRange.value, new Range(1, 1, 1, 6)); - ctrl.cancelSession(); + await ctrl.cancelSession(); d.dispose(); }); @@ -235,7 +235,7 @@ suite('InteractiveChatController', function () { assert.ok(session); assert.deepStrictEqual(session.wholeRange.value, new Range(1, 1, 1, 6)); - ctrl.cancelSession(); + await ctrl.cancelSession(); d.dispose(); }); @@ -298,7 +298,7 @@ suite('InteractiveChatController', function () { assert.deepStrictEqual(session.wholeRange.value, new Range(1, 1, 4, 12)); - ctrl.cancelSession(); + await ctrl.cancelSession(); await r; }); From 6fa270070d87361f903214b131239bc2d499a4bb Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 18 Oct 2023 12:24:02 +0200 Subject: [PATCH 226/290] fix final edit --- .../contrib/inlineChat/browser/inlineChatController.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 5ca18ef7a67..1ec6178f510 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -591,8 +591,7 @@ export class InlineChatController implements IEditorContribution { response = new MarkdownResponse(this._activeSession.textModelN.uri, reply); } else if (reply) { const editResponse = new EditResponse(this._activeSession.textModelN.uri, this._activeSession.textModelN.getAlternativeVersionId(), reply, progressEdits); - const offset = editResponse.allLocalEdits.length - progressEdits.length; - for (let i = offset; i < editResponse.allLocalEdits.length; i++) { + for (let i = progressEdits.length; i < editResponse.allLocalEdits.length; i++) { await this._makeChanges(editResponse.allLocalEdits[i], true); } response = editResponse; From cdc2850a7292dbfe4004c02f2de7f40f0c5807d1 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Oct 2023 12:29:25 +0200 Subject: [PATCH 227/290] polish badge (#195890) --- src/vs/workbench/browser/parts/media/paneCompositePart.css | 4 ++-- .../workbench/browser/parts/titlebar/media/titlebarpart.css | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/media/paneCompositePart.css b/src/vs/workbench/browser/parts/media/paneCompositePart.css index 0006a43986d..b30eba09a97 100644 --- a/src/vs/workbench/browser/parts/media/paneCompositePart.css +++ b/src/vs/workbench/browser/parts/media/paneCompositePart.css @@ -172,12 +172,12 @@ .monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; - top: 11px; + top: 12px; right: 0px; font-size: 9px; font-weight: 600; min-width: 12px; - height: 12px; + height: 11px; padding: 0 2px; border-radius: 16px; text-align: center; diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 5109fdeaf92..a9f73b33351 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -444,12 +444,12 @@ .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; - top: 10px; + top: 11px; right: 0px; font-size: 9px; font-weight: 600; min-width: 12px; - height: 12px; + height: 11px; padding: 0 2px; border-radius: 16px; text-align: center; From e240d95168b8ec29a4deaf096aca1ad86d612fe6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2023 12:40:26 +0200 Subject: [PATCH 228/290] windows - add and use `IBaseWindow` (#195896) --- src/vs/platform/window/electron-main/window.ts | 7 +++++-- src/vs/platform/windows/electron-main/windowImpl.ts | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/window/electron-main/window.ts b/src/vs/platform/window/electron-main/window.ts index 8330d6f39a5..379bdd161f6 100644 --- a/src/vs/platform/window/electron-main/window.ts +++ b/src/vs/platform/window/electron-main/window.ts @@ -13,7 +13,11 @@ import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataPro import { INativeWindowConfiguration } from 'vs/platform/window/common/window'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; -export interface ICodeWindow extends IDisposable { +export interface IBaseWindow extends IDisposable { + focus(options?: { force: boolean }): void; +} + +export interface ICodeWindow extends IBaseWindow { readonly onWillLoad: Event; readonly onDidSignalReady: Event; @@ -49,7 +53,6 @@ export interface ICodeWindow extends IDisposable { load(config: INativeWindowConfiguration, options?: { isReload?: boolean }): void; reload(cli?: NativeParsedArgs): void; - focus(options?: { force: boolean }): void; close(): void; getBounds(): Rectangle; diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index da1c92d03b6..32168a31b7e 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -35,7 +35,7 @@ import { getMenuBarVisibility, getTitleBarStyle, IFolderToOpen, INativeWindowCon import { defaultBrowserWindowOptions, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; -import { IWindowState, ICodeWindow, ILoadEvent, WindowMode, WindowError, LoadReason, defaultWindowState } from 'vs/platform/window/electron-main/window'; +import { IWindowState, ICodeWindow, ILoadEvent, WindowMode, WindowError, LoadReason, defaultWindowState, IBaseWindow } from 'vs/platform/window/electron-main/window'; import { Color } from 'vs/base/common/color'; import { IPolicyService } from 'vs/platform/policy/common/policy'; import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; @@ -82,7 +82,7 @@ const enum ReadyState { READY } -export abstract class BaseWindow extends Disposable { +export abstract class BaseWindow extends Disposable implements IBaseWindow { protected abstract getWin(): BrowserWindow | null; From a61980d2b033ab0185471c74cc062c580c82d296 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 18 Oct 2023 14:38:46 +0200 Subject: [PATCH 229/290] - always use `computeMoreMinimalEdits` to reduce flicker for empty edits - don't use automatic inline diff'ing for predictable heights - fix widget positioning off by one --- .../contrib/inlineChat/browser/inlineChatController.ts | 9 +++++++-- .../inlineChat/browser/inlineChatLivePreviewWidget.ts | 1 + .../contrib/inlineChat/browser/inlineChatStrategies.ts | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 1ec6178f510..bb504a95533 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -569,7 +569,7 @@ export class InlineChatController implements IEditorContribution { throw new Error('Progress in NOT supported in non-live mode'); } progressEdits.push(data.edits); - await this._makeChanges(data.edits, false); + await this._makeChanges(data.edits, true); await this._strategy?.renderProgressChanges(); } }); @@ -650,10 +650,15 @@ export class InlineChatController implements IEditorContribution { assertType(this._strategy); // make changes from modelN -> modelN+1 - const moreMinimalEdits = computeMoreMinimalEdits ? await this._editorWorkerService.computeHumanReadableDiff(this._activeSession.textModelN.uri, lastEdits) : undefined; + const moreMinimalEdits = computeMoreMinimalEdits ? await this._editorWorkerService.computeMoreMinimalEdits(this._activeSession.textModelN.uri, lastEdits) : undefined; const editOperations = (moreMinimalEdits ?? lastEdits).map(TextEdit.asEditOperation); this._log('edits from PROVIDER and after making them MORE MINIMAL', this._activeSession.provider.debugName, lastEdits, moreMinimalEdits); + if (editOperations.length === 0) { + // nothing left to do + return; + } + try { this._ignoreModelContentChanged = true; this._activeSession.wholeRange.trackEdits(editOperations); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index 11b1281498c..005d0216fb0 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -80,6 +80,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { stickyScroll: { enabled: false }, minimap: { enabled: false }, isInEmbeddedEditor: true, + useInlineViewWhenSpaceIsLimited: false, overflowWidgetsDomNode: editor.getOverflowWidgetsDomNode(), onlyShowAccessibleDiffViewer: this.accessibilityService.isScreenReaderOptimized(), }, { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 9821f36e6a3..d47b03f78c1 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -484,7 +484,7 @@ export class LivePreviewStrategy extends LiveStrategy { const zone = this._diffZonePool[i]; if (zone.isVisible && zone.position) { // above last view zone - return zone.position.delta(-1); + return zone.position; } } return undefined; From 45dda0e1daab6dc9d84ea210b29e9142dca37d4f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Oct 2023 14:42:02 +0200 Subject: [PATCH 230/290] debt - remove old style voice transcriber (#195883) --- build/gulpfile.vscode.js | 1 - build/lib/i18n.resources.json | 4 - src/vs/code/electron-main/app.ts | 12 - .../sharedProcess/contrib/voiceTranscriber.ts | 212 ------------------ .../node/sharedProcess/sharedProcessMain.ts | 8 +- .../electron-main/sharedProcess.ts | 7 +- .../node/voiceRecognitionService.ts | 81 ------- .../voiceTranscriptionWorklet.ts | 127 ----------- .../workbenchVoiceRecognitionService.ts | 208 ----------------- src/vs/workbench/workbench.desktop.main.ts | 1 - 10 files changed, 3 insertions(+), 658 deletions(-) delete mode 100644 src/vs/code/node/sharedProcess/contrib/voiceTranscriber.ts delete mode 100644 src/vs/platform/voiceRecognition/node/voiceRecognitionService.ts delete mode 100644 src/vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.ts delete mode 100644 src/vs/workbench/services/voiceRecognition/electron-sandbox/workbenchVoiceRecognitionService.ts diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 2d2451c28e8..4ae98a95577 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -73,7 +73,6 @@ const vscodeResources = [ 'out-build/vs/workbench/contrib/terminal/browser/media/*.sh', 'out-build/vs/workbench/contrib/terminal/browser/media/*.zsh', 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', - 'out-build/vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.js', 'out-build/vs/**/markdown.css', 'out-build/vs/workbench/contrib/tasks/**/*.json', '!**/test/**' diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 2d03fbd5712..65f37d5e283 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -82,10 +82,6 @@ "name": "vs/workbench/services/assignment", "project": "vscode-workbench" }, - { - "name": "vs/workbench/services/voiceRecognition", - "project": "vscode-workbench" - }, { "name": "vs/workbench/contrib/extensions", "project": "vscode-workbench" diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index fb758311a1a..147ea68d2ab 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -165,10 +165,6 @@ export class CodeApplication extends Disposable { const isUrlFromWebview = (requestingUrl: string | undefined) => requestingUrl?.startsWith(`${Schemas.vscodeWebview}://`); - const allowedPermissionsInMainFrame = new Set( - this.productService.quality === 'stable' ? [] : ['media'] - ); - const allowedPermissionsInWebview = new Set([ 'clipboard-read', 'clipboard-sanitized-write', @@ -179,10 +175,6 @@ export class CodeApplication extends Disposable { return callback(allowedPermissionsInWebview.has(permission)); } - if (details.isMainFrame && details.securityOrigin === `${Schemas.vscodeFileResource}://${VSCODE_AUTHORITY}/`) { - return callback(allowedPermissionsInMainFrame.has(permission)); - } - return callback(false); }); @@ -191,10 +183,6 @@ export class CodeApplication extends Disposable { return allowedPermissionsInWebview.has(permission); } - if (details.isMainFrame && details.securityOrigin === `${Schemas.vscodeFileResource}://${VSCODE_AUTHORITY}/`) { - return allowedPermissionsInMainFrame.has(permission); - } - return false; }); diff --git a/src/vs/code/node/sharedProcess/contrib/voiceTranscriber.ts b/src/vs/code/node/sharedProcess/contrib/voiceTranscriber.ts deleted file mode 100644 index 6f29b8d3a23..00000000000 --- a/src/vs/code/node/sharedProcess/contrib/voiceTranscriber.ts +++ /dev/null @@ -1,212 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event } from 'vs/base/common/event'; -import { MessagePortMain, MessageEvent } from 'vs/base/parts/sandbox/node/electronTypes'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { IVoiceRecognitionService } from 'vs/platform/voiceRecognition/node/voiceRecognitionService'; -import { ILogService } from 'vs/platform/log/common/log'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { LimitedQueue, Queue } from 'vs/base/common/async'; - -export class VoiceTranscriptionManager extends Disposable { - - private static USE_SLIDING_WINDOW = !!process.env.VSCODE_VOICE_USE_SLIDING_WINDOW; - - constructor( - private readonly onDidWindowConnectRaw: Event, - @IVoiceRecognitionService private readonly voiceRecognitionService: IVoiceRecognitionService, - @ILogService private readonly logService: ILogService - ) { - super(); - - this.registerListeners(); - } - - private registerListeners(): void { - this._register(this.onDidWindowConnectRaw(port => { - this.logService.info(`[voice] transcriber: new connection (sliding window: ${VoiceTranscriptionManager.USE_SLIDING_WINDOW})`); - - if (VoiceTranscriptionManager.USE_SLIDING_WINDOW) { - this._register(new SlidingWindowVoiceTranscriber(port, this.voiceRecognitionService, this.logService)); - } else { - this._register(new FullWindowVoiceTranscriber(port, this.voiceRecognitionService, this.logService)); - } - })); - } -} - -abstract class VoiceTranscriber extends Disposable { - - protected static MAX_DATA_LENGTH = 30 /* seconds */ * 16000 /* sampling rate */ * 16 /* bith depth */ * 1 /* channels */ / 8; - - constructor( - protected readonly port: MessagePortMain, - protected readonly voiceRecognitionService: IVoiceRecognitionService, - protected readonly logService: ILogService - ) { - super(); - - this.registerListeners(); - } - - private registerListeners(): void { - const cts = new CancellationTokenSource(); - this._register(toDisposable(() => cts.dispose(true))); - - const requestHandler = (e: MessageEvent) => { - if (!(e.data instanceof Float32Array)) { - return; - } - - this.handleRequest(e.data, cts.token); - }; - this.port.on('message', requestHandler); - this._register(toDisposable(() => this.port.off('message', requestHandler))); - - this.port.start(); - - let closed = false; - this.port.on('close', () => { - this.logService.info(`[voice] transcriber: closed connection`); - - closed = true; - this.dispose(); - }); - - this._register(toDisposable(() => { - if (!closed) { - this.port.close(); - } - })); - } - - protected abstract handleRequest(data: Float32Array, cancellation: CancellationToken): Promise; - - protected joinFloat32Arrays(float32Arrays: Float32Array[]): Float32Array { - const result = new Float32Array(float32Arrays.reduce((prev, curr) => prev + curr.length, 0)); - - let offset = 0; - for (const float32Array of float32Arrays) { - result.set(float32Array, offset); - offset += float32Array.length; - } - - return result; - } -} - -class SlidingWindowVoiceTranscriber extends VoiceTranscriber { - - private readonly transcriptionQueue = this._register(new Queue()); - - private transcribedResults: string[] = []; - private data: Float32Array = new Float32Array(0); - - protected async handleRequest(data: Float32Array, cancellation: CancellationToken): Promise { - if (data.length > 0) { - this.logService.info(`[voice] transcriber: voice detected, storing in buffer`); - - this.data = this.data ? this.joinFloat32Arrays([this.data, data]) : data; - } else { - this.logService.info(`[voice] transcriber: silence detected, transcribing window...`); - - const data = this.data.slice(0); - this.data = new Float32Array(0); - - this.transcriptionQueue.queue(() => this.transcribe(data, cancellation)); - } - } - - private async transcribe(data: Float32Array, cancellation: CancellationToken): Promise { - if (cancellation.isCancellationRequested) { - return; - } - - if (data.length > VoiceTranscriber.MAX_DATA_LENGTH) { - this.logService.warn(`[voice] transcriber: refusing to accept more than 30s of audio data`); - return; - } - - if (data.length !== 0) { - const result = await this.voiceRecognitionService.transcribe(data, cancellation); - if (result) { - this.transcribedResults.push(result); - } - } - - if (cancellation.isCancellationRequested) { - return; - } - - this.port.postMessage(this.transcribedResults.join(' ')); - } - - override dispose(): void { - super.dispose(); - - this.data = new Float32Array(0); - } -} - -class FullWindowVoiceTranscriber extends VoiceTranscriber { - - private readonly transcriptionQueue = new LimitedQueue(); - - private data: Float32Array | undefined = undefined; - - private transcribedDataLength = 0; - private transcribedResult = ''; - - protected async handleRequest(data: Float32Array, cancellation: CancellationToken): Promise { - const dataCandidate = this.data ? this.joinFloat32Arrays([this.data, data]) : data; - if (dataCandidate.length > VoiceTranscriber.MAX_DATA_LENGTH) { - this.logService.warn(`[voice] transcriber: refusing to accept more than 30s of audio data`); - return; - } - - this.data = dataCandidate; - - this.transcriptionQueue.queue(() => this.transcribe(cancellation)); - } - - private async transcribe(cancellation: CancellationToken): Promise { - if (cancellation.isCancellationRequested) { - return; - } - - const data = this.data?.slice(0); - if (!data) { - return; - } - - let result: string; - if (data.length === this.transcribedDataLength) { - // Optimization: if the data is the same as the last time - // we transcribed, don't transcribe again, just return the - // same result as we had last time. - this.logService.info(`[voice] transcriber: silence detected, reusing previous transcription result`); - result = this.transcribedResult; - } else { - this.logService.info(`[voice] transcriber: voice detected, transcribing everything...`); - result = await this.voiceRecognitionService.transcribe(data, cancellation); - } - - this.transcribedResult = result; - this.transcribedDataLength = data.length; - - if (cancellation.isCancellationRequested) { - return; - } - - this.port.postMessage(result); - } - - override dispose(): void { - super.dispose(); - - this.data = undefined; - } -} diff --git a/src/vs/code/node/sharedProcess/sharedProcessMain.ts b/src/vs/code/node/sharedProcess/sharedProcessMain.ts index 557f8b6a6fe..84d080486a3 100644 --- a/src/vs/code/node/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/node/sharedProcess/sharedProcessMain.ts @@ -114,8 +114,6 @@ import { IRemoteSocketFactoryService, RemoteSocketFactoryService } from 'vs/plat import { RemoteConnectionType } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { IVoiceRecognitionService, VoiceRecognitionService } from 'vs/platform/voiceRecognition/node/voiceRecognitionService'; -import { VoiceTranscriptionManager } from 'vs/code/node/sharedProcess/contrib/voiceTranscriber'; import { SharedProcessRawConnection, SharedProcessLifecycle } from 'vs/platform/sharedProcess/common/sharedProcess'; class SharedProcessMain extends Disposable implements IClientConnectionFilter { @@ -183,8 +181,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { instantiationService.createInstance(LogsDataCleaner), instantiationService.createInstance(LocalizationsUpdater), instantiationService.createInstance(ExtensionsContributions), - instantiationService.createInstance(UserDataProfilesCleaner), - instantiationService.createInstance(VoiceTranscriptionManager, this.onDidWindowConnectRaw.event) + instantiationService.createInstance(UserDataProfilesCleaner) )); } @@ -367,9 +364,6 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { // Remote Tunnel services.set(IRemoteTunnelService, new SyncDescriptor(RemoteTunnelService)); - // Voice Recognition - services.set(IVoiceRecognitionService, new SyncDescriptor(VoiceRecognitionService)); - return new InstantiationService(services); } diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 7372f366459..66defd005d1 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -19,7 +19,6 @@ import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtil import { parseSharedProcessDebugPort } from 'vs/platform/environment/node/environmentService'; import { assertIsDefined } from 'vs/base/common/types'; import { SharedProcessChannelConnection, SharedProcessRawConnection, SharedProcessLifecycle } from 'vs/platform/sharedProcess/common/sharedProcess'; -import { IProductService } from 'vs/platform/product/common/productService'; export class SharedProcess extends Disposable { @@ -35,8 +34,7 @@ export class SharedProcess extends Disposable { @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @ILogService private readonly logService: ILogService, @ILoggerMainService private readonly loggerMainService: ILoggerMainService, - @IPolicyService private readonly policyService: IPolicyService, - @IProductService private readonly productService: IProductService + @IPolicyService private readonly policyService: IPolicyService ) { super(); @@ -165,8 +163,7 @@ export class SharedProcess extends Disposable { type: 'shared-process', entryPoint: 'vs/code/node/sharedProcess/sharedProcessMain', payload: this.createSharedProcessConfiguration(), - execArgv, - allowLoadingUnsignedLibraries: !!process.env.VSCODE_VOICE_MODULE_PATH && this.productService.quality !== 'stable' // TODO@bpasero package + execArgv }); } diff --git a/src/vs/platform/voiceRecognition/node/voiceRecognitionService.ts b/src/vs/platform/voiceRecognition/node/voiceRecognitionService.ts deleted file mode 100644 index 03f7a16ca95..00000000000 --- a/src/vs/platform/voiceRecognition/node/voiceRecognitionService.ts +++ /dev/null @@ -1,81 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { CancellationToken } from 'vs/base/common/cancellation'; -import { ILogService } from 'vs/platform/log/common/log'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IProductService } from 'vs/platform/product/common/productService'; - -export const IVoiceRecognitionService = createDecorator('voiceRecognitionService'); - -export interface IVoiceRecognitionService { - - readonly _serviceBrand: undefined; - - /** - * Given a buffer of audio data, attempts to - * transcribe the spoken words into text. - * - * @param channelData the raw audio data obtained - * from the microphone as uncompressed PCM data: - * - 1 channel (mono) - * - 16khz sampling rate - * - 16bit sample size - */ - transcribe(channelData: Float32Array, cancellation: CancellationToken): Promise; -} - -export class VoiceRecognitionService implements IVoiceRecognitionService { - - declare readonly _serviceBrand: undefined; - - constructor( - @ILogService private readonly logService: ILogService, - @IProductService private readonly productService: IProductService - ) { } - - async transcribe(channelData: Float32Array, cancellation: CancellationToken): Promise { - const modulePath = process.env.VSCODE_VOICE_MODULE_PATH; // TODO@bpasero package - if (!modulePath || this.productService.quality === 'stable') { - this.logService.error(`[voice] transcribe(${channelData.length}): Voice recognition not yet supported`); - throw new Error('Voice recognition not yet supported!'); - } - - const now = Date.now(); - - try { - const voiceModule: { - transcribe: ( - audioBuffer: { channelCount: 1; samplingRate: 16000; bitDepth: 16; channelData: Float32Array }, - options: { - language: string | 'auto'; - signal: AbortSignal; - } - ) => Promise; - } = require.__$__nodeRequire(modulePath); - - const abortController = new AbortController(); - cancellation.onCancellationRequested(() => abortController.abort()); - - const text = await voiceModule.transcribe({ - samplingRate: 16000, - bitDepth: 16, - channelCount: 1, - channelData - }, { - language: 'en', - signal: abortController.signal - }); - - this.logService.info(`[voice] transcribe(${channelData.length}): Text "${text}", took ${Date.now() - now}ms)`); - - return text; - } catch (error) { - this.logService.error(`[voice] transcribe(${channelData.length}): Failed width "${error}", took ${Date.now() - now}ms)`); - - throw error; - } - } -} diff --git a/src/vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.ts b/src/vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.ts deleted file mode 100644 index cb0083c81eb..00000000000 --- a/src/vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.ts +++ /dev/null @@ -1,127 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare class AudioWorkletProcessor { - - readonly port: MessagePort; - - process(inputs: [Float32Array[]], outputs: [Float32Array[]]): boolean; -} - -interface IVoiceTranscriptionWorkletOptions extends AudioWorkletNodeOptions { - processorOptions: { - readonly bufferTimespan: number; - readonly vadThreshold: number; - }; -} - -class VoiceTranscriptionWorklet extends AudioWorkletProcessor { - - private startTime: number | undefined = undefined; - private stopped: boolean = false; - - private buffer: Float32Array[] = []; - - private sharedProcessConnection: MessagePort | undefined = undefined; - - constructor(private readonly options: IVoiceTranscriptionWorkletOptions) { - super(); - - this.registerListeners(); - } - - private registerListeners() { - this.port.onmessage = event => { - switch (event.data) { - case 'vscode:startVoiceTranscription': { - this.sharedProcessConnection = event.ports[0]; - - this.sharedProcessConnection.onmessage = event => { - if (this.stopped) { - return; - } - - if (typeof event.data === 'string') { - this.port.postMessage(event.data); - } - }; - - this.sharedProcessConnection.start(); - break; - } - - case 'vscode:stopVoiceTranscription': { - this.stopped = true; - - this.sharedProcessConnection?.close(); - this.sharedProcessConnection = undefined; - - break; - } - } - }; - } - - override process(inputs: [Float32Array[]]): boolean { - if (this.startTime === undefined) { - this.startTime = Date.now(); - } - - const inputChannelData = inputs[0][0]; - if ((!(inputChannelData instanceof Float32Array))) { - return !this.stopped; - } - - this.buffer.push(inputChannelData.slice(0)); - - if (Date.now() - this.startTime > this.options.processorOptions.bufferTimespan && this.sharedProcessConnection) { - const buffer = this.joinFloat32Arrays(this.buffer); - this.buffer = []; - - // Send buffer to shared process for transcription. - // Send an empty buffer if it appears to be silence - // so that we can still trigger the transcription - // service and let it know about this. - - this.sharedProcessConnection.postMessage(this.appearsToBeSilence(buffer) ? new Float32Array(0) : buffer); - - this.startTime = Date.now(); - } - - return !this.stopped; - } - - private appearsToBeSilence(data: Float32Array): boolean { - - // This is the most simple Voice Activity Detection (VAD) - // and it is based on the Root Mean Square (RMS) of the signal - // with a certain threshold. Good for testing but probably - // not suitable for shipping to stable (TODO@bpasero). - - let sum = 0; - for (let i = 0; i < data.length; i++) { - sum += data[i] * data[i]; - } - - const rms = Math.sqrt(sum / data.length); - - return rms < this.options.processorOptions.vadThreshold; - } - - private joinFloat32Arrays(float32Arrays: Float32Array[]): Float32Array { - const result = new Float32Array(float32Arrays.reduce((prev, curr) => prev + curr.length, 0)); - - let offset = 0; - for (const float32Array of float32Arrays) { - result.set(float32Array, offset); - offset += float32Array.length; - } - - return result; - } -} - -// @ts-ignore -registerProcessor('voice-transcription-worklet', VoiceTranscriptionWorklet); diff --git a/src/vs/workbench/services/voiceRecognition/electron-sandbox/workbenchVoiceRecognitionService.ts b/src/vs/workbench/services/voiceRecognition/electron-sandbox/workbenchVoiceRecognitionService.ts deleted file mode 100644 index 0f279ac26ea..00000000000 --- a/src/vs/workbench/services/voiceRecognition/electron-sandbox/workbenchVoiceRecognitionService.ts +++ /dev/null @@ -1,208 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { localize } from 'vs/nls'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Emitter, Event } from 'vs/base/common/event'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; -import { DeferredPromise } from 'vs/base/common/async'; -import { FileAccess } from 'vs/base/common/network'; -import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; -import { INotificationService } from 'vs/platform/notification/common/notification'; - -export const IWorkbenchVoiceRecognitionService = createDecorator('workbenchVoiceRecognitionService'); - -export interface IWorkbenchVoiceRecognitionOptions { - - /** - * Optional event that is fired when the user cancels the voice recognition. - */ - readonly onDidCancel?: () => void; -} - -export interface IWorkbenchVoiceRecognitionService { - - readonly _serviceBrand: undefined; - - /** - * Starts listening to the microphone transcribing the voice to text. Microphone - * recording starts when the returned promise is resolved. - * - * @param cancellation a cancellation token to stop transcribing and - * listening to the microphone. - */ - transcribe(cancellation: CancellationToken, options?: IWorkbenchVoiceRecognitionOptions): Promise>; -} - -interface IVoiceTranscriptionWorkletOptions extends AudioWorkletNodeOptions { - processorOptions: { - readonly bufferTimespan: number; - readonly vadThreshold: number; - }; -} - -class VoiceTranscriptionWorkletNode extends AudioWorkletNode { - - constructor( - context: BaseAudioContext, - options: IVoiceTranscriptionWorkletOptions, - private readonly onDidTranscribe: Emitter, - private readonly sharedProcessService: ISharedProcessService - ) { - super(context, 'voice-transcription-worklet', options); - - this.registerListeners(); - } - - private registerListeners(): void { - this.port.onmessage = e => { - if (typeof e.data === 'string') { - this.onDidTranscribe.fire(e.data); - } - }; - } - - async start(token: CancellationToken): Promise { - token.onCancellationRequested(() => this.stop()); - - const sharedProcessConnection = await this.sharedProcessService.createRawConnection(); - - if (token.isCancellationRequested) { - this.stop(); - return; - } - - this.port.postMessage('vscode:startVoiceTranscription', [sharedProcessConnection]); - } - - private stop(): void { - this.port.postMessage('vscode:stopVoiceTranscription'); - this.disconnect(); - } -} - -export class WorkbenchVoiceRecognitionService implements IWorkbenchVoiceRecognitionService { - - declare readonly _serviceBrand: undefined; - - private static readonly AUDIO_SAMPLING_RATE = 16000; - private static readonly AUDIO_BIT_DEPTH = 16; - private static readonly AUDIO_CHANNELS = 1; - - private static readonly BUFFER_TIMESPAN = 1000; - private static readonly VAD_THRESHOLD = 0.02; - - constructor( - @IProgressService private readonly progressService: IProgressService, - @ISharedProcessService private readonly sharedProcessService: ISharedProcessService, - @INotificationService private readonly notificationService: INotificationService - ) { } - - async transcribe(cancellation: CancellationToken, options?: IWorkbenchVoiceRecognitionOptions): Promise> { - const cts = new CancellationTokenSource(cancellation); - - const onDidTranscribe = new Emitter(); - cts.token.onCancellationRequested(() => { - onDidTranscribe.dispose(); - options?.onDidCancel?.(); - }); - - await this.doTranscribe(onDidTranscribe, cts); - - return onDidTranscribe.event; - } - - private doTranscribe(onDidTranscribe: Emitter, cts: CancellationTokenSource): Promise { - const recordingReady = new DeferredPromise(); - cts.token.onCancellationRequested(() => recordingReady.complete()); - - this.progressService.withProgress({ - location: ProgressLocation.Window, - title: localize('voiceTranscription', "Voice Transcription"), - cancellable: true - }, async progress => { - const recordingDone = new DeferredPromise(); - try { - progress.report({ message: localize('voiceTranscriptionGettingReady', "Getting microphone ready...") }); - - const microphoneDevice = await navigator.mediaDevices.getUserMedia({ - audio: { - sampleRate: WorkbenchVoiceRecognitionService.AUDIO_SAMPLING_RATE, - sampleSize: WorkbenchVoiceRecognitionService.AUDIO_BIT_DEPTH, - channelCount: WorkbenchVoiceRecognitionService.AUDIO_CHANNELS, - autoGainControl: true, - noiseSuppression: true, - echoCancellation: false - } - }); - - if (cts.token.isCancellationRequested) { - return; - } - - const audioContext = new AudioContext({ - sampleRate: WorkbenchVoiceRecognitionService.AUDIO_SAMPLING_RATE, - latencyHint: 'interactive' - }); - - const microphoneSource = audioContext.createMediaStreamSource(microphoneDevice); - - cts.token.onCancellationRequested(() => { - try { - for (const track of microphoneDevice.getTracks()) { - track.stop(); - } - - microphoneSource.disconnect(); - audioContext.close(); - } finally { - recordingDone.complete(); - } - }); - - await audioContext.audioWorklet.addModule(FileAccess.asBrowserUri('vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.js').toString(true)); - - if (cts.token.isCancellationRequested) { - return; - } - - const voiceTranscriptionTarget = new VoiceTranscriptionWorkletNode(audioContext, { - channelCount: WorkbenchVoiceRecognitionService.AUDIO_CHANNELS, - channelCountMode: 'explicit', - processorOptions: { - bufferTimespan: WorkbenchVoiceRecognitionService.BUFFER_TIMESPAN, - vadThreshold: WorkbenchVoiceRecognitionService.VAD_THRESHOLD - } - }, onDidTranscribe, this.sharedProcessService); - await voiceTranscriptionTarget.start(cts.token); - - if (cts.token.isCancellationRequested) { - return; - } - - microphoneSource.connect(voiceTranscriptionTarget); - - progress.report({ message: localize('voiceTranscriptionRecording', "Recording from microphone...") }); - recordingReady.complete(); - - return recordingDone.p; - } catch (error) { - this.notificationService.error(localize('voiceTranscriptionError', "Voice transcription failed: {0}", error.message)); - - recordingReady.error(error); - recordingDone.error(error); - } - }, () => { - cts.cancel(); - }); - - return recordingReady.p; - } -} - -// Register Service -registerSingleton(IWorkbenchVoiceRecognitionService, WorkbenchVoiceRecognitionService, InstantiationType.Delayed); diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 4f5ab26bb35..f590f1f8815 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -75,7 +75,6 @@ import 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentServi import 'vs/workbench/services/integrity/electron-sandbox/integrityService'; import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService'; import 'vs/workbench/services/checksum/electron-sandbox/checksumService'; -import 'vs/workbench/services/voiceRecognition/electron-sandbox/workbenchVoiceRecognitionService'; import 'vs/platform/remote/electron-sandbox/sharedProcessTunnelService'; import 'vs/workbench/services/tunnel/electron-sandbox/tunnelService'; import 'vs/platform/diagnostics/electron-sandbox/diagnosticsService'; From 970cc6eaa530f35bd14baba649d3c82c9d05be9f Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Wed, 18 Oct 2023 15:21:17 +0200 Subject: [PATCH 231/290] Add show tabs submenu to editor tabs bar --- src/vs/platform/actions/common/actions.ts | 1 + .../workbench/browser/parts/editor/editor.contribution.ts | 8 ++++---- .../workbench/browser/parts/editor/noEditorTabsControl.ts | 8 +------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 10a31c98531..081100f8528 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -69,6 +69,7 @@ export class MenuId { static readonly EmptyEditorGroup = new MenuId('EmptyEditorGroup'); static readonly EmptyEditorGroupContext = new MenuId('EmptyEditorGroupContext'); static readonly EditorTabsBarContext = new MenuId('EditorTabsBarContext'); + static readonly EditorTabsBarShowTabsSubmenu = new MenuId('EditorTabsBarShowTabsSubmenu'); static readonly ExplorerContext = new MenuId('ExplorerContext'); static readonly ExplorerContextShare = new MenuId('ExplorerContextShare'); static readonly ExtensionContext = new MenuId('ExtensionContext'); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index cca074fe569..71003f0f7d4 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -355,8 +355,10 @@ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '2_split', order: 20 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 }); -MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ShowSingleEditorTabAction.ID, title: localize('showSingleTab', "Show Single Tab") }, group: '3_config', order: 10, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }); -MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar") }, group: '3_config', order: 15, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none').negate() }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { submenu: MenuId.EditorTabsBarShowTabsSubmenu, title: localize('showTabs', "Show Tabs"), group: '3_config', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowMultipleEditorTabsAction.ID, title: localize('multipleTabs', "Multiple Tab"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '1_config', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowSingleEditorTabAction.ID, title: localize('singleTab', "Single Tab"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single') }, group: '1_config', order: 20 }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none') }, group: '1_config', order: 30 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleSeparatePinnedTabsAction.ID, title: localize('toggleSeparatePinnedEditorTabs', "Separate Pinned Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.pinnedTabsOnSeparateRow') }, when: EditorPinnedAndUnpinnedTabsContext, group: '3_config', order: 20 }); // Editor Title Context Menu @@ -375,8 +377,6 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_ED MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '5_split', order: 40 }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_IN_GROUP, title: localize('splitInGroup', "Split in Group") }, group: '6_split_in_group', order: 10, when: ActiveEditorCanSplitInGroupContext }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: JOIN_EDITOR_IN_GROUP, title: localize('joinInGroup', "Join in Group") }, group: '6_split_in_group', order: 10, when: SideBySideEditorActiveContext }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: ShowMultipleEditorTabsAction.ID, title: localize('showMultipleTabs', "Show Multiple Tabs") }, group: '7_config', order: 10, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single') }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar") }, group: '7_config', order: 20, when: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none').negate() }); // Editor Title Menu MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_DIFF_SIDE_BY_SIDE, title: localize('inlineView', "Inline View"), toggled: ContextKeyExpr.equals('config.diffEditor.renderSideBySide', false) }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') }); diff --git a/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts b/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts index 4d426dcf52f..f265b196212 100644 --- a/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts @@ -11,11 +11,7 @@ import { IEditorTitleControlDimensions } from 'vs/workbench/browser/parts/editor export class NoEditorTabsControl extends EditorTabsControl { - protected override create(parent: HTMLElement): void { - super.create(parent); - } - - protected override prepareEditorActions(editorActions: IToolbarActions): IToolbarActions { + protected prepareEditorActions(editorActions: IToolbarActions): IToolbarActions { return { primary: [], secondary: [] @@ -50,8 +46,6 @@ export class NoEditorTabsControl extends EditorTabsControl { updateEditorDirty(editor: EditorInput): void { } - override updateStyles(): void { } - getHeight(): number { return 0; } From fa0a3031eccc52d7e723d752d40e2e6cabb3ae47 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:44:15 +0200 Subject: [PATCH 232/290] SCM - Source Control Repositories view to use scm.providerCountBadge (#194696) * SCM - Source Control Repositories view to use scm.providerCountBadge * Update setting description * Pull request feedback --- .../contrib/scm/browser/scm.contribution.ts | 2 +- .../scm/browser/scmRepositoriesViewPane.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 689016f02bf..924f9f477a1 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -228,7 +228,7 @@ Registry.as(ConfigurationExtensions.Configuration).regis localize('scm.providerCountBadge.auto', "Only show count badge for Source Control Provider when non-zero."), localize('scm.providerCountBadge.visible', "Show Source Control Provider count badges.") ], - description: localize('scm.providerCountBadge', "Controls the count badges on Source Control Provider headers. These headers only appear when there is more than one provider."), + markdownDescription: localize('scm.providerCountBadge', "Controls the count badges on Source Control Provider headers. These headers appear in the \"Source Control\", and \"Source Control Sync\" views when there is more than one provider or when the {0} setting is enabled, as well as in the \"Source Control Repositories\" view.", '\`#scm.alwaysShowRepositories#\`'), default: 'hidden' }, 'scm.defaultViewMode': { diff --git a/src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts index ab4e907d21b..3cd3d80fb18 100644 --- a/src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts @@ -5,6 +5,7 @@ import 'vs/css!./media/scm'; import { localize } from 'vs/nls'; +import { Event } from 'vs/base/common/event'; import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane'; import { append, $ } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list'; @@ -24,6 +25,7 @@ import { RepositoryRenderer } from 'vs/workbench/contrib/scm/browser/scmReposito import { collectContextMenuActions, getActionViewItemProvider } from 'vs/workbench/contrib/scm/browser/util'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Iterable } from 'vs/base/common/iterator'; +import { DisposableStore } from 'vs/base/common/lifecycle'; class ListDelegate implements IListVirtualDelegate { @@ -39,6 +41,7 @@ class ListDelegate implements IListVirtualDelegate { export class SCMRepositoriesViewPane extends ViewPane { private list!: WorkbenchList; + private readonly disposables = new DisposableStore(); constructor( options: IViewPaneOptions, @@ -61,6 +64,14 @@ export class SCMRepositoriesViewPane extends ViewPane { const listContainer = append(container, $('.scm-view.scm-repositories-view')); + const updateProviderCountVisibility = () => { + const value = this.configurationService.getValue<'hidden' | 'auto' | 'visible'>('scm.providerCountBadge'); + listContainer.classList.toggle('hide-provider-counts', value === 'hidden'); + listContainer.classList.toggle('auto-provider-counts', value === 'auto'); + }; + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.providerCountBadge'), this.disposables)(updateProviderCountVisibility)); + updateProviderCountVisibility(); + const delegate = new ListDelegate(); const renderer = this.instantiationService.createInstance(RepositoryRenderer, getActionViewItemProvider(this.instantiationService)); const identityProvider = { getId: (r: ISCMRepository) => r.provider.id }; @@ -179,4 +190,9 @@ export class SCMRepositoriesViewPane extends ViewPane { this.list.setFocus([selection[0]]); } } + + override dispose(): void { + this.disposables.dispose(); + super.dispose(); + } } From e26251254a3c4ad0ad7d426b3b72b40ebc76b646 Mon Sep 17 00:00:00 2001 From: Benjamin Simmonds <44439583+benibenj@users.noreply.github.com> Date: Wed, 18 Oct 2023 16:20:00 +0200 Subject: [PATCH 233/290] Update src/vs/workbench/browser/parts/editor/editor.contribution.ts Co-authored-by: Benjamin Pasero --- src/vs/workbench/browser/parts/editor/editor.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 71003f0f7d4..9e657431c9a 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -356,7 +356,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { submenu: MenuId.EditorTabsBarShowTabsSubmenu, title: localize('showTabs', "Show Tabs"), group: '3_config', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowMultipleEditorTabsAction.ID, title: localize('multipleTabs', "Multiple Tab"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '1_config', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowMultipleEditorTabsAction.ID, title: localize('multipleTabs', "Multiple Tabs"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '1_config', order: 10 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowSingleEditorTabAction.ID, title: localize('singleTab', "Single Tab"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single') }, group: '1_config', order: 20 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none') }, group: '1_config', order: 30 }); MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleSeparatePinnedTabsAction.ID, title: localize('toggleSeparatePinnedEditorTabs', "Separate Pinned Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.pinnedTabsOnSeparateRow') }, when: EditorPinnedAndUnpinnedTabsContext, group: '3_config', order: 20 }); From af0e723d17885198779b7ea80bf089bf5a712982 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2023 16:49:10 +0200 Subject: [PATCH 234/290] no diff editor when just dealing with inserts (#195910) --- .../browser/inlineChatLivePreviewWidget.ts | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index 005d0216fb0..12dbe5db481 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -21,7 +21,7 @@ import { LineRange } from 'vs/editor/common/core/lineRange'; import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { Position } from 'vs/editor/common/core/position'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; -import { ScrollType } from 'vs/editor/common/editorCommon'; +import { IEditorDecorationsCollection, ScrollType } from 'vs/editor/common/editorCommon'; import { ILogService } from 'vs/platform/log/common/log'; import { lineRangeAsRange, invertLineRange } from 'vs/workbench/contrib/inlineChat/browser/utils'; import { ResourceLabel } from 'vs/workbench/browser/labels'; @@ -43,7 +43,9 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { private readonly _elements = h('div.inline-chat-diff-widget@domNode'); + private readonly _decorationCollection: IEditorDecorationsCollection; private readonly _diffEditor: IDiffEditor; + private _dim: Dimension | undefined; private _isVisible: boolean = false; @@ -60,6 +62,8 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { super.create(); assertType(editor.hasModel()); + this._decorationCollection = editor.createDecorationsCollection(); + const diffContributions = EditorExtensionsRegistry .getEditorContributions() .filter(c => c.id !== INLINE_CHAT_ID && c.id !== FoldingController.ID); @@ -137,6 +141,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { } override hide(): void { + this._decorationCollection.clear(); this._cleanupFullDiff(); super.hide(); this._isVisible = false; @@ -150,13 +155,17 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { const hasFocus = this._diffEditor.hasTextFocus(); this._isVisible = true; - if (changes.length === 0 || this._session.textModel0.getValueLength() === 0) { + const onlyInserts = changes.every(change => change.original.isEmpty); + + if (onlyInserts || changes.length === 0 || this._session.textModel0.getValueLength() === 0) { // no change or changes to an empty file this._logService.debug('[IE] livePreview-mode: no diff'); this._cleanupFullDiff(); + this._renderInsertWithHighlight(changes); } else { // complex changes this._logService.debug('[IE] livePreview-mode: full diff'); + this._decorationCollection.clear(); this._renderChangesWithFullDiff(changes); } @@ -170,6 +179,22 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { } + private _renderInsertWithHighlight(changes: readonly DetailedLineRangeMapping[]) { + assertType(this.editor.hasModel()); + + const ranges = this._computeHiddenRanges(this.editor.getModel(), changes); + + this._decorationCollection.set([{ + range: lineRangeAsRange(ranges.modifiedHidden), + options: { + description: 'inline-chat-insert', + showIfCollapsed: false, + isWholeLine: true, + className: 'inline-chat-lines-inserted-range', + } + }]); + } + // --- full diff private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[]) { From 6663ea94c188e8c2f8d38c163f640ddb8f10887d Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 18 Oct 2023 09:02:33 -0700 Subject: [PATCH 235/290] move in if statement --- .../accessibility/browser/accessibilityContributions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts index 5dd2eaac1df..4b288d0dc48 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts @@ -98,9 +98,8 @@ class EditorAccessibilityHelpProvider implements IAccessibleContentProvider { } } const screenReaderOptimized = this._accessibilityService.isScreenReaderOptimized(); - const saveAudioCue = this._configurationService.getValue(AudioCue.save.settingsKey); - const formatAudioCue = this._configurationService.getValue(AudioCue.format.settingsKey); if (screenReaderOptimized) { + const saveAudioCue = this._configurationService.getValue(AudioCue.save.settingsKey); switch (saveAudioCue) { case 'never': content.push(AccessibilityHelpNLS.saveAudioCueDisabled); @@ -112,6 +111,7 @@ class EditorAccessibilityHelpProvider implements IAccessibleContentProvider { content.push(AccessibilityHelpNLS.saveAudioCueUserGesture); break; } + const formatAudioCue = this._configurationService.getValue(AudioCue.format.settingsKey); switch (formatAudioCue) { case 'never': content.push(AccessibilityHelpNLS.formatAudioCueDisabled); From 962adbee96f54bdf60127dabbb0a2f164d86a65b Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 18 Oct 2023 18:22:19 +0200 Subject: [PATCH 236/290] Fix disappearing editorGutter element in editor (#195917) The "editorGutter" element in the editor has disappeared Fixes #195762 --- .../contrib/scm/browser/dirtydiffDecorator.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index 16eba22cc57..6fc13ccd0ef 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -1674,8 +1674,14 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor for (const [uri, item] of this.items) { for (const editorId of item.keys()) { if (!this.editorService.visibleTextEditorControls.find(editor => isCodeEditor(editor) && editor.getModel()?.uri.toString() === uri.toString() && editor.getId() === editorId)) { - dispose(item.values()); - this.items.delete(uri); + if (item.has(editorId)) { + const dirtyDiffItem = item.get(editorId); + dirtyDiffItem?.dispose(); + item.delete(editorId); + if (item.size === 0) { + this.items.delete(uri); + } + } } } } From 288064ddd27fbb63e1318fa325c2934ae56ae881 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 18 Oct 2023 09:29:01 -0700 Subject: [PATCH 237/290] fix #195834 --- .../terminal/common/capabilities/commandDetectionCapability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 99f609e2c31..b14cec4e26f 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -443,7 +443,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe return; } // TODO: fine tune prompt regex to accomodate for unique configurtions. - return line.translateToString(true)?.match(/^(?(?:PS.+>\s)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; + return line.translateToString(true)?.match(/^(?.*(?:PS.+>\s)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; } handleGenericCommand(options?: IHandleCommandOptions): void { From dc5edccaf01a2560a59ed919ca269fa74ab0fa45 Mon Sep 17 00:00:00 2001 From: Andrew Maust <144873395+amaust@users.noreply.github.com> Date: Wed, 18 Oct 2023 12:34:21 -0400 Subject: [PATCH 238/290] Fixes Aria Label Showing [Object object] --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 980be904fa4..4c960cf556c 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -138,7 +138,7 @@ export class IconLabel extends Disposable { containerClasses.push('disabled'); } if (options.title) { - ariaLabel += options.title; + ariaLabel += label; } } From c4f114586ef0172e03e4eb2d2ace1052a6af5287 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 18 Oct 2023 10:21:26 -0700 Subject: [PATCH 239/290] tighter match --- .../terminal/common/capabilities/commandDetectionCapability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index b14cec4e26f..37e32c47bb7 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -443,7 +443,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe return; } // TODO: fine tune prompt regex to accomodate for unique configurtions. - return line.translateToString(true)?.match(/^(?.*(?:PS.+>\s)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; + return line.translateToString(true)?.match(/^(?(\(.+\)\s)?(?:PS.+>\s)|(?:[A-Z]:\\.*>))/)?.groups?.prompt; } handleGenericCommand(options?: IHandleCommandOptions): void { From 40b94a8f44b77a203dca486039e5fc694d0d57c0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 18 Oct 2023 19:35:43 +0200 Subject: [PATCH 240/290] Better rendering of insert-only "diffs", be very conservative when making separate diff groups (#195921) --- .../browser/inlineChatLivePreviewWidget.ts | 34 ++++++++-------- .../browser/inlineChatStrategies.ts | 40 +++++++++++++------ 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index 12dbe5db481..c95b92258bc 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -10,7 +10,7 @@ import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; -import { ITextModel } from 'vs/editor/common/model'; +import { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model'; import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; @@ -18,7 +18,7 @@ import * as editorColorRegistry from 'vs/editor/common/core/editorColorRegistry' import { IThemeService } from 'vs/platform/theme/common/themeService'; import { INLINE_CHAT_ID, inlineChatDiffInserted, inlineChatDiffRemoved, inlineChatRegionHighlight } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { LineRange } from 'vs/editor/common/core/lineRange'; -import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; +import { LineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { Position } from 'vs/editor/common/core/position'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; import { IEditorDecorationsCollection, ScrollType } from 'vs/editor/common/editorCommon'; @@ -151,7 +151,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { throw new Error('use showForChanges'); } - showForChanges(changes: readonly DetailedLineRangeMapping[]): void { + showForChanges(changes: readonly LineRangeMapping[]): void { const hasFocus = this._diffEditor.hasTextFocus(); this._isVisible = true; @@ -179,25 +179,27 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { } - private _renderInsertWithHighlight(changes: readonly DetailedLineRangeMapping[]) { + private _renderInsertWithHighlight(changes: readonly LineRangeMapping[]) { assertType(this.editor.hasModel()); - const ranges = this._computeHiddenRanges(this.editor.getModel(), changes); + const options: IModelDecorationOptions = { + description: 'inline-chat-insert', + showIfCollapsed: false, + isWholeLine: true, + className: 'inline-chat-lines-inserted-range', + }; - this._decorationCollection.set([{ - range: lineRangeAsRange(ranges.modifiedHidden), - options: { - description: 'inline-chat-insert', - showIfCollapsed: false, - isWholeLine: true, - className: 'inline-chat-lines-inserted-range', - } - }]); + this._decorationCollection.set(changes.map(change => { + return { + range: lineRangeAsRange(change.modified), + options, + }; + })); } // --- full diff - private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[]) { + private _renderChangesWithFullDiff(changes: readonly LineRangeMapping[]) { assertType(this.editor.hasModel()); const modified = this.editor.getModel(); @@ -225,7 +227,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { super.hide(); } - private _computeHiddenRanges(model: ITextModel, changes: readonly DetailedLineRangeMapping[]) { + private _computeHiddenRanges(model: ITextModel, changes: readonly LineRangeMapping[]) { let originalLineRange = changes[0].original; let modifiedLineRange = changes[0].modified; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index d47b03f78c1..c36dfd9d714 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -12,7 +12,7 @@ import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; -import { DetailedLineRangeMapping, LineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; +import { LineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon'; import { TextEdit } from 'vs/editor/common/languages'; import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model'; @@ -377,7 +377,7 @@ export class LivePreviewStrategy extends LiveStrategy { private readonly _previewZone: Lazy; private readonly _diffZonePool: InlineChatLivePreviewWidget[] = []; - private _currentLineRangeGroups: DetailedLineRangeMapping[][] = []; + private _currentLineRangeGroups: LineRangeMapping[][] = []; constructor( session: Session, @@ -411,22 +411,36 @@ export class LivePreviewStrategy extends LiveStrategy { return; } - const groups: DetailedLineRangeMapping[][] = []; - let group = [diff.changes[0]]; - groups.push(group); + const originalStartLineNumber = this._session.session.wholeRange?.startLineNumber ?? 1; - for (let i = 1; i < diff.changes.length; i++) { - const last = tail(group); - const next = diff.changes[i]; + const mainGroup: LineRangeMapping[] = []; + let lastGroup: LineRangeMapping[] | undefined; + const groups: LineRangeMapping[][] = [mainGroup]; + + for (let i = 0; i < diff.changes.length; i++) { + const change = diff.changes[i]; + + // everything below the original start line is one group + if (change.original.startLineNumber >= originalStartLineNumber) { + mainGroup.push(change); + continue; + } + + if (!lastGroup) { + lastGroup = [change]; + groups.push(lastGroup); + continue; + } // when the distance between the two changes is less than 75% of the total number of lines changed // they get merged into the same group - const treshold = Math.ceil((next.modified.length + last.modified.length) * .75); - if (next.modified.startLineNumber - last.modified.endLineNumberExclusive <= treshold) { - group.push(next); + const last = tail(lastGroup); + const treshold = Math.ceil((change.modified.length + last.modified.length) * .75); + if (change.modified.startLineNumber - last.modified.endLineNumberExclusive <= treshold) { + lastGroup.push(change); } else { - group = [next]; - groups.push(group); + lastGroup = [change]; + groups.push(lastGroup); } } From 342a9e5a2e8ccd49646aeb0e7981ab590c394733 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:29:26 -0700 Subject: [PATCH 241/290] Fix extension gallery fail when no network (#195925) Fixes #195722 --- .../preferences/browser/settingsEditor2.ts | 22 +++++--------- .../preferences/browser/settingsLayout.ts | 11 +++---- .../contrib/preferences/common/preferences.ts | 30 +++++++++++++++++-- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 0a9cb4fd924..11cb3a3208f 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -1291,27 +1291,21 @@ export class SettingsEditor2 extends EditorPane { } const additionalGroups: ISettingsGroup[] = []; - const toggleData = await getExperimentalExtensionToggleData(this.workbenchAssignmentService, this.environmentService, this.productService); - if (this.extensionGalleryService.isEnabled() && toggleData && groups.filter(g => g.extensionInfo).length) { + const toggleData = await getExperimentalExtensionToggleData(this.extensionGalleryService, this.workbenchAssignmentService, this.environmentService, this.productService); + if (toggleData && groups.filter(g => g.extensionInfo).length) { for (const key in toggleData.settingsEditorRecommendedExtensions) { - const extensionId = key; - // Recommend prerelease if not on Stable. - const isStable = this.productService.quality === 'stable'; - const [extension] = await this.extensionGalleryService.getExtensions([{ id: extensionId, preRelease: !isStable }], CancellationToken.None); - if (!extension) { - continue; - } - - let groupTitle: string | undefined; + const extension = toggleData.recommendedExtensionsGalleryInfo[key]; const manifest = await this.extensionGalleryService.getManifest(extension, CancellationToken.None); const contributesConfiguration = manifest?.contributes?.configuration; + + let groupTitle: string | undefined; if (!Array.isArray(contributesConfiguration)) { groupTitle = contributesConfiguration?.title; } else if (contributesConfiguration.length === 1) { groupTitle = contributesConfiguration[0].title; } - const extensionName = extension?.displayName ?? extension?.name ?? extensionId; + const extensionName = extension?.displayName ?? extension?.name ?? extension.identifier.id; const settingKey = `${key}.manageExtension`; const setting: ISetting = { range: nullRange, @@ -1325,7 +1319,7 @@ export class SettingsEditor2 extends EditorPane { title: extensionName, scope: ConfigurationScope.WINDOW, type: 'null', - displayExtensionId: extensionId, + displayExtensionId: extension.identifier.id, prereleaseExtensionId: key, stableExtensionId: key, extensionGroupTitle: groupTitle ?? extensionName @@ -1339,7 +1333,7 @@ export class SettingsEditor2 extends EditorPane { resolvedSettingsRoot.children!.push(await createTocTreeForExtensionSettings(this.extensionService, groups.filter(g => g.extensionInfo))); - const commonlyUsedDataToUse = await getCommonlyUsedData(this.workbenchAssignmentService, this.environmentService, this.productService); + const commonlyUsedDataToUse = getCommonlyUsedData(toggleData); const commonlyUsed = resolveSettingsTree(commonlyUsedDataToUse, groups, this.logService); resolvedSettingsRoot.children!.unshift(commonlyUsed.tree); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts index 3f26f411904..ddd36df91b6 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts @@ -4,10 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { getExperimentalExtensionToggleData } from 'vs/workbench/contrib/preferences/common/preferences'; -import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService'; +import { ExtensionToggleData } from 'vs/workbench/contrib/preferences/common/preferences'; + export interface ITOCEntry { id: string; label: string; @@ -31,12 +29,11 @@ const defaultCommonlyUsedSettings: string[] = [ 'workbench.editor.enablePreview' ]; -export async function getCommonlyUsedData(workbenchAssignmentService: IWorkbenchAssignmentService, environmentService: IEnvironmentService, productService: IProductService): Promise> { - const toggleData = await getExperimentalExtensionToggleData(workbenchAssignmentService, environmentService, productService); +export function getCommonlyUsedData(toggleData: ExtensionToggleData | undefined): ITOCEntry { return { id: 'commonlyUsed', label: localize('commonlyUsed', "Commonly Used"), - settings: toggleData ? toggleData.commonlyUsed : defaultCommonlyUsedSettings + settings: toggleData?.commonlyUsed ?? defaultCommonlyUsedSettings }; } diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index 1c07a0e9418..39b553be023 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -8,6 +8,7 @@ import { IStringDictionary } from 'vs/base/common/collections'; import { IExtensionRecommendations } from 'vs/base/common/product'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProductService } from 'vs/platform/product/common/productService'; import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService'; @@ -95,33 +96,56 @@ export const ENABLE_LANGUAGE_FILTER = true; export const ENABLE_EXTENSION_TOGGLE_SETTINGS = true; -type ExtensionToggleData = { +export type ExtensionToggleData = { settingsEditorRecommendedExtensions: IStringDictionary; + recommendedExtensionsGalleryInfo: IStringDictionary; commonlyUsed: string[]; }; let cachedExtensionToggleData: ExtensionToggleData | undefined; -export async function getExperimentalExtensionToggleData(workbenchAssignmentService: IWorkbenchAssignmentService, environmentService: IEnvironmentService, productService: IProductService): Promise { +export async function getExperimentalExtensionToggleData(extensionGalleryService: IExtensionGalleryService, workbenchAssignmentService: IWorkbenchAssignmentService, environmentService: IEnvironmentService, productService: IProductService): Promise { if (!ENABLE_EXTENSION_TOGGLE_SETTINGS) { return undefined; } + if (!extensionGalleryService.isEnabled()) { + return undefined; + } + if (cachedExtensionToggleData) { return cachedExtensionToggleData; } const isTreatment = await workbenchAssignmentService.getTreatment('ExtensionToggleSettings'); if ((isTreatment || !environmentService.isBuilt) && productService.extensionRecommendations && productService.commonlyUsedSettings) { - const settingsEditorRecommendedExtensions: Record = {}; + const settingsEditorRecommendedExtensions: IStringDictionary = {}; Object.keys(productService.extensionRecommendations).forEach(extensionId => { const extensionInfo = productService.extensionRecommendations![extensionId]; if (extensionInfo.onSettingsEditorOpen) { settingsEditorRecommendedExtensions[extensionId] = extensionInfo; } }); + + const recommendedExtensionsGalleryInfo: IStringDictionary = {}; + for (const key in settingsEditorRecommendedExtensions) { + const extensionId = key; + // Recommend prerelease if not on Stable. + const isStable = productService.quality === 'stable'; + try { + const [extension] = await extensionGalleryService.getExtensions([{ id: extensionId, preRelease: !isStable }], CancellationToken.None); + if (extension) { + recommendedExtensionsGalleryInfo[key] = extension; + } + } catch (e) { + // Network connection fail. Return nothing rather than partial data. + return undefined; + } + } + cachedExtensionToggleData = { settingsEditorRecommendedExtensions, + recommendedExtensionsGalleryInfo, commonlyUsed: productService.commonlyUsedSettings }; return cachedExtensionToggleData; From 23234efe3dfa3925f5be73467e81b3580c84d5cc Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 18 Oct 2023 11:34:05 -0700 Subject: [PATCH 242/290] fix: don't show welcome view between reloads (#195928) * fix: rerender chat pane when provider is added * fix: don't show welcome view between reloads --- src/vs/workbench/contrib/chat/browser/chatViewPane.ts | 7 ++++++- src/vs/workbench/contrib/chat/common/chatService.ts | 3 ++- src/vs/workbench/contrib/chat/common/chatServiceImpl.ts | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index 9be6f027aba..a37800587b7 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -66,6 +66,11 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { // View state for the ViewPane is currently global per-provider basically, but some other strictly per-model state will require a separate memento. this.memento = new Memento('interactive-session-view-' + this.chatViewOptions.providerId, this.storageService); this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState; + this._register(this.chatService.onDidRegisterProvider(({ providerId }) => { + if (providerId === this.chatViewOptions.providerId && !this._widget?.viewModel) { + this.updateModel(); + } + })); } private updateModel(model?: IChatModel | undefined): void { @@ -83,7 +88,7 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { } override shouldShowWelcome(): boolean { - return !this.chatService.hasProviders(); + return !this.chatService.hasSessions(this.chatViewOptions.providerId) && !this._widget?.viewModel; } protected override renderBody(parent: HTMLElement): void { diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index d3e13df3fe3..1f544e5294e 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -265,8 +265,9 @@ export interface IChatService { transferredSessionData: IChatTransferredSessionData | undefined; onDidSubmitSlashCommand: Event<{ slashCommand: string; sessionId: string }>; + onDidRegisterProvider: Event<{ providerId: string }>; registerProvider(provider: IChatProvider): IDisposable; - hasProviders(): boolean; + hasSessions(providerId: string): boolean; getProviderInfos(): IChatProviderInfo[]; startSession(providerId: string, token: CancellationToken): ChatModel | undefined; getSession(sessionId: string): IChatModel | undefined; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 2b09ccbe24b..e6d47676f54 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -149,6 +149,9 @@ export class ChatService extends Disposable implements IChatService { private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string }>()); public readonly onDidDisposeSession = this._onDidDisposeSession.event; + private readonly _onDidRegisterProvider = this._register(new Emitter<{ providerId: string }>()); + public readonly onDidRegisterProvider = this._onDidRegisterProvider.event; + constructor( @IStorageService private readonly storageService: IStorageService, @ILogService private readonly logService: ILogService, @@ -742,6 +745,7 @@ export class ChatService extends Disposable implements IChatService { this._providers.set(provider.id, provider); this._hasProvider.set(true); + this._onDidRegisterProvider.fire({ providerId: provider.id }); Array.from(this._sessionModels.values()) .filter(model => model.providerId === provider.id) @@ -759,8 +763,8 @@ export class ChatService extends Disposable implements IChatService { }); } - hasProviders(): boolean { - return this._providers.size > 0; + public hasSessions(providerId: string): boolean { + return !!Object.values(this._persistedSessions).find((session) => session.providerId === providerId); } getProviderInfos(): IChatProviderInfo[] { From fc474f69dc65aa0f8a84c8df47d28363a3827b9f Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 18 Oct 2023 12:06:39 -0700 Subject: [PATCH 243/290] fix: render chat welcome if session init fails (#195933) --- .../workbench/contrib/chat/browser/chatViewPane.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index a37800587b7..38bf98c82c4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -44,6 +44,7 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { private modelDisposables = this._register(new DisposableStore()); private memento: Memento; private viewState: IViewPaneState; + private didProviderRegistrationFail = false; constructor( private readonly chatViewOptions: IChatViewOptions, @@ -88,7 +89,8 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { } override shouldShowWelcome(): boolean { - return !this.chatService.hasSessions(this.chatViewOptions.providerId) && !this._widget?.viewModel; + const noPersistedSessions = !this.chatService.hasSessions(this.chatViewOptions.providerId); + return !this._widget?.viewModel && (noPersistedSessions || this.didProviderRegistrationFail); } protected override renderBody(parent: HTMLElement): void { @@ -121,6 +123,16 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { sessionId = this.viewState.sessionId; } + // Render the welcome view if this session gets disposed at any point, + // including if the provider registration fails + const disposeListener = sessionId ? this._register(this.chatService.onDidDisposeSession((e) => { + if (e.sessionId === sessionId) { + this.didProviderRegistrationFail = true; + disposeListener?.dispose(); + this._onDidChangeViewWelcomeState.fire(); + } + })) : undefined; + const initialModel = sessionId ? this.chatService.getOrRestoreSession(sessionId) : undefined; this.updateModel(initialModel); } catch (e) { From 03ca3e3a42f70d87e036c8b63031057f42e5e312 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 18 Oct 2023 12:43:29 -0700 Subject: [PATCH 244/290] fix #195814 --- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index af6ba1145eb..f07ef891a23 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -622,7 +622,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { iconElement.classList.remove(...ThemeIcon.asClassNameArray(icon(element))); @@ -630,6 +630,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer Date: Wed, 18 Oct 2023 12:47:49 -0700 Subject: [PATCH 245/290] clean up --- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index f07ef891a23..108b766f61b 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -622,7 +622,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { iconElement.classList.remove(...ThemeIcon.asClassNameArray(icon(element))); @@ -630,7 +630,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer Date: Wed, 18 Oct 2023 13:22:22 -0700 Subject: [PATCH 246/290] Use less padding on ul and ol elements in chat --- src/vs/workbench/contrib/chat/browser/media/chat.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 04abd853552..10fdef20e20 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -162,6 +162,14 @@ line-height: 1.5em; } +.interactive-item-container .value .rendered-markdown ul { + padding-inline-start: 24px; +} + +.interactive-item-container .value .rendered-markdown ol { + padding-inline-start: 28px; +} + .interactive-item-container .value .rendered-markdown li { line-height: 1.3rem; } From 5c41358a2f500a32f542533197436e22db2f7d25 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 18 Oct 2023 13:55:01 -0700 Subject: [PATCH 247/290] fix #195941 --- .../browser/terminalAccessibleBufferProvider.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts index 0540afae829..36988986a57 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts @@ -9,6 +9,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/model'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver'; import { TerminalCapability, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; @@ -34,7 +35,8 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements @IConfigurationService configurationService: IConfigurationService, @IContextKeyService _contextKeyService: IContextKeyService, @ITerminalService _terminalService: ITerminalService, - @IKeybindingService private readonly _keybindingService: IKeybindingService + @IKeybindingService private readonly _keybindingService: IKeybindingService, + @IContextViewService private readonly _contextViewService: IContextViewService ) { super(); this.options.customHelp = customHelp; @@ -58,6 +60,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements if (!shouldFocusTerminal(e.browserEvent, this._keybindingService)) { return; } + this._contextViewService.hideContextView(); this._instance.focus(); } From 9979a72abf788fb3b1da2ddbd9378c493de7cb1e Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 18 Oct 2023 14:14:06 -0700 Subject: [PATCH 248/290] debug: fix serverReadyAction.killOnServerStop not working (#195944) Fixes #195942 --- .../debug-server-ready/src/extension.ts | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/extensions/debug-server-ready/src/extension.ts b/extensions/debug-server-ready/src/extension.ts index 307b5e25475..df5c8521c09 100644 --- a/extensions/debug-server-ready/src/extension.ts +++ b/extensions/debug-server-ready/src/extension.ts @@ -53,11 +53,12 @@ class ServerReadyDetector extends vscode.Disposable { private static detectors = new Map(); private static terminalDataListener: vscode.Disposable | undefined; + private readonly stoppedEmitter = new vscode.EventEmitter(); + private readonly onDidSessionStop = this.stoppedEmitter.event; + private readonly disposables = new Set([]); private trigger: Trigger; private shellPid?: number; private regexp: RegExp; - private disposables: vscode.Disposable[] = []; - private lateDisposables = new Set([]); static start(session: vscode.DebugSession): ServerReadyDetector | undefined { if (session.configuration.serverReadyAction) { @@ -75,6 +76,7 @@ class ServerReadyDetector extends vscode.Disposable { const detector = ServerReadyDetector.detectors.get(session); if (detector) { ServerReadyDetector.detectors.delete(session); + detector.sessionStopped(); detector.dispose(); } } @@ -125,12 +127,11 @@ class ServerReadyDetector extends vscode.Disposable { private internalDispose() { this.disposables.forEach(d => d.dispose()); - this.disposables = []; + this.disposables.clear(); } - override dispose() { - this.lateDisposables.forEach(d => d.dispose()); - return super.dispose(); + public sessionStopped() { + this.stoppedEmitter.fire(); } detectPattern(s: string): boolean { @@ -139,7 +140,6 @@ class ServerReadyDetector extends vscode.Disposable { if (matches && matches.length >= 1) { this.openExternalWithString(this.session, matches.length > 1 ? matches[1] : ''); this.trigger.fire(); - this.internalDispose(); return true; } } @@ -147,7 +147,6 @@ class ServerReadyDetector extends vscode.Disposable { } private openExternalWithString(session: vscode.DebugSession, captureString: string) { - const args: ServerReadyAction = session.configuration.serverReadyAction; let uri; @@ -228,14 +227,12 @@ class ServerReadyDetector extends vscode.Disposable { return; } - const stopListener = vscode.debug.onDidTerminateDebugSession(async (terminated) => { - if (terminated === session) { - stopListener.dispose(); - this.lateDisposables.delete(stopListener); - await vscode.debug.stopDebugging(createdSession); - } + const stopListener = this.onDidSessionStop(async () => { + stopListener.dispose(); + this.disposables.delete(stopListener); + await vscode.debug.stopDebugging(createdSession); }); - this.lateDisposables.add(stopListener); + this.disposables.add(stopListener); } private startBrowserDebugSession(type: string, session: vscode.DebugSession, uri: string, trackerId?: string) { @@ -272,14 +269,12 @@ class ServerReadyDetector extends vscode.Disposable { return; } - const stopListener = vscode.debug.onDidTerminateDebugSession(async (terminated) => { - if (terminated === session) { - stopListener.dispose(); - this.lateDisposables.delete(stopListener); - await vscode.debug.stopDebugging(createdSession); - } + const stopListener = this.onDidSessionStop(async () => { + stopListener.dispose(); + this.disposables.delete(stopListener); + await vscode.debug.stopDebugging(createdSession); }); - this.lateDisposables.add(stopListener); + this.disposables.add(stopListener); } private catchStartedDebugSession(predicate: (session: vscode.DebugSession) => boolean, cancellationToken: vscode.CancellationToken): Promise { @@ -287,8 +282,8 @@ class ServerReadyDetector extends vscode.Disposable { const done = (value?: vscode.DebugSession) => { listener.dispose(); cancellationListener.dispose(); - this.lateDisposables.delete(listener); - this.lateDisposables.delete(cancellationListener); + this.disposables.delete(listener); + this.disposables.delete(cancellationListener); _resolve(value); }; @@ -300,8 +295,8 @@ class ServerReadyDetector extends vscode.Disposable { }); // In case the debug session of interest was never caught anyhow. - this.lateDisposables.add(listener); - this.lateDisposables.add(cancellationListener); + this.disposables.add(listener); + this.disposables.add(cancellationListener); }); } } From dedfcf65d348fec024f05d675aab73c769e4c81c Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 18 Oct 2023 16:52:49 -0700 Subject: [PATCH 249/290] feat: add enum descriptions for TS locale setting (#195947) --- .../typescript-language-features/package.json | 13 +++++++++++++ .../typescript-language-features/package.nls.json | 1 + 2 files changed, 14 insertions(+) diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 607bb3aabe0..850a0855a8d 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -859,6 +859,19 @@ "zh-CN", "zh-TW" ], + "enumDescriptions": [ + "%typescript.locale.auto%", + "Deutsch", + "español", + "English", + "français", + "italiano", + "日本語", + "한국어", + "русский", + "中文(简体)", + "中文(繁體)" + ], "markdownDescription": "%typescript.locale%", "scope": "window" }, diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index f31c5fa3be4..4ae4c9a9c99 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -82,6 +82,7 @@ "configuration.tsserver.maxTsServerMemory": "The maximum amount of memory (in MB) to allocate to the TypeScript server process. To use a memory limit greater than 4 GB, use `#typescript.tsserver.nodePath#` to run TS Server with a custom Node installation.", "configuration.tsserver.experimental.enableProjectDiagnostics": "(Experimental) Enables project wide error reporting.", "typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Defaults to use VS Code's locale.", + "typescript.locale.auto": "Use VS Code's configured display language", "configuration.implicitProjectConfig.module": "Sets the module system for the program. See more: https://www.typescriptlang.org/tsconfig#module.", "configuration.implicitProjectConfig.target": "Set target JavaScript language version for emitted JavaScript and include library declarations. See more: https://www.typescriptlang.org/tsconfig#target.", "configuration.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing `jsconfig.json` or `tsconfig.json` files override this setting.", From e13e81d2e6746a5414f8c146374a2b093bf9e1c3 Mon Sep 17 00:00:00 2001 From: Andrew Maust <144873395+amaust@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:47:02 -0400 Subject: [PATCH 250/290] Fix for cases where the Aria-label is already a string. --- src/vs/base/browser/ui/iconLabel/iconLabel.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 4c960cf556c..6fa5b4551a2 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -138,7 +138,11 @@ export class IconLabel extends Disposable { containerClasses.push('disabled'); } if (options.title) { - ariaLabel += label; + if (typeof options.title === 'string') { + ariaLabel += options.title; + } else { + ariaLabel += label; + } } } From 96d5db84d1dfb60318269b769907a5b1dc185d91 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 18 Oct 2023 15:37:02 -0700 Subject: [PATCH 251/290] cli: fix closing before stdio is drained Fixes https://github.com/microsoft/vscode-remote-tunnels/issues/693 --- cli/src/tunnels/control_server.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cli/src/tunnels/control_server.rs b/cli/src/tunnels/control_server.rs index df2c8b2b820..bb3715832b1 100644 --- a/cli/src/tunnels/control_server.rs +++ b/cli/src/tunnels/control_server.rs @@ -1037,7 +1037,14 @@ where let futs = FuturesUnordered::new(); if let (Some(mut a), Some(mut b)) = (p.stdout.take(), stdout) { - futs.push(async move { tokio::io::copy(&mut a, &mut b).await }.boxed()); + futs.push( + async move { + let r = tokio::io::copy(&mut a, &mut b).await; + // println!("copy exited with {:?}", r); + r + } + .boxed(), + ); } if let (Some(mut a), Some(mut b)) = (p.stderr.take(), stderr) { futs.push(async move { tokio::io::copy(&mut a, &mut b).await }.boxed()); @@ -1110,13 +1117,7 @@ async fn wait_for_process_exit( mut process: tokio::process::Child, futs: FuturesUnordered>>, ) -> Result { - let closed = process.wait(); - pin!(closed); - - let r = tokio::select! { - _ = futures::future::join_all(futs) => closed.await, - r = &mut closed => r - }; + let (_, r) = tokio::join!(futures::future::join_all(futs), process.wait()); let r = match r { Ok(e) => SpawnResult { From 4aa04c7db2a977d2b7a9336e2bc04e1a5d86f366 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 18 Oct 2023 19:08:19 -0700 Subject: [PATCH 252/290] cli: add extra fs operations for container Ref https://github.com/microsoft/vscode-remote-tunnels/issues/695 --- cli/src/tunnels/control_server.rs | 147 ++++++++++++++++++++++++++---- cli/src/tunnels/protocol.rs | 67 +++++++++++++- cli/src/util/machine.rs | 12 +++ 3 files changed, 206 insertions(+), 20 deletions(-) diff --git a/cli/src/tunnels/control_server.rs b/cli/src/tunnels/control_server.rs index bb3715832b1..48c11fc1b35 100644 --- a/cli/src/tunnels/control_server.rs +++ b/cli/src/tunnels/control_server.rs @@ -21,6 +21,7 @@ use crate::util::http::{ }; use crate::util::io::SilentCopyProgress; use crate::util::is_integrated_cli; +use crate::util::machine::kill_pid; use crate::util::os::os_release; use crate::util::sync::{new_barrier, Barrier, BarrierOpener}; @@ -29,6 +30,7 @@ use futures::FutureExt; use opentelemetry::trace::SpanKind; use opentelemetry::KeyValue; use std::collections::HashMap; +use std::path::PathBuf; use std::process::Stdio; use tokio::pin; use tokio::process::{ChildStderr, ChildStdin}; @@ -51,9 +53,10 @@ use super::port_forwarder::{PortForwarding, PortForwardingProcessor}; use super::protocol::{ AcquireCliParams, CallServerHttpParams, CallServerHttpResult, ChallengeIssueParams, ChallengeIssueResponse, ChallengeVerifyParams, ClientRequestMethod, EmptyObject, ForwardParams, - ForwardResult, FsStatRequest, FsStatResponse, GetEnvResponse, GetHostnameResponse, - HttpBodyParams, HttpHeadersParams, ServeParams, ServerLog, ServerMessageParams, SpawnParams, - SpawnResult, ToClientRequest, UnforwardParams, UpdateParams, UpdateResult, VersionResponse, + ForwardResult, FsReadDirEntry, FsReadDirResponse, FsRenameRequest, FsSinglePathRequest, + FsStatResponse, GetEnvResponse, GetHostnameResponse, HttpBodyParams, HttpHeadersParams, + ServeParams, ServerLog, ServerMessageParams, SpawnParams, SpawnResult, SysKillRequest, + SysKillResponse, ToClientRequest, UnforwardParams, UpdateParams, UpdateResult, VersionResponse, METHOD_CHALLENGE_VERIFY, }; use super::server_bridge::ServerBridge; @@ -306,10 +309,54 @@ fn make_socket_rpc( rpc.register_sync("ping", |_: EmptyObject, _| Ok(EmptyObject {})); rpc.register_sync("gethostname", |_: EmptyObject, _| handle_get_hostname()); - rpc.register_sync("fs_stat", |p: FsStatRequest, c| { + rpc.register_sync("sys_kill", |p: SysKillRequest, c| { + ensure_auth(&c.auth_state)?; + handle_sys_kill(p.pid) + }); + rpc.register_sync("fs_stat", |p: FsSinglePathRequest, c| { ensure_auth(&c.auth_state)?; handle_stat(p.path) }); + rpc.register_duplex( + "fs_read", + 1, + move |mut streams, p: FsSinglePathRequest, c| async move { + ensure_auth(&c.auth_state)?; + handle_fs_read(streams.remove(0), p.path).await + }, + ); + rpc.register_duplex( + "fs_write", + 1, + move |mut streams, p: FsSinglePathRequest, c| async move { + ensure_auth(&c.auth_state)?; + handle_fs_write(streams.remove(0), p.path).await + }, + ); + rpc.register_duplex( + "fs_connect", + 1, + move |mut streams, p: FsSinglePathRequest, c| async move { + ensure_auth(&c.auth_state)?; + handle_fs_connect(streams.remove(0), p.path).await + }, + ); + rpc.register_async("fs_rm", move |p: FsSinglePathRequest, c| async move { + ensure_auth(&c.auth_state)?; + handle_fs_remove(p.path).await + }); + rpc.register_sync("fs_mkdirp", |p: FsSinglePathRequest, c| { + ensure_auth(&c.auth_state)?; + handle_fs_mkdirp(p.path) + }); + rpc.register_sync("fs_rename", |p: FsRenameRequest, c| { + ensure_auth(&c.auth_state)?; + handle_fs_rename(p.from_path, p.to_path) + }); + rpc.register_sync("fs_readdir", |p: FsSinglePathRequest, c| { + ensure_auth(&c.auth_state)?; + handle_fs_readdir(p.path) + }); rpc.register_sync("get_env", |_: EmptyObject, c| { ensure_auth(&c.auth_state)?; handle_get_env() @@ -820,16 +867,87 @@ fn handle_stat(path: String) -> Result { .map(|m| FsStatResponse { exists: true, size: Some(m.len()), - kind: Some(match m.file_type() { - t if t.is_dir() => "dir", - t if t.is_file() => "file", - t if t.is_symlink() => "link", - _ => "unknown", - }), + kind: Some(m.file_type().into()), }) .unwrap_or_default()) } +async fn handle_fs_read(mut out: DuplexStream, path: String) -> Result { + let mut f = tokio::fs::File::open(path) + .await + .map_err(|e| wrap(e, "file not found"))?; + + tokio::io::copy(&mut f, &mut out) + .await + .map_err(|e| wrap(e, "error reading file"))?; + + Ok(EmptyObject {}) +} + +async fn handle_fs_write(mut input: DuplexStream, path: String) -> Result { + let mut f = tokio::fs::File::create(path) + .await + .map_err(|e| wrap(e, "file not found"))?; + + tokio::io::copy(&mut input, &mut f) + .await + .map_err(|e| wrap(e, "error writing file"))?; + + Ok(EmptyObject {}) +} + +async fn handle_fs_connect( + mut stream: DuplexStream, + path: String, +) -> Result { + let mut s = get_socket_rw_stream(&PathBuf::from(path)) + .await + .map_err(|e| wrap(e, "could not connect to socket"))?; + + tokio::io::copy_bidirectional(&mut stream, &mut s) + .await + .map_err(|e| wrap(e, "error copying stream data"))?; + + Ok(EmptyObject {}) +} + +async fn handle_fs_remove(path: String) -> Result { + tokio::fs::remove_dir_all(path) + .await + .map_err(|e| wrap(e, "error removing directory"))?; + Ok(EmptyObject {}) +} + +fn handle_fs_rename(from_path: String, to_path: String) -> Result { + std::fs::rename(from_path, to_path).map_err(|e| wrap(e, "error renaming"))?; + Ok(EmptyObject {}) +} + +fn handle_fs_mkdirp(path: String) -> Result { + std::fs::create_dir_all(path).map_err(|e| wrap(e, "error creating directory"))?; + Ok(EmptyObject {}) +} + +fn handle_fs_readdir(path: String) -> Result { + let mut entries = std::fs::read_dir(path).map_err(|e| wrap(e, "error listing directory"))?; + + let mut contents = Vec::new(); + while let Some(Ok(child)) = entries.next() { + contents.push(FsReadDirEntry { + name: child.file_name().to_string_lossy().into_owned(), + kind: child.file_type().ok().map(|v| v.into()), + }); + } + + Ok(FsReadDirResponse { contents }) +} + +fn handle_sys_kill(pid: u32) -> Result { + Ok(SysKillResponse { + success: kill_pid(pid), + }) +} + fn handle_get_env() -> Result { Ok(GetEnvResponse { env: std::env::vars().collect(), @@ -1037,14 +1155,7 @@ where let futs = FuturesUnordered::new(); if let (Some(mut a), Some(mut b)) = (p.stdout.take(), stdout) { - futs.push( - async move { - let r = tokio::io::copy(&mut a, &mut b).await; - // println!("copy exited with {:?}", r); - r - } - .boxed(), - ); + futs.push(async move { tokio::io::copy(&mut a, &mut b).await }.boxed()); } if let (Some(mut a), Some(mut b)) = (p.stderr.take(), stderr) { futs.push(async move { tokio::io::copy(&mut a, &mut b).await }.boxed()); diff --git a/cli/src/tunnels/protocol.rs b/cli/src/tunnels/protocol.rs index 5665714fed9..547ffba82a8 100644 --- a/cli/src/tunnels/protocol.rs +++ b/cli/src/tunnels/protocol.rs @@ -133,17 +133,80 @@ pub struct GetEnvResponse { pub os_release: String, } +/// Method: `kill`. Sends a generic, platform-specific kill command to the process. #[derive(Deserialize)] -pub struct FsStatRequest { +pub struct SysKillRequest { + pub pid: u32, +} + +#[derive(Serialize)] +pub struct SysKillResponse { + pub success: bool, +} + +/// Methods: `fs_read`/`fs_write`/`fs_rm`/`fs_mkdirp`/`fs_stat` +/// - fs_read: reads into a stream returned from the method, +/// - fs_write: writes from a stream passed to the method. +/// - fs_rm: recursively removes the file +/// - fs_mkdirp: recursively creates the directory +/// - fs_readdir: reads directory contents +/// - fs_stat: stats the given path +/// - fs_connect: connect to the given unix or named pipe socket, streaming +/// data in and out from the method's stream. +#[derive(Deserialize)] +pub struct FsSinglePathRequest { pub path: String, } +#[derive(Serialize)] +pub enum FsFileKind { + #[serde(rename = "dir")] + Directory, + #[serde(rename = "file")] + File, + #[serde(rename = "link")] + Link, +} + +impl From for FsFileKind { + fn from(kind: std::fs::FileType) -> Self { + if kind.is_dir() { + Self::Directory + } else if kind.is_file() { + Self::File + } else if kind.is_symlink() { + Self::Link + } else { + unreachable!() + } + } +} + #[derive(Serialize, Default)] pub struct FsStatResponse { pub exists: bool, pub size: Option, #[serde(rename = "type")] - pub kind: Option<&'static str>, + pub kind: Option, +} + +#[derive(Serialize)] +pub struct FsReadDirResponse { + pub contents: Vec, +} + +#[derive(Serialize)] +pub struct FsReadDirEntry { + pub name: String, + #[serde(rename = "type")] + pub kind: Option, +} + +/// Method: `fs_reaname`. Renames a file. +#[derive(Deserialize)] +pub struct FsRenameRequest { + pub from_path: String, + pub to_path: String, } #[derive(Deserialize, Debug)] diff --git a/cli/src/util/machine.rs b/cli/src/util/machine.rs index 1df4a7843ff..4c7b6729e43 100644 --- a/cli/src/util/machine.rs +++ b/cli/src/util/machine.rs @@ -29,6 +29,18 @@ pub fn process_exists(pid: u32) -> bool { sys.refresh_process(Pid::from_u32(pid)) } +pub fn kill_pid(pid: u32) -> bool { + let mut sys = System::new(); + let pid = Pid::from_u32(pid); + sys.refresh_process(pid); + + if let Some(p) = sys.process(pid) { + p.kill() + } else { + false + } +} + pub async fn wait_until_process_exits(pid: Pid, poll_ms: u64) { let mut s = System::new(); let duration = Duration::from_millis(poll_ms); From e897a3e1b897236dcd40b72fedd0217369991471 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 18 Oct 2023 20:28:19 -0700 Subject: [PATCH 253/290] Add timings telemetry for chat agents (#195955) --- .../workbench/api/common/extHostChatAgents2.ts | 17 +++++++++++------ .../workbench/contrib/chat/common/chatAgents.ts | 2 +- .../contrib/chat/common/chatService.ts | 2 +- .../contrib/chat/common/chatServiceImpl.ts | 10 +++++----- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 4044bb79786..1d7f6adaa2e 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -7,8 +7,10 @@ import { DeferredPromise, raceCancellation } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Emitter } from 'vs/base/common/event'; +import { StopWatch } from 'vs/base/common/stopwatch'; import { assertType } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { Progress } from 'vs/platform/progress/common/progress'; @@ -75,6 +77,8 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { ? await agent.validateSlashCommand(request.command) : undefined; + const stopWatch = StopWatch.create(false); + let firstProgress: number | undefined; try { const task = agent.invoke( { @@ -85,6 +89,10 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { { history: context.history.map(typeConvert.ChatMessage.to) }, new Progress(progress => { throwIfDone(); + if (typeof firstProgress === 'undefined') { + firstProgress = stopWatch.elapsed(); + } + const convertedProgress = typeConvert.ChatResponseProgress.from(progress); if ('placeholder' in progress && 'resolvedContent' in progress) { const resolvedContent = Promise.all([this._proxy.$handleProgressChunk(requestId, convertedProgress), progress.resolvedContent]); @@ -112,7 +120,8 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { } sessionResults.set(requestId, result); - return { errorDetails: result.errorDetails }; // TODO timings here + const timings = { firstProgress: firstProgress, totalElapsed: stopWatch.elapsed() }; + return { errorDetails: result.errorDetails, timings }; } else { this._previousResultMap.delete(sessionId); } @@ -122,11 +131,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { } catch (e) { this._logService.error(e, agent.extension); - return { - errorDetails: { - message: toErrorMessage(e) - } - }; + return { errorDetails: { message: localize('errorResponse', "Error from provider: {0}", toErrorMessage(e)), responseIsIncomplete: true } }; } finally { done = true; diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index 6a4867cec7e..46ffe37cefe 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -54,7 +54,7 @@ export interface IChatAgentResult { followUp?: IChatFollowup[]; errorDetails?: IChatResponseErrorDetails; timings?: { - firstProgress: number; + firstProgress?: number; totalElapsed: number; }; } diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 1f544e5294e..3ae70a7161b 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -42,7 +42,7 @@ export interface IChatResponse { session: IChat; errorDetails?: IChatResponseErrorDetails; timings?: { - firstProgress: number; + firstProgress?: number; totalElapsed: number; }; } diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index e6d47676f54..537a3c2e59c 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -45,8 +45,8 @@ const SESSION_TRANSFER_EXPIRATION_IN_MILLISECONDS = 1000 * 60; type ChatProviderInvokedEvent = { providerId: string; - timeToFirstProgress: number; - totalTime: number; + timeToFirstProgress: number | undefined; + totalTime: number | undefined; result: 'success' | 'error' | 'errorWithOutput' | 'cancelled' | 'filtered'; requestType: 'string' | 'followup' | 'slashCommand'; slashCommand: string | undefined; @@ -485,7 +485,7 @@ export class ChatService extends Disposable implements IChatService { this.trace('sendRequest', `Request for session ${model.sessionId} was cancelled`); this.telemetryService.publicLog2('interactiveSessionProviderInvoked', { providerId: provider.id, - timeToFirstProgress: -1, + timeToFirstProgress: undefined, // Normally timings happen inside the EH around the actual provider. For cancellation we can measure how long the user waited before cancelling totalTime: stopWatch.elapsed(), result: 'cancelled', @@ -589,8 +589,8 @@ export class ChatService extends Disposable implements IChatService { 'success'; this.telemetryService.publicLog2('interactiveSessionProviderInvoked', { providerId: provider.id, - timeToFirstProgress: rawResponse.timings?.firstProgress ?? 0, - totalTime: rawResponse.timings?.totalElapsed ?? 0, + timeToFirstProgress: rawResponse.timings?.firstProgress, + totalTime: rawResponse.timings?.totalElapsed, result, requestType, slashCommand: usedSlashCommand?.command From 29c169c1d7bcc243ebd46651641bf38731bd2215 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 18 Oct 2023 21:10:17 -0700 Subject: [PATCH 254/290] Disable text selection on references button (#195958) --- src/vs/workbench/contrib/chat/browser/media/chat.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 10fdef20e20..d8c8fe803e5 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -465,6 +465,7 @@ font-size: 12px; color: var(--vscode-foreground); opacity: 0.8; + user-select: none; } .interactive-session .chat-used-context-label:hover { From c42f8961f9ba803175ccbb8260e8d70d561f8bee Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 18 Oct 2023 21:50:32 -0700 Subject: [PATCH 255/290] fix: use persisted chat session (#195959) Also don't record init failure on session clear --- .../contrib/chat/browser/chatViewPane.ts | 30 +++++++++++-------- .../contrib/chat/common/chatService.ts | 2 +- .../contrib/chat/common/chatServiceImpl.ts | 6 ++-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index 38bf98c82c4..88d3ebd5bb3 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -69,7 +69,9 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState; this._register(this.chatService.onDidRegisterProvider(({ providerId }) => { if (providerId === this.chatViewOptions.providerId && !this._widget?.viewModel) { - this.updateModel(); + const sessionId = this.getSessionId(); + const model = sessionId ? this.chatService.getOrRestoreSession(sessionId) : undefined; + this.updateModel(model); } })); } @@ -93,6 +95,17 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { return !this._widget?.viewModel && (noPersistedSessions || this.didProviderRegistrationFail); } + private getSessionId() { + let sessionId: string | undefined; + if (this.chatService.transferredSessionData) { + sessionId = this.chatService.transferredSessionData.sessionId; + this.viewState.inputValue = this.chatService.transferredSessionData.inputValue; + } else { + sessionId = this.viewState.sessionId; + } + return sessionId; + } + protected override renderBody(parent: HTMLElement): void { try { super.renderBody(parent); @@ -115,26 +128,19 @@ export class ChatViewPane extends ViewPane implements IChatViewPane { this._register(this._widget.onDidClear(() => this.clear())); this._widget.render(parent); - let sessionId: string | undefined; - if (this.chatService.transferredSessionData) { - sessionId = this.chatService.transferredSessionData.sessionId; - this.viewState.inputValue = this.chatService.transferredSessionData.inputValue; - } else { - sessionId = this.viewState.sessionId; - } - + const sessionId = this.getSessionId(); // Render the welcome view if this session gets disposed at any point, // including if the provider registration fails const disposeListener = sessionId ? this._register(this.chatService.onDidDisposeSession((e) => { - if (e.sessionId === sessionId) { + if (e.reason === 'initializationFailed' && e.sessionId === sessionId) { this.didProviderRegistrationFail = true; disposeListener?.dispose(); this._onDidChangeViewWelcomeState.fire(); } })) : undefined; + const model = sessionId ? this.chatService.getOrRestoreSession(sessionId) : undefined; - const initialModel = sessionId ? this.chatService.getOrRestoreSession(sessionId) : undefined; - this.updateModel(initialModel); + this.updateModel(model); } catch (e) { this.logService.error(e); throw e; diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 3ae70a7161b..eef34513cd3 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -290,7 +290,7 @@ export interface IChatService { onDidPerformUserAction: Event; notifyUserAction(event: IChatUserActionEvent): void; - onDidDisposeSession: Event<{ sessionId: string }>; + onDidDisposeSession: Event<{ sessionId: string; reason: 'initializationFailed' | 'cleared' }>; transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void; } diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 537a3c2e59c..dda6ceded44 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -146,7 +146,7 @@ export class ChatService extends Disposable implements IChatService { private readonly _onDidSubmitSlashCommand = this._register(new Emitter<{ slashCommand: string; sessionId: string }>()); public readonly onDidSubmitSlashCommand = this._onDidSubmitSlashCommand.event; - private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string }>()); + private readonly _onDidDisposeSession = this._register(new Emitter<{ sessionId: string; reason: 'initializationFailed' | 'cleared' }>()); public readonly onDidDisposeSession = this._onDidDisposeSession.event; private readonly _onDidRegisterProvider = this._register(new Emitter<{ providerId: string }>()); @@ -379,7 +379,7 @@ export class ChatService extends Disposable implements IChatService { model.setInitializationError(err); model.dispose(); this._sessionModels.delete(model.sessionId); - this._onDidDisposeSession.fire({ sessionId: model.sessionId }); + this._onDidDisposeSession.fire({ sessionId: model.sessionId, reason: 'initializationFailed' }); } } @@ -733,7 +733,7 @@ export class ChatService extends Disposable implements IChatService { model.dispose(); this._sessionModels.delete(sessionId); this._pendingRequests.get(sessionId)?.cancel(); - this._onDidDisposeSession.fire({ sessionId }); + this._onDidDisposeSession.fire({ sessionId, reason: 'cleared' }); } registerProvider(provider: IChatProvider): IDisposable { From 00c04b0cdb427a7138b055a8566975947c36882d Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 19 Oct 2023 09:09:48 +0200 Subject: [PATCH 256/290] Adding inline chat sparkle decoration in the gutter which spawns inline chat (#195471) Adding inline chat sparkle decoration --- .../browser/breakpointEditorContribution.ts | 2 +- .../browser/inlineChat.contribution.ts | 4 +- .../contrib/inlineChat/browser/inlineChat.css | 14 ++ .../browser/inlineChatDecorations.ts | 141 ++++++++++++++++++ .../contrib/inlineChat/common/inlineChat.ts | 6 + 5 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 src/vs/workbench/contrib/inlineChat/browser/inlineChatDecorations.ts diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index c6126663925..4a412b0e3df 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -474,7 +474,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi if (decorations) { for (const { options } of decorations) { const clz = options.glyphMarginClassName; - if (clz && (!clz.includes('codicon-') || clz.includes('codicon-testing-') || clz.includes('codicon-merge-') || clz.includes('codicon-arrow-') || clz.includes('codicon-loading') || clz.includes('codicon-fold'))) { + if (clz && (!clz.includes('codicon-') || clz.includes('codicon-testing-') || clz.includes('codicon-merge-') || clz.includes('codicon-arrow-') || clz.includes('codicon-loading') || clz.includes('codicon-fold') || clz.includes('codicon-inline-chat'))) { return false; } } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts index 046890e899f..bf51f1ca521 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts @@ -7,7 +7,7 @@ import { registerAction2 } from 'vs/platform/actions/common/actions'; import { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController'; import * as InlineChatActions from 'vs/workbench/contrib/inlineChat/browser/inlineChatActions'; -import { IInlineChatService, INLINE_CHAT_ID, INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { IInlineChatService, INLINE_CHAT_DECORATIONS_ID, INLINE_CHAT_ID, INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { InlineChatServiceImpl } from 'vs/workbench/contrib/inlineChat/common/inlineChatServiceImpl'; import { IInlineChatSessionService, InlineChatSessionService } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; @@ -16,12 +16,14 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { InlineChatNotebookContribution } from 'vs/workbench/contrib/inlineChat/browser/inlineChatNotebook'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { InlineChatAccessibleViewContribution } from './inlineChatAccessibleView'; +import { InlineChatDecorationsContribution } from 'vs/workbench/contrib/inlineChat/browser/inlineChatDecorations'; registerSingleton(IInlineChatService, InlineChatServiceImpl, InstantiationType.Delayed); registerSingleton(IInlineChatSessionService, InlineChatSessionService, InstantiationType.Delayed); registerEditorContribution(INLINE_CHAT_ID, InlineChatController, EditorContributionInstantiation.Eager); // EAGER because of notebook dispose/create of editors registerEditorContribution(INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID, InlineChatActions.InlineAccessibilityHelpContribution, EditorContributionInstantiation.Eventually); +registerEditorContribution(INLINE_CHAT_DECORATIONS_ID, InlineChatDecorationsContribution, EditorContributionInstantiation.AfterFirstRender); registerAction2(InlineChatActions.StartSessionAction); registerAction2(InlineChatActions.UnstashSessionAction); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css index 9ffe8efc5bb..356105ef6ad 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css @@ -328,3 +328,17 @@ justify-content: space-between; padding: 3px 6px 3px 0; } + +/* gutter decoration */ + +.monaco-editor .glyph-margin-widgets .cgmr.codicon-inline-chat { + display: block; + cursor: pointer; + opacity: 0.5; + transition: opacity .2s ease-in-out; +} + +.monaco-editor .glyph-margin-widgets .cgmr.codicon-inline-chat:hover { + opacity: 1; +} + diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatDecorations.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatDecorations.ts new file mode 100644 index 00000000000..c6f28ad6e29 --- /dev/null +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatDecorations.ts @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Codicon } from 'vs/base/common/codicons'; +import { ThemeIcon } from 'vs/base/common/themables'; +import { IActiveCodeEditor, ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; +import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { GlyphMarginLane, IModelDecorationsChangeAccessor, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; +import { localize } from 'vs/nls'; +import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; +import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { GutterActionsRegistry } from 'vs/workbench/contrib/codeEditor/browser/editorLineNumberMenu'; +import { Action } from 'vs/base/common/actions'; +import { IInlineChatService } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { Iterable } from 'vs/base/common/iterator'; +import { Range } from 'vs/editor/common/core/range'; + +const GUTTER_INLINE_CHAT_ICON = registerIcon('inline-chat', Codicon.sparkle, localize('startInlineChatIcon', 'Icon which spawns the inline chat from the gutter')); + +export class InlineChatDecorationsContribution extends Disposable implements IEditorContribution { + + private _localToDispose = new DisposableStore(); + private _gutterDecorationID: string | undefined; + + public static readonly GUTTER_SETTING_ID = 'inlineChat.showGutterIcon'; + private static readonly GUTTER_ICON_CLASSNAME = 'codicon-inline-chat'; + private static readonly GUTTER_DECORATION = ModelDecorationOptions.register({ + description: 'inline-chat-decoration', + glyphMarginClassName: ThemeIcon.asClassName(GUTTER_INLINE_CHAT_ICON), + glyphMargin: { position: GlyphMarginLane.Left }, + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + }); + + constructor( + private readonly _editor: ICodeEditor, + @IInlineChatService private readonly _inlineChatService: IInlineChatService, + @IConfigurationService private readonly _configurationService: IConfigurationService + ) { + super(); + this._register(this._configurationService.onDidChangeConfiguration((e: IConfigurationChangeEvent) => { + if (!e.affectsConfiguration(InlineChatDecorationsContribution.GUTTER_SETTING_ID)) { + return; + } + this._onEnablementOrModelChanged(); + })); + this._register(this._inlineChatService.onDidChangeProviders(() => this._onEnablementOrModelChanged())); + this._register(this._editor.onDidChangeModel(() => this._onEnablementOrModelChanged())); + } + + private _onEnablementOrModelChanged(): void { + // cancels the scheduler, removes editor listeners / removes decoration + this._localToDispose.clear(); + if (!this._editor.hasModel() || !this._isSettingEnabled() || !this._hasProvider()) { + return; + } + const editor = this._editor; + const decorationUpdateScheduler = new RunOnceScheduler(() => this._onSelectionOrContentChanged(editor), 200); + this._localToDispose.add(decorationUpdateScheduler); + this._localToDispose.add(this._editor.onDidChangeCursorSelection(() => decorationUpdateScheduler.schedule())); + this._localToDispose.add(this._editor.onDidChangeModelContent(() => decorationUpdateScheduler.schedule())); + this._localToDispose.add(this._editor.onMouseDown(async (e: IEditorMouseEvent) => { + if (!e.target.element?.classList.contains(InlineChatDecorationsContribution.GUTTER_ICON_CLASSNAME)) { + return; + } + InlineChatController.get(this._editor)?.run(); + })); + this._localToDispose.add({ + dispose: () => { + if (this._gutterDecorationID) { + this._removeGutterDecoration(this._gutterDecorationID); + } + } + }); + } + + private _onSelectionOrContentChanged(editor: IActiveCodeEditor): void { + const selection = editor.getSelection(); + const isEnabled = selection.isEmpty() && /^\s*$/g.test(editor.getModel().getLineContent(selection.startLineNumber)); + if (isEnabled) { + if (this._gutterDecorationID === undefined) { + this._addGutterDecoration(selection.startLineNumber); + } else { + const decorationRange = editor.getModel().getDecorationRange(this._gutterDecorationID); + if (decorationRange?.startLineNumber !== selection.startLineNumber) { + this._updateGutterDecoration(this._gutterDecorationID, selection.startLineNumber); + } + } + } else if (this._gutterDecorationID) { + this._removeGutterDecoration(this._gutterDecorationID); + } + } + + private _isSettingEnabled(): boolean { + return this._configurationService.getValue(InlineChatDecorationsContribution.GUTTER_SETTING_ID); + } + + private _hasProvider(): boolean { + return !Iterable.isEmpty(this._inlineChatService.getAllProvider()); + } + + private _addGutterDecoration(lineNumber: number) { + this._editor.changeDecorations((accessor: IModelDecorationsChangeAccessor) => { + this._gutterDecorationID = accessor.addDecoration(new Range(lineNumber, 0, lineNumber, 0), InlineChatDecorationsContribution.GUTTER_DECORATION); + }); + } + + private _removeGutterDecoration(decorationId: string) { + this._editor.changeDecorations((accessor: IModelDecorationsChangeAccessor) => { + accessor.removeDecoration(decorationId); + this._gutterDecorationID = undefined; + }); + } + + private _updateGutterDecoration(decorationId: string, lineNumber: number) { + this._editor.changeDecorations((accessor: IModelDecorationsChangeAccessor) => { + accessor.changeDecoration(decorationId, new Range(lineNumber, 0, lineNumber, 0)); + }); + } + + override dispose() { + super.dispose(); + this._localToDispose.dispose(); + } +} + +GutterActionsRegistry.registerGutterActionsGenerator(({ lineNumber, editor, accessor }, result) => { + const configurationService = accessor.get(IConfigurationService); + result.push(new Action( + 'inlineChat.toggleShowGutterIcon', + localize('toggleShowGutterIcon', "Toggle Inline Chat Icon"), + undefined, + true, + () => { configurationService.updateValue(InlineChatDecorationsContribution.GUTTER_SETTING_ID, !configurationService.getValue(InlineChatDecorationsContribution.GUTTER_SETTING_ID)); } + )); +}); diff --git a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts index e358d1368b8..449d5e5884a 100644 --- a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts +++ b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts @@ -120,6 +120,7 @@ export interface IInlineChatService { export const INLINE_CHAT_ID = 'interactiveEditor'; export const INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID = 'interactiveEditorAccessiblityHelp'; +export const INLINE_CHAT_DECORATIONS_ID = 'interactiveEditorDecorations'; export const CTX_INLINE_CHAT_HAS_PROVIDER = new RawContextKey('inlineChatHasProvider', false, localize('inlineChatHasProvider', "Whether a provider for interactive editors exists")); export const CTX_INLINE_CHAT_VISIBLE = new RawContextKey('inlineChatVisible', false, localize('inlineChatVisible', "Whether the interactive editor input is visible")); @@ -206,6 +207,11 @@ Registry.as(Extensions.Configuration).registerConfigurat description: localize('showDiff', "Enable/disable showing the diff when edits are generated. Works only with inlineChat.mode equal to live or livePreview."), default: true, type: 'boolean' + }, + 'inlineChat.showGutterIcon': { + description: localize('showGutterIcon', "Show/hide a gutter icon for spawning inline chat on empty lines."), + default: true, + type: 'boolean' } } }); From 315279f5c72c881eef2e76678d55e7648a412360 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 19 Oct 2023 07:33:32 +0200 Subject: [PATCH 257/290] aux window - add action to split window side by side --- src/vs/platform/native/common/native.ts | 3 +- .../electron-main/nativeHostMainService.ts | 15 ++++- src/vs/platform/window/common/window.ts | 7 +++ .../platform/windows/electron-main/windows.ts | 15 +++-- .../browser/parts/editor/editorParts.ts | 5 +- .../electron-sandbox/actions/windowActions.ts | 61 +++++++++++++++++++ .../electron-sandbox/desktop.contribution.ts | 7 ++- .../browser/auxiliaryWindowService.ts | 18 +++++- .../auxiliaryWindowService.ts | 12 +++- .../editor/common/editorGroupsService.ts | 5 +- .../electron-sandbox/workbenchTestServices.ts | 3 +- 11 files changed, 133 insertions(+), 18 deletions(-) diff --git a/src/vs/platform/native/common/native.ts b/src/vs/platform/native/common/native.ts index cf36862e04f..6b2d0f538b4 100644 --- a/src/vs/platform/native/common/native.ts +++ b/src/vs/platform/native/common/native.ts @@ -12,7 +12,7 @@ import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IV8Profile } from 'vs/platform/profiling/common/profiling'; import { IPartsSplash } from 'vs/platform/theme/common/themeService'; -import { IColorScheme, IOpenedWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IWindowOpenable } from 'vs/platform/window/common/window'; +import { IColorScheme, IOpenedWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IRectangle, IWindowOpenable } from 'vs/platform/window/common/window'; export interface ICPUProperties { model: string; @@ -76,6 +76,7 @@ export interface ICommonNativeHostService { unmaximizeWindow(): Promise; minimizeWindow(): Promise; moveWindowTop(options?: { targetWindowId?: number }): Promise; + positionWindow(position: IRectangle, options?: { targetWindowId?: number }): Promise; /** * Only supported on Windows and macOS. Updates the window controls to match the title bar size. diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index b25b5e92ecd..92855b5ae24 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -33,7 +33,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IPartsSplash } from 'vs/platform/theme/common/themeService'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { ICodeWindow } from 'vs/platform/window/electron-main/window'; -import { IColorScheme, IOpenedWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IWindowOpenable } from 'vs/platform/window/common/window'; +import { IColorScheme, IOpenedWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IRectangle, IWindowOpenable } from 'vs/platform/window/common/window'; import { getFocusedOrLastActiveWindow, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; import { isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; @@ -224,6 +224,19 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } } + async positionWindow(firstArg: number | undefined, position: IRectangle, options?: { targetWindowId?: number | undefined } | undefined): Promise { + const window = this.windowById(options?.targetWindowId) ?? this.codeWindowById(firstArg); + if (window?.win) { + if (window.win.isFullScreen()) { + const fullscreenLeftFuture = Event.toPromise(Event.once(Event.fromNodeEventEmitter(window.win, 'leave-full-screen'))); + window.win.setFullScreen(false); + await fullscreenLeftFuture; + } + + window.win.setBounds(position); + } + } + async updateWindowControls(windowId: number | undefined, options: { height?: number; backgroundColor?: string; foregroundColor?: string }): Promise { const window = this.codeWindowById(windowId); if (window) { diff --git a/src/vs/platform/window/common/window.ts b/src/vs/platform/window/common/window.ts index 5762b3c380b..4e7a1872b0e 100644 --- a/src/vs/platform/window/common/window.ts +++ b/src/vs/platform/window/common/window.ts @@ -24,6 +24,13 @@ export const WindowMinimumSize = { HEIGHT: 270 }; +export interface IRectangle { + readonly x: number; + readonly y: number; + readonly width: number; + readonly height: number; +} + export interface IBaseOpenWindowsOptions { /** diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index bc30770d0b4..dd832b583fd 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -9,7 +9,7 @@ import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/co import { URI } from 'vs/base/common/uri'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { ICodeWindow, defaultWindowState } from 'vs/platform/window/electron-main/window'; +import { ICodeWindow, IWindowState } from 'vs/platform/window/electron-main/window'; import { IOpenEmptyWindowOptions, IWindowOpenable, IWindowSettings, WindowMinimumSize, zoomLevelToZoomFactor } from 'vs/platform/window/common/window'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -111,7 +111,7 @@ export interface IOpenConfiguration extends IBaseOpenConfiguration { export interface IOpenEmptyConfiguration extends IBaseOpenConfiguration { } -export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowState = defaultWindowState(), overrides?: BrowserWindowConstructorOptions): BrowserWindowConstructorOptions & { experimentalDarkMode: boolean } { +export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowState?: IWindowState, overrides?: BrowserWindowConstructorOptions): BrowserWindowConstructorOptions & { experimentalDarkMode: boolean } { const themeMainService = accessor.get(IThemeMainService); const productService = accessor.get(IProductService); const configurationService = accessor.get(IConfigurationService); @@ -120,10 +120,6 @@ export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowSt const windowSettings = configurationService.getValue('window'); const options: BrowserWindowConstructorOptions & { experimentalDarkMode: boolean } = { - width: windowState.width, - height: windowState.height, - x: windowState.x, - y: windowState.y, backgroundColor: themeMainService.getBackgroundColor(), minWidth: WindowMinimumSize.WIDTH, minHeight: WindowMinimumSize.HEIGHT, @@ -143,6 +139,13 @@ export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowSt experimentalDarkMode: true }; + if (windowState) { + options.x = windowState.x; + options.y = windowState.y; + options.width = windowState.width; + options.height = windowState.height; + } + if (isLinux) { options.icon = join(environmentMainService.appRoot, 'resources/linux/code.png'); // always on Linux } else if (isWindows && !environmentMainService.isBuilt) { diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 20d39b64adc..3aa3974137d 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -14,6 +14,7 @@ import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/ import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IAuxiliaryWindowService } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { IRectangle } from 'vs/platform/window/common/window'; export class EditorParts extends Disposable implements IEditorGroupsService, IEditorPartsView { @@ -37,10 +38,10 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd //#region Auxiliary Editor Parts - createAuxiliaryEditorPart(): IAuxiliaryEditorPart { + createAuxiliaryEditorPart(options?: { position?: IRectangle }): IAuxiliaryEditorPart { const disposables = new DisposableStore(); - const auxiliaryWindow = disposables.add(this.auxiliaryWindowService.open()); + const auxiliaryWindow = disposables.add(this.auxiliaryWindowService.open(options)); disposables.add(Event.once(auxiliaryWindow.onDidClose)(() => disposables.dispose())); const partContainer = document.createElement('div'); diff --git a/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/src/vs/workbench/electron-sandbox/actions/windowActions.ts index 95c4100ff13..771de64a129 100644 --- a/src/vs/workbench/electron-sandbox/actions/windowActions.ts +++ b/src/vs/workbench/electron-sandbox/actions/windowActions.ts @@ -26,6 +26,11 @@ import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { isMacintosh } from 'vs/base/common/platform'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { getActiveWindow } from 'vs/base/browser/dom'; +import { isAuxiliaryWindow } from 'vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; export class CloseWindowAction extends Action2 { @@ -333,3 +338,59 @@ export const ToggleWindowTabsBarHandler: ICommandHandler = function (accessor: S return accessor.get(INativeHostService).toggleWindowTabsBar(); }; + +export class ExperimentalSplitWindowAction extends Action2 { + + constructor() { + super({ + id: 'workbench.action.experimentalSplitWindowAction', + title: { + value: localize('splitWindow', "Split Window (Experimental)"), + mnemonicTitle: localize({ key: 'miSplitWindow', comment: ['&& denotes a mnemonic'] }, "&&Split Window (Experimental)"), + original: 'Split Window (Experimental)' + }, + category: Categories.View, + f1: true + }); + } + + override async run(accessor: ServicesAccessor): Promise { + const editorService = accessor.get(IEditorService); + const editorGroupService = accessor.get(IEditorGroupsService); + const nativeHostService = accessor.get(INativeHostService); + const environmentService = accessor.get(INativeWorkbenchEnvironmentService); + + let activeWindowId: number; + const activeWindow = getActiveWindow(); + if (isAuxiliaryWindow(activeWindow)) { + activeWindowId = await activeWindow.vscodeWindowId; + } else { + activeWindowId = environmentService.window.id; + } + + // First position the active window which may involve + // leaving fullscreen mode and then split it. + await nativeHostService.positionWindow({ + x: 0, + y: 0, + width: activeWindow.screen.availWidth / 2, + height: activeWindow.screen.availHeight + }, { targetWindowId: activeWindowId }); + + // Then create a new window next to the active window + const auxiliaryEditorPart = editorGroupService.createAuxiliaryEditorPart({ + position: { + x: activeWindow.screen.availWidth / 2, + y: 0, + width: activeWindow.screen.availWidth / 2, + height: activeWindow.screen.availHeight + } + }); + + // Finally copy over the active editor if any + const activeEditorPane = editorService.activeEditorPane; + if (activeEditorPane) { + activeEditorPane.group.copyEditor(activeEditorPane.input, auxiliaryEditorPart.activeGroup); + } + } +} diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index f904efaafae..829ef06961c 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -10,7 +10,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { ConfigureRuntimeArgumentsAction, ToggleDevToolsAction, ReloadWindowWithExtensionsDisabledAction, OpenUserDataFolderAction } from 'vs/workbench/electron-sandbox/actions/developerActions'; -import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseWindowAction, SwitchWindowAction, QuickSwitchWindowAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-sandbox/actions/windowActions'; +import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseWindowAction, SwitchWindowAction, QuickSwitchWindowAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler, ExperimentalSplitWindowAction } from 'vs/workbench/electron-sandbox/actions/windowActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -27,6 +27,7 @@ import { ShutdownReason } from 'vs/workbench/services/lifecycle/common/lifecycle import { NativeWindow } from 'vs/workbench/electron-sandbox/window'; import { ModifierKeyEmitter } from 'vs/base/browser/dom'; import { applicationConfigurationNodeBase, securityConfigurationNodeBase } from 'vs/workbench/common/configuration'; +import product from 'vs/platform/product/common/product'; // Actions (function registerActions(): void { @@ -40,6 +41,10 @@ import { applicationConfigurationNodeBase, securityConfigurationNodeBase } from registerAction2(SwitchWindowAction); registerAction2(QuickSwitchWindowAction); registerAction2(CloseWindowAction); + if (product.quality !== 'stable') { + // TODO@bpasero revisit + registerAction2(ExperimentalSplitWindowAction); + } if (isMacintosh) { // macOS: behave like other native apps that have documents diff --git a/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts b/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts index c6daa32b996..fbf577298d8 100644 --- a/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts +++ b/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts @@ -12,6 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { onUnexpectedError } from 'vs/base/common/errors'; import { isWeb } from 'vs/base/common/platform'; +import { IRectangle } from 'vs/platform/window/common/window'; export const IAuxiliaryWindowService = createDecorator('auxiliaryWindowService'); @@ -19,7 +20,7 @@ export interface IAuxiliaryWindowService { readonly _serviceBrand: undefined; - open(): IAuxiliaryWindow; + open(options?: { position?: IRectangle }): IAuxiliaryWindow; } export interface IAuxiliaryWindow extends IDisposable { @@ -42,10 +43,10 @@ export class BrowserAuxiliaryWindowService implements IAuxiliaryWindowService { @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService ) { } - open(): IAuxiliaryWindow { + open(options?: { position?: IRectangle }): IAuxiliaryWindow { const disposables = new DisposableStore(); - const auxiliaryWindow = assertIsDefined(window.open('about:blank')?.window) as AuxiliaryWindow; + const auxiliaryWindow = this.doOpen(options); disposables.add(registerWindow(auxiliaryWindow)); disposables.add(toDisposable(() => auxiliaryWindow.close())); @@ -60,6 +61,17 @@ export class BrowserAuxiliaryWindowService implements IAuxiliaryWindowService { }; } + private doOpen(options?: { position?: IRectangle }): AuxiliaryWindow { + let auxiliaryWindow: Window | null; + if (options?.position) { + auxiliaryWindow = window.open('about:blank', undefined, `left=${options.position.x},top=${options.position.y},width=${options.position.width},height=${options.position.height}`); + } else { + auxiliaryWindow = window.open('about:blank'); + } + + return assertIsDefined(auxiliaryWindow).window as AuxiliaryWindow; + } + protected create(auxiliaryWindow: AuxiliaryWindow, disposables: DisposableStore) { this.patchMethods(auxiliaryWindow); diff --git a/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts b/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts index 55e441436f0..3d931ca6fd1 100644 --- a/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts +++ b/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts @@ -14,13 +14,15 @@ import { INativeHostService } from 'vs/platform/native/common/native'; import { DeferredPromise } from 'vs/base/common/async'; type AuxiliaryWindow = BaseAuxiliaryWindow & { + readonly vscodeWindowId: Promise; + moveTop: () => void; }; export function isAuxiliaryWindow(obj: unknown): obj is AuxiliaryWindow { const candidate = obj as AuxiliaryWindow | undefined; - return typeof candidate?.moveTop === 'function'; + return candidate?.vscodeWindowId instanceof Promise && typeof candidate?.moveTop === 'function'; } export class NativeAuxiliaryWindowService extends BrowserAuxiliaryWindowService { @@ -52,6 +54,14 @@ export class NativeAuxiliaryWindowService extends BrowserAuxiliaryWindowService windowId.complete(await getGlobals(auxiliaryWindow)?.ipcRenderer.invoke('vscode:getWindowId')); })(); + // Add a `windowId` property + Object.defineProperty(auxiliaryWindow, 'vscodeWindowId', { + value: windowId.p, + writable: false, + enumerable: false, + configurable: false + }); + // Enable `window.focus()` to work in Electron by // asking the main process to focus the window. const that = this; diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 0ae10e6268c..df939bcb94f 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -14,6 +14,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { URI } from 'vs/base/common/uri'; import { IGroupModelChangeEvent } from 'vs/workbench/common/editor/editorGroupModel'; +import { IRectangle } from 'vs/platform/window/common/window'; export const IEditorGroupsService = createDecorator('editorGroupsService'); @@ -479,9 +480,9 @@ export interface IEditorGroupsService extends IEditorGroupsContainer { /** * Opens a new window with a full editor part instantiated - * in there. + * in there at the optional position on screen. */ - createAuxiliaryEditorPart(): IAuxiliaryEditorPart; + createAuxiliaryEditorPart(options?: { position?: IRectangle }): IAuxiliaryEditorPart; } export const enum OpenEditorContext { diff --git a/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts b/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts index 542f59259ed..a6e43ee5000 100644 --- a/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts @@ -12,7 +12,7 @@ import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IFileDialogService, INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; import { IPartsSplash } from 'vs/platform/theme/common/themeService'; -import { IOpenedWindow, IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IColorScheme } from 'vs/platform/window/common/window'; +import { IOpenedWindow, IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IColorScheme, IRectangle } from 'vs/platform/window/common/window'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -94,6 +94,7 @@ export class TestNativeHostService implements INativeHostService { async unmaximizeWindow(): Promise { } async minimizeWindow(): Promise { } async moveWindowTop(options?: { targetWindowId?: number }): Promise { } + async positionWindow(position: IRectangle, options?: { targetWindowId?: number }): Promise { } async updateWindowControls(options: { height?: number; backgroundColor?: string; foregroundColor?: string }): Promise { } async setMinimumSize(width: number | undefined, height: number | undefined): Promise { } async saveWindowSplash(value: IPartsSplash): Promise { } From eb0575e464a696a402a6722dac8fa1bb4f35c86e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 19 Oct 2023 09:16:12 +0200 Subject: [PATCH 258/290] aux window - improve popup block situation --- build/lib/i18n.resources.json | 4 ++ .../browser/parts/editor/editorActions.ts | 2 +- .../browser/parts/editor/editorParts.ts | 4 +- .../electron-sandbox/actions/windowActions.ts | 2 +- .../browser/auxiliaryWindowService.ts | 55 ++++++++++++++----- .../auxiliaryWindowService.ts | 6 +- .../editor/common/editorGroupsService.ts | 2 +- .../test/browser/workbenchTestServices.ts | 4 +- 8 files changed, 57 insertions(+), 22 deletions(-) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 65f37d5e283..fd37a4d1431 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -82,6 +82,10 @@ "name": "vs/workbench/services/assignment", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/auxiliaryWindow", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/extensions", "project": "vscode-workbench" diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 9838d2b99c5..86e2ec7c78a 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -2448,7 +2448,7 @@ export class ExperimentalMoveEditorIntoNewWindowAction extends Action2 { return; } - const auxiliaryEditorPart = editorGroupService.createAuxiliaryEditorPart(); + const auxiliaryEditorPart = await editorGroupService.createAuxiliaryEditorPart(); activeEditorPane.group.moveEditor(activeEditorPane.input, auxiliaryEditorPart.activeGroup); } diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 3aa3974137d..08297cc6210 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -38,10 +38,10 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd //#region Auxiliary Editor Parts - createAuxiliaryEditorPart(options?: { position?: IRectangle }): IAuxiliaryEditorPart { + async createAuxiliaryEditorPart(options?: { position?: IRectangle }): Promise { const disposables = new DisposableStore(); - const auxiliaryWindow = disposables.add(this.auxiliaryWindowService.open(options)); + const auxiliaryWindow = disposables.add(await this.auxiliaryWindowService.open(options)); disposables.add(Event.once(auxiliaryWindow.onDidClose)(() => disposables.dispose())); const partContainer = document.createElement('div'); diff --git a/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/src/vs/workbench/electron-sandbox/actions/windowActions.ts index 771de64a129..b174c469230 100644 --- a/src/vs/workbench/electron-sandbox/actions/windowActions.ts +++ b/src/vs/workbench/electron-sandbox/actions/windowActions.ts @@ -378,7 +378,7 @@ export class ExperimentalSplitWindowAction extends Action2 { }, { targetWindowId: activeWindowId }); // Then create a new window next to the active window - const auxiliaryEditorPart = editorGroupService.createAuxiliaryEditorPart({ + const auxiliaryEditorPart = await editorGroupService.createAuxiliaryEditorPart({ position: { x: activeWindow.screen.availWidth / 2, y: 0, diff --git a/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts b/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts index fbf577298d8..e422b90a2e3 100644 --- a/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts +++ b/src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts @@ -3,16 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { localize } from 'vs/nls'; import { Emitter, Event } from 'vs/base/common/event'; -import { Dimension, EventHelper, EventType, addDisposableListener, copyAttributes, getClientArea, position, registerWindow, size, trackAttributes } from 'vs/base/browser/dom'; +import { Dimension, EventHelper, EventType, addDisposableListener, copyAttributes, getActiveWindow, getClientArea, position, registerWindow, size, trackAttributes } from 'vs/base/browser/dom'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { assertIsDefined } from 'vs/base/common/types'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { onUnexpectedError } from 'vs/base/common/errors'; import { isWeb } from 'vs/base/common/platform'; import { IRectangle } from 'vs/platform/window/common/window'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import Severity from 'vs/base/common/severity'; export const IAuxiliaryWindowService = createDecorator('auxiliaryWindowService'); @@ -20,7 +22,7 @@ export interface IAuxiliaryWindowService { readonly _serviceBrand: undefined; - open(options?: { position?: IRectangle }): IAuxiliaryWindow; + open(options?: { position?: IRectangle }): Promise; } export interface IAuxiliaryWindow extends IDisposable { @@ -39,14 +41,21 @@ export class BrowserAuxiliaryWindowService implements IAuxiliaryWindowService { declare readonly _serviceBrand: undefined; + private static readonly DEFAULT_SIZE = { width: 800, height: 600 }; + constructor( - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IDialogService private readonly dialogService: IDialogService ) { } - open(options?: { position?: IRectangle }): IAuxiliaryWindow { + async open(options?: { position?: IRectangle }): Promise { const disposables = new DisposableStore(); - const auxiliaryWindow = this.doOpen(options); + const auxiliaryWindow = await this.doOpen(options); + if (!auxiliaryWindow) { + throw new Error(localize('unableToOpenWindowError', "Unable to open a new window.")); + } + disposables.add(registerWindow(auxiliaryWindow)); disposables.add(toDisposable(() => auxiliaryWindow.close())); @@ -61,15 +70,35 @@ export class BrowserAuxiliaryWindowService implements IAuxiliaryWindowService { }; } - private doOpen(options?: { position?: IRectangle }): AuxiliaryWindow { - let auxiliaryWindow: Window | null; - if (options?.position) { - auxiliaryWindow = window.open('about:blank', undefined, `left=${options.position.x},top=${options.position.y},width=${options.position.width},height=${options.position.height}`); - } else { - auxiliaryWindow = window.open('about:blank'); + private async doOpen(options?: { position?: IRectangle }): Promise { + let position: IRectangle | undefined = options?.position; + if (!position) { + const activeWindow = getActiveWindow(); + position = { + x: activeWindow.screen.availWidth / 2 - BrowserAuxiliaryWindowService.DEFAULT_SIZE.width / 2, + y: activeWindow.screen.availHeight / 2 - BrowserAuxiliaryWindowService.DEFAULT_SIZE.height / 2, + width: BrowserAuxiliaryWindowService.DEFAULT_SIZE.width, + height: BrowserAuxiliaryWindowService.DEFAULT_SIZE.height + }; } - return assertIsDefined(auxiliaryWindow).window as AuxiliaryWindow; + const auxiliaryWindow = window.open('about:blank', undefined, `popup=yes,left=${position.x},top=${position.y},width=${position.width},height=${position.height}`); + if (!auxiliaryWindow && isWeb) { + return (await this.dialogService.prompt({ + type: Severity.Warning, + message: localize('unableToOpenWindow', "The browser interrupted the opening of a new window. Press 'Retry' to try again."), + detail: localize('unableToOpenWindowDetail', "To avoid this problem in the future, please ensure to allow popups for this website."), + buttons: [ + { + label: localize({ key: 'retry', comment: ['&& denotes a mnemonic'] }, "&&Retry"), + run: () => this.doOpen(options) + } + ], + cancelButton: true + })).result; + } + + return auxiliaryWindow?.window; } protected create(auxiliaryWindow: AuxiliaryWindow, disposables: DisposableStore) { diff --git a/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts b/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts index 3d931ca6fd1..c348bb92047 100644 --- a/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts +++ b/src/vs/workbench/services/auxiliaryWindow/electron-sandbox/auxiliaryWindowService.ts @@ -12,6 +12,7 @@ import { IWindowsConfiguration } from 'vs/platform/window/common/window'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { INativeHostService } from 'vs/platform/native/common/native'; import { DeferredPromise } from 'vs/base/common/async'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; type AuxiliaryWindow = BaseAuxiliaryWindow & { readonly vscodeWindowId: Promise; @@ -30,9 +31,10 @@ export class NativeAuxiliaryWindowService extends BrowserAuxiliaryWindowService constructor( @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IConfigurationService private readonly configurationService: IConfigurationService, - @INativeHostService private readonly nativeHostService: INativeHostService + @INativeHostService private readonly nativeHostService: INativeHostService, + @IDialogService dialogService: IDialogService ) { - super(layoutService); + super(layoutService, dialogService); } protected override create(auxiliaryWindow: AuxiliaryWindow, disposables: DisposableStore) { diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index df939bcb94f..1b48ec30bca 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -482,7 +482,7 @@ export interface IEditorGroupsService extends IEditorGroupsContainer { * Opens a new window with a full editor part instantiated * in there at the optional position on screen. */ - createAuxiliaryEditorPart(options?: { position?: IRectangle }): IAuxiliaryEditorPart; + createAuxiliaryEditorPart(options?: { position?: IRectangle }): Promise; } export const enum OpenEditorContext { diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index d1ba09d3c00..315f909a7ed 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -869,7 +869,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { readonly activePart = this; readonly mainPart = this; registerEditorPart(part: any): IDisposable { return Disposable.None; } - createAuxiliaryEditorPart(): IAuxiliaryEditorPart { throw new Error('Method not implemented.'); } + createAuxiliaryEditorPart(): Promise { throw new Error('Method not implemented.'); } } export class TestEditorGroupView implements IEditorGroupView { @@ -1753,7 +1753,7 @@ export class TestEditorPart extends MainEditorPart implements IEditorGroupsServi return Disposable.None; } - createAuxiliaryEditorPart(): IAuxiliaryEditorPart { + createAuxiliaryEditorPart(): Promise { throw new Error('Method not implemented.'); } From 5f9481b9a90d65bc677a76e88bec828c70945d25 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 19 Oct 2023 10:53:12 +0200 Subject: [PATCH 259/290] polish view header (#195971) --- src/vs/base/browser/ui/splitview/paneview.css | 4 ++++ src/vs/base/browser/ui/splitview/paneview.ts | 12 ++++++++++-- .../workbench/browser/parts/views/viewPane.ts | 17 +++++++++++++---- .../browser/parts/views/viewPaneContainer.ts | 1 + 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/splitview/paneview.css b/src/vs/base/browser/ui/splitview/paneview.css index 81f66e998ab..62cb3fe642c 100644 --- a/src/vs/base/browser/ui/splitview/paneview.css +++ b/src/vs/base/browser/ui/splitview/paneview.css @@ -31,6 +31,10 @@ box-sizing: border-box; } +.monaco-pane-view .pane > .pane-header.not-collapsible { + cursor: default; +} + .monaco-pane-view .pane > .pane-header > .title { text-transform: uppercase; } diff --git a/src/vs/base/browser/ui/splitview/paneview.ts b/src/vs/base/browser/ui/splitview/paneview.ts index 5ae5a44f37d..2747c01eff2 100644 --- a/src/vs/base/browser/ui/splitview/paneview.ts +++ b/src/vs/base/browser/ui/splitview/paneview.ts @@ -317,14 +317,22 @@ export abstract class Pane extends Disposable implements IView { protected updateHeader(): void { const expanded = !this.headerVisible || this.isExpanded(); + if (this.collapsible) { + this.header.setAttribute('tabindex', '0'); + this.header.setAttribute('role', 'button'); + } else { + this.header.removeAttribute('tabindex'); + this.header.removeAttribute('role'); + } + this.header.style.lineHeight = `${this.headerSize}px`; this.header.classList.toggle('hidden', !this.headerVisible); this.header.classList.toggle('expanded', expanded); this.header.classList.toggle('not-collapsible', !this.collapsible); this.header.setAttribute('aria-expanded', String(expanded)); - this.header.style.color = this.styles.headerForeground ?? ''; - this.header.style.backgroundColor = this.styles.headerBackground ?? ''; + this.header.style.color = this.collapsible ? this.styles.headerForeground ?? '' : ''; + this.header.style.backgroundColor = (this.collapsible ? this.styles.headerBackground : 'transparent') ?? ''; this.header.style.borderTop = this.styles.headerBorder && this.orientation === Orientation.VERTICAL ? `1px solid ${this.styles.headerBorder}` : ''; this.element.style.borderLeft = this.styles.leftBorder && this.orientation === Orientation.HORIZONTAL ? `1px solid ${this.styles.leftBorder}` : ''; } diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index 7331134d3c3..870f0980ef2 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -406,10 +406,7 @@ export abstract class ViewPane extends Pane implements IView { if (changed) { this._onDidChangeBodyVisibility.fire(expanded); } - if (this.twistiesContainer) { - this.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded))); - this.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded))); - } + this.updateTwistyIcon(); return changed; } @@ -459,6 +456,18 @@ export abstract class ViewPane extends Pane implements IView { this.updateActionsVisibility(); } + protected override updateHeader(): void { + super.updateHeader(); + this.updateTwistyIcon(); + } + + private updateTwistyIcon(): void { + if (this.twistiesContainer) { + this.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!this._expanded))); + this.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(this._expanded))); + } + } + protected getTwistyIcon(expanded: boolean): ThemeIcon { return expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon; } diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index b744ee98eed..4664b61c95d 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -1065,6 +1065,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { this.paneItems[0].pane.collapsible = true; } else { if (this.paneItems.length === 1) { + this.paneItems[0].pane.headerVisible = true; this.paneItems[0].pane.setExpanded(true); this.paneItems[0].pane.collapsible = false; } else { From 0b1e8b379dfb06beec92d6846224bfb7d72aa018 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 19 Oct 2023 10:53:34 +0200 Subject: [PATCH 260/290] fix #195973 (#195975) Adjust height and line-height of badge in titlebar and paneCompositePart --- src/vs/workbench/browser/parts/media/paneCompositePart.css | 3 ++- .../workbench/browser/parts/titlebar/media/titlebarpart.css | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/parts/media/paneCompositePart.css b/src/vs/workbench/browser/parts/media/paneCompositePart.css index b30eba09a97..428d7ea596f 100644 --- a/src/vs/workbench/browser/parts/media/paneCompositePart.css +++ b/src/vs/workbench/browser/parts/media/paneCompositePart.css @@ -177,7 +177,8 @@ font-size: 9px; font-weight: 600; min-width: 12px; - height: 11px; + height: 12px; + line-height: 12px; padding: 0 2px; border-radius: 16px; text-align: center; diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index a9f73b33351..d98f25eec30 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -444,12 +444,13 @@ .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content { position: absolute; - top: 11px; + top: 10px; right: 0px; font-size: 9px; font-weight: 600; min-width: 12px; - height: 11px; + height: 12px; + line-height: 12px; padding: 0 2px; border-radius: 16px; text-align: center; From 291ee48c5e48b30db363a11a0d682631b6a846f9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 19 Oct 2023 13:05:53 +0200 Subject: [PATCH 261/290] voice - reduce auto-accept delay (#195983) --- .../contrib/chat/electron-sandbox/actions/voiceChatActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index 33a5497c6b8..afc579f3103 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -260,7 +260,7 @@ class VoiceChatSessions { const speechToTextSession = session.disposables.add(this.speechService.createSpeechToTextSession(cts.token)); let transcription: string = ''; - const acceptTranscriptionScheduler = session.disposables.add(new RunOnceScheduler(() => session.controller.acceptInput(), 2000)); + const acceptTranscriptionScheduler = session.disposables.add(new RunOnceScheduler(() => session.controller.acceptInput(), 1200)); session.disposables.add(speechToTextSession.onDidChange(({ status, text }) => { if (cts.token.isCancellationRequested) { return; From 4d071818acd4093b1bb8f108ce743cb24b48b7b1 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Thu, 19 Oct 2023 15:06:10 +0200 Subject: [PATCH 262/290] Use the ID, not the label for unique comment controller ID (#195989) Part of microsoft/vscode-pull-request-github#5317 --- src/vs/workbench/api/browser/mainThreadComments.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 40f5cd9341b..7685218a12d 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -507,7 +507,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments } $registerCommentController(handle: number, id: string, label: string, extensionId: string): void { - const providerId = `${label}-${extensionId}`; + const providerId = `${id}-${extensionId}`; this._handlers.set(handle, providerId); const provider = new MainThreadCommentController(this._proxy, this._commentService, handle, providerId, id, label, {}); From 0f150853c7bb4afcb042da9763efef54d0215993 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 19 Oct 2023 15:54:50 +0200 Subject: [PATCH 263/290] Update inline chat functionality with markdown support streaming (#195992) --- src/vs/workbench/api/common/extHostInlineChat.ts | 5 +++-- .../inlineChat/browser/inlineChatController.ts | 14 +++++++++++--- .../inlineChat/browser/inlineChatSession.ts | 4 +++- .../contrib/inlineChat/common/inlineChat.ts | 1 + src/vscode-dts/vscode.proposed.interactive.d.ts | 1 + 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/common/extHostInlineChat.ts b/src/vs/workbench/api/common/extHostInlineChat.ts index 3699d824d2f..90b1900d4e8 100644 --- a/src/vs/workbench/api/common/extHostInlineChat.ts +++ b/src/vs/workbench/api/common/extHostInlineChat.ts @@ -153,7 +153,7 @@ export class ExtHostInteractiveEditor implements ExtHostInlineChatShape { let done = false; - const progress: vscode.Progress<{ message?: string; edits?: vscode.TextEdit[]; slashCommand?: vscode.InteractiveEditorSlashCommand }> = { + const progress: vscode.Progress = { report: async value => { if (!request.live) { throw new Error('Progress reporting is only supported for live sessions'); @@ -164,7 +164,8 @@ export class ExtHostInteractiveEditor implements ExtHostInlineChatShape { await this._proxy.$handleProgressChunk(request.requestId, { message: value.message, edits: value.edits?.map(typeConvert.TextEdit.from), - slashCommand: value.slashCommand?.command + slashCommand: value.slashCommand?.command, + markdownFragment: extHostTypes.MarkdownString.isMarkdownString(value.content) ? value.content.value : value.content }); } }; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index bb504a95533..f8f190fbfb3 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -37,6 +37,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { TextEdit } from 'vs/editor/common/languages'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { MarkdownString } from 'vs/base/common/htmlContent'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', @@ -552,6 +553,8 @@ export class InlineChatController implements IEditorContribution { this._chatAccessibilityService.acceptRequest(); const progressEdits: TextEdit[][] = []; + const markdownContents = new MarkdownString('', { supportThemeIcons: true, supportHtml: true, isTrusted: false }); + const progress = new AsyncProgress(async data => { this._log('received chunk', data, request); if (data.message) { @@ -572,6 +575,10 @@ export class InlineChatController implements IEditorContribution { await this._makeChanges(data.edits, true); await this._strategy?.renderProgressChanges(); } + if (data.markdownFragment) { + markdownContents.appendMarkdown(data.markdownFragment); + this._zone.value.widget.updateMarkdownMessage(markdownContents); + } }); const task = this._activeSession.provider.provideResponse(this._activeSession.session, request, progress, requestCts.token); this._log('request started', this._activeSession.provider.debugName, this._activeSession.session, request); @@ -588,7 +595,8 @@ export class InlineChatController implements IEditorContribution { await progress.drain(); if (reply?.type === InlineChatResponseType.Message) { - response = new MarkdownResponse(this._activeSession.textModelN.uri, reply); + markdownContents.appendMarkdown(reply.message.value); + response = new MarkdownResponse(this._activeSession.textModelN.uri, reply, markdownContents); } else if (reply) { const editResponse = new EditResponse(this._activeSession.textModelN.uri, this._activeSession.textModelN.getAlternativeVersionId(), reply, progressEdits); for (let i = progressEdits.length; i < editResponse.allLocalEdits.length; i++) { @@ -716,7 +724,7 @@ export class InlineChatController implements IEditorContribution { // clear status, show MD message this._zone.value.widget.updateStatus(''); - const content = this._zone.value.widget.updateMarkdownMessage(response.raw.message); + const content = this._zone.value.widget.updateMarkdownMessage(response.mdContent); this._zone.value.widget.updateToolbar(true); if (content) { status = localize('markdownResponseMessage', "{0}", content); @@ -862,7 +870,7 @@ export class InlineChatController implements IEditorContribution { viewInChat() { if (this._activeSession?.lastExchange?.response instanceof MarkdownResponse) { - this._instaService.invokeFunction(showMessageResponse, this._activeSession.lastExchange.prompt.value, this._activeSession.lastExchange.response.raw.message.value); + this._instaService.invokeFunction(showMessageResponse, this._activeSession.lastExchange.prompt.value, this._activeSession.lastExchange.response.mdContent.value); } } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index b5daf7c9c27..891b3c02da2 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -26,6 +26,7 @@ import { isCancellationError } from 'vs/base/common/errors'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { raceCancellation } from 'vs/base/common/async'; import { LineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; +import { IMarkdownString } from 'vs/base/common/htmlContent'; export type Recording = { when: Date; @@ -281,7 +282,8 @@ export class ErrorResponse { export class MarkdownResponse { constructor( readonly localUri: URI, - readonly raw: IInlineChatMessageResponse + readonly raw: IInlineChatMessageResponse, + readonly mdContent: IMarkdownString, ) { } } diff --git a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts index 449d5e5884a..807bbb2c2c0 100644 --- a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts +++ b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts @@ -84,6 +84,7 @@ export interface IInlineChatMessageResponse { } export interface IInlineChatProgressItem { + markdownFragment?: string; edits?: TextEdit[]; message?: string; slashCommand?: string; diff --git a/src/vscode-dts/vscode.proposed.interactive.d.ts b/src/vscode-dts/vscode.proposed.interactive.d.ts index d10a0946dfa..262522a6710 100644 --- a/src/vscode-dts/vscode.proposed.interactive.d.ts +++ b/src/vscode-dts/vscode.proposed.interactive.d.ts @@ -52,6 +52,7 @@ declare module 'vscode' { message?: string; edits?: TextEdit[]; slashCommand?: InteractiveEditorSlashCommand; + content?: string | MarkdownString; } export enum InteractiveEditorResponseFeedbackKind { From c1fb869bcd9f295d5ca546ea78d7f84cb0e3b8ba Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 19 Oct 2023 16:44:25 +0200 Subject: [PATCH 264/290] undo streaming edits when final result isn't an edit result (#195995) fixes https://github.com/microsoft/vscode-copilot/issues/2030 --- .../contrib/inlineChat/browser/inlineChatController.ts | 9 ++++++--- .../contrib/inlineChat/browser/inlineChatStrategies.ts | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index f8f190fbfb3..4e15cd82405 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -490,7 +490,7 @@ export class InlineChatController implements IEditorContribution { if (lastExchange.response instanceof EditResponse) { try { this._ignoreModelContentChanged = true; - await this._strategy.undoChanges(lastExchange.response); + await this._strategy.undoChanges(lastExchange.response.modelAltVersionId); } finally { this._ignoreModelContentChanged = false; } @@ -552,6 +552,7 @@ export class InlineChatController implements IEditorContribution { }; this._chatAccessibilityService.acceptRequest(); + const modelAltVersionIdNow = this._activeSession.textModelN.getAlternativeVersionId(); const progressEdits: TextEdit[][] = []; const markdownContents = new MarkdownString('', { supportThemeIcons: true, supportHtml: true, isTrusted: false }); @@ -598,7 +599,7 @@ export class InlineChatController implements IEditorContribution { markdownContents.appendMarkdown(reply.message.value); response = new MarkdownResponse(this._activeSession.textModelN.uri, reply, markdownContents); } else if (reply) { - const editResponse = new EditResponse(this._activeSession.textModelN.uri, this._activeSession.textModelN.getAlternativeVersionId(), reply, progressEdits); + const editResponse = new EditResponse(this._activeSession.textModelN.uri, modelAltVersionIdNow, reply, progressEdits); for (let i = progressEdits.length; i < editResponse.allLocalEdits.length; i++) { await this._makeChanges(editResponse.allLocalEdits[i], true); } @@ -609,14 +610,16 @@ export class InlineChatController implements IEditorContribution { } catch (e) { response = new ErrorResponse(e); - } finally { this._ctxHasActiveRequest.set(false); this._zone.value.widget.updateProgress(false); this._zone.value.widget.updateInfo(''); this._zone.value.widget.updateToolbar(true); this._log('request took', sw.elapsed(), this._activeSession.provider.debugName); + } + if (request.live && !(response instanceof EditResponse)) { + this._strategy?.undoChanges(modelAltVersionIdNow); } requestCts.dispose(); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index c36dfd9d714..a3447e3b5a9 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -40,7 +40,7 @@ export abstract class EditModeStrategy { abstract makeChanges(edits: ISingleEditOperation[]): Promise; - abstract undoChanges(response: EditResponse): Promise; + abstract undoChanges(altVersionId: number): Promise; abstract renderProgressChanges(): Promise; @@ -122,7 +122,7 @@ export class PreviewStrategy extends EditModeStrategy { // nothing to do } - override async undoChanges(_response: EditResponse): Promise { + override async undoChanges(_altVersionId: number): Promise { // nothing to do } @@ -317,9 +317,9 @@ export class LiveStrategy extends EditModeStrategy { this._editor.executeEdits('inline-chat-live', edits, cursorStateComputerAndInlineDiffCollection); } - override async undoChanges(response: EditResponse): Promise { + override async undoChanges(altVersionId: number): Promise { const { textModelN } = this._session; - LiveStrategy._undoModelUntil(textModelN, response.modelAltVersionId); + LiveStrategy._undoModelUntil(textModelN, altVersionId); } override async renderProgressChanges(): Promise { From 01a7748cef179bccf9ae0ac85620dfa4987d91e2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 19 Oct 2023 16:50:28 +0200 Subject: [PATCH 265/290] fix acitivty bar position action in fullscreen mode (#195999) --- src/vs/workbench/browser/layout.ts | 5 +++++ .../workbench/browser/parts/activitybar/activitybarPart.ts | 6 +++--- src/vs/workbench/common/contextkeys.ts | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 18c41696437..e536574f0a5 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -1106,6 +1106,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return true; } + // with the activity bar on top, we should always show + if (this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION) === ActivityBarPosition.TOP) { + return true; + } + // macOS desktop does not need a title bar when full screen if (isMacintosh && isNative) { return !this.state.runtime.fullscreen; diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index d0182c35883..762f9935736 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -36,7 +36,7 @@ import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IViewDescriptorService, ViewContainerLocation, ViewContainerLocationToString } from 'vs/workbench/common/views'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; -import { TitleBarVisibleContext } from 'vs/workbench/common/contextkeys'; +import { TitleBarStyleContext } from 'vs/workbench/common/contextkeys'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -389,11 +389,11 @@ registerAction2(class extends Action2 { toggled: ContextKeyExpr.equals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), menu: [{ id: MenuId.ActivityBarPositionMenu, - when: TitleBarVisibleContext.isEqualTo(true), + when: TitleBarStyleContext.notEqualsTo('native'), order: 2 }, { id: MenuId.CommandPalette, - when: ContextKeyExpr.and(ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), TitleBarVisibleContext.isEqualTo(true)), + when: ContextKeyExpr.and(ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), TitleBarStyleContext.notEqualsTo('native')), }] }); } diff --git a/src/vs/workbench/common/contextkeys.ts b/src/vs/workbench/common/contextkeys.ts index 8403b656459..c58fb9d32f7 100644 --- a/src/vs/workbench/common/contextkeys.ts +++ b/src/vs/workbench/common/contextkeys.ts @@ -15,6 +15,7 @@ import { Schemas } from 'vs/base/common/network'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IEditorResolverService } from 'vs/workbench/services/editor/common/editorResolverService'; import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor'; +import { isLinux } from 'vs/base/common/platform'; //#region < --- Workbench --- > @@ -99,6 +100,7 @@ export const StatusBarFocused = new RawContextKey('statusBarFocused', f //#region < --- Title Bar --- > +export const TitleBarStyleContext = new RawContextKey('titleBarStyle', isLinux ? 'native' : 'custom', localize('titleBarStyle', "Style of the window title bar")); export const TitleBarVisibleContext = new RawContextKey('titleBarVisible', false, localize('titleBarVisible', "Whether the title bar is visible")); //#endregion From 9e36f4c03e0318bb4a583af0b29652f21cc0f9b8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 19 Oct 2023 16:53:09 +0200 Subject: [PATCH 266/290] fix badge in hc themes (#195996) --- src/vs/workbench/browser/parts/compositeBarActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index 161e0a84840..7f58326dcb0 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -220,7 +220,7 @@ export class CompoisteBarActionViewItem extends BaseActionViewItem { this.badgeContent.style.color = badgeFg ? badgeFg.toString() : ''; this.badgeContent.style.backgroundColor = badgeBg ? badgeBg.toString() : ''; - this.badgeContent.style.borderStyle = contrastBorderColor ? 'solid' : ''; + this.badgeContent.style.borderStyle = contrastBorderColor && !this.options.compact ? 'solid' : ''; this.badgeContent.style.borderWidth = contrastBorderColor ? '1px' : ''; this.badgeContent.style.borderColor = contrastBorderColor ? contrastBorderColor.toString() : ''; } From 8e8811a5c1e64033cb696831ee7e17f9b1e27877 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 14:05:57 -0700 Subject: [PATCH 267/290] clean raw jupyter error stack traces --- extensions/notebook-renderers/src/index.ts | 5 +++- .../src/stackTraceHelper.ts | 26 ++++++++++++++++++ .../src/test/notebookRenderer.test.ts | 27 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 extensions/notebook-renderers/src/stackTraceHelper.ts diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index 6ee655c509c..68eed9edfd0 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -7,6 +7,7 @@ import type { ActivationFunction, OutputItem, RendererContext } from 'vscode-not import { createOutputContent, appendOutput, scrollableClass } from './textHelper'; import { HtmlRenderingHook, IDisposable, IRichRenderContext, JavaScriptRenderingHook, OutputWithAppend, RenderOptions } from './rendererTypes'; import { ttPolicy } from './htmlHelper'; +import { cleanStackTrace } from './stackTraceHelper'; function clearContainer(container: HTMLElement) { while (container.firstChild) { @@ -172,8 +173,10 @@ function renderError( if (err.stack) { outputElement.classList.add('traceback'); + const stackTrace = cleanStackTrace(err.stack); + const outputScrolling = scrollingEnabled(outputInfo, ctx.settings); - const content = createOutputContent(outputInfo.id, err.stack ?? '', { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml }); + const content = createOutputContent(outputInfo.id, stackTrace ?? '', { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml }); const contentParent = document.createElement('div'); contentParent.classList.toggle('word-wrap', ctx.settings.outputWordWrap); disposableStore.push(ctx.onDidChangeSettings(e => { diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts new file mode 100644 index 00000000000..ddaf3b8fa1a --- /dev/null +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export function cleanStackTrace(stack: string) { + let cleaned: string; + // Ansi colors are described here: + // https://en.wikipedia.org/wiki/ANSI_escape_code under the SGR section + + // Remove background colors. The ones from IPython don't work well with + // themes 40-49 sets background color + cleaned = stack.replace(/\u001b\[4\dm/g, ''); + + // Also remove specific foreground colors (38 is the ascii code for picking one) (they don't translate either) + // Turn them into default foreground + cleaned = cleaned.replace(/\u001b\[38;.*?\d+m/g, '\u001b[39m'); + + // Turn all foreground colors after the --> to default foreground + cleaned = cleaned.replace(/(;32m[ ->]*?)(\d+)(.*)\n/g, (_s, prefix, num, suffix) => { + suffix = suffix.replace(/\u001b\[3\d+m/g, '\u001b[39m'); + return `${prefix}${num}${suffix}\n`; + }); + + return cleaned; +} diff --git a/extensions/notebook-renderers/src/test/notebookRenderer.test.ts b/extensions/notebook-renderers/src/test/notebookRenderer.test.ts index 7c92a5a01f4..8e33720d337 100644 --- a/extensions/notebook-renderers/src/test/notebookRenderer.test.ts +++ b/extensions/notebook-renderers/src/test/notebookRenderer.test.ts @@ -451,5 +451,32 @@ suite('Notebook builtin output renderer', () => { assert.equal(settingsChangedHandlers.length, handlerCount); }); + + const rawIPythonError = { + name: "NameError", + message: "name 'x' is not defined", + stack: "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m" + + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)" + + "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mmyfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n" + + "Cell \u001b[1;32mIn[1], line 2\u001b[0m, in \u001b[0;36mmyfunc\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mmyfunc\u001b[39m():\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mx\u001b[49m)\n" + + "\u001b[1;31mNameError\u001b[0m: name 'x' is not defined" + }; + + test(`Should clean up raw IPython error stack traces`, async () => { + LinkDetector.injectedHtmlCreator = (value: string) => value; + const context = createContext({ outputWordWrap: true, outputScrolling: true }); + const renderer = await activate(context); + assert.ok(renderer, 'Renderer not created'); + + const outputElement = new OutputHtml().getFirstOuputElement(); + const outputItem = createOutputItem(JSON.stringify(rawIPythonError), errorMimeType); + await renderer!.renderOutputItem(outputItem, outputElement); + + const inserted = outputElement.firstChild as HTMLElement; + assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`); + //assert.ok(false, `TextContent:\n ${outputElement.textContent}`); + assert.ok(outputElement.innerHTML.indexOf('class="code-background-colored"') === -1, `inner HTML:\n ${outputElement.innerHTML}`); + }); + }); From 315f158d205d97931a4ffe9e887855a4c6039ba4 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 15:22:51 -0700 Subject: [PATCH 268/290] link test --- extensions/notebook-renderers/src/index.ts | 4 +- .../src/stackTraceHelper.ts | 2 +- .../src/test/stackTraceHelper.test.ts | 37 +++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 extensions/notebook-renderers/src/test/stackTraceHelper.test.ts diff --git a/extensions/notebook-renderers/src/index.ts b/extensions/notebook-renderers/src/index.ts index 68eed9edfd0..ba57767b7fc 100644 --- a/extensions/notebook-renderers/src/index.ts +++ b/extensions/notebook-renderers/src/index.ts @@ -7,7 +7,7 @@ import type { ActivationFunction, OutputItem, RendererContext } from 'vscode-not import { createOutputContent, appendOutput, scrollableClass } from './textHelper'; import { HtmlRenderingHook, IDisposable, IRichRenderContext, JavaScriptRenderingHook, OutputWithAppend, RenderOptions } from './rendererTypes'; import { ttPolicy } from './htmlHelper'; -import { cleanStackTrace } from './stackTraceHelper'; +import { formatStackTrace } from './stackTraceHelper'; function clearContainer(container: HTMLElement) { while (container.firstChild) { @@ -173,7 +173,7 @@ function renderError( if (err.stack) { outputElement.classList.add('traceback'); - const stackTrace = cleanStackTrace(err.stack); + const stackTrace = formatStackTrace(err.stack); const outputScrolling = scrollingEnabled(outputInfo, ctx.settings); const content = createOutputContent(outputInfo.id, stackTrace ?? '', { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml }); diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index ddaf3b8fa1a..79441e8db35 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export function cleanStackTrace(stack: string) { +export function formatStackTrace(stack: string) { let cleaned: string; // Ansi colors are described here: // https://en.wikipedia.org/wiki/ANSI_escape_code under the SGR section diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts new file mode 100644 index 00000000000..0fe1b861488 --- /dev/null +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { formatStackTrace } from '../stackTraceHelper'; +import * as assert from 'assert'; + +suite('StackTraceHelper', () => { + + test('Non Ipython stack trace is left alone', () => { + const stack = 'DivideError: integer division error\n' + + 'Stacktrace:\n' + + '[1] divide_by_zero(x:: Int64)\n' + + '@Main c:\\src\\test\\3\\otherlanguages\\julia.ipynb: 3\n' + + '[2] top - level scope\n' + + '@c:\\src\\test\\3\\otherlanguages\\julia.ipynb: 1; '; + assert.equal(formatStackTrace(stack), stack); + }); + + test('IPython cell references are linkified', () => { + const stack = + '---------------------------------------------------------------------------\n' + + 'Exception Traceback(most recent call last)\n' + + 'Cell In[3], line 2\n' + + ' 1 import myLib\n' + + '----> 2 myLib.throwEx()\n' + + '\n' + + 'File C:\\venvs\\myLib.py:2, in throwEx()\n' + + ' 1 def throwEx():\n' + + '----> 2 raise Exception\n'; + + const formatted = formatStackTrace(stack); + assert.ok(formatted.indexOf); + }); + +}); From 2123a011bfcd2e2ff2ea8a09b326590ebc4d9ebe Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Mon, 16 Oct 2023 10:42:44 -0700 Subject: [PATCH 269/290] linkify stack lines for file references --- .../src/stackTraceHelper.ts | 41 +++++++++++++++++++ .../src/test/stackTraceHelper.test.ts | 18 +++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index 79441e8db35..3228628029d 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -22,5 +22,46 @@ export function formatStackTrace(stack: string) { return `${prefix}${num}${suffix}\n`; }); + if (isIpythonStackTrace(stack)) { + return linkifyStack(stack); + } + return cleaned; } + +function isIpythonStackTrace(stack: string) { + const cellIdentifier = /^Cell In\[\d+\], line \d+$/gm; + return cellIdentifier.test(stack); +} + +const fileRegex = /^File\s+(.+):\d+/; +const lineNumberRegex = /([ ->]*?)(\d+)(.*)/; + +function linkifyStack(stack: string) { + const lines = stack.split('\n'); + + let fileOrCell: string | undefined; + + for (const i in lines) { + + const original = lines[i]; + console.log(`linkify ${original}`); // REMOVE + if (fileRegex.test(original)) { + const fileMatch = lines[i].match(fileRegex); + fileOrCell = fileMatch![1]; + console.log(`matched file ${fileOrCell}`); // REMOVE + continue; + } else if (!fileOrCell || original.trim() === '') { + // we don't have a location, so don't linkify anything + fileOrCell = undefined; + continue; + } else if (lineNumberRegex.test(original)) { + console.log(`linkify line ${original}`); // REMOVE + lines[i] = original.replace(lineNumberRegex, (_s, prefix, num, suffix) => { + return `${prefix}${num}${suffix}`; + }); + } + } + + return lines.join('\n'); +} diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index 0fe1b861488..b40ec59e652 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -18,7 +18,7 @@ suite('StackTraceHelper', () => { assert.equal(formatStackTrace(stack), stack); }); - test('IPython cell references are linkified', () => { + test('IPython stack line numbers are linkified', () => { const stack = '---------------------------------------------------------------------------\n' + 'Exception Traceback(most recent call last)\n' + @@ -31,7 +31,21 @@ suite('StackTraceHelper', () => { '----> 2 raise Exception\n'; const formatted = formatStackTrace(stack); - assert.ok(formatted.indexOf); + assert.ok(formatted.indexOf('2') > 0, formatted); + }); + + test('IPython stack trace lines without associated location are not linkified', () => { + const stack = + '---------------------------------------------------------------------------\n' + + 'Exception Traceback(most recent call last)\n' + + 'File C:\\venvs\\myLib.py:2, in throwEx()\n' + + '\n' + + 'unkown reference' + + ' 1 import myLib\n' + // trace lines without an associated file + '----> 2 myLib.throwEx()\n'; + + const formatted = formatStackTrace(stack); + assert.ok(formatted.indexOf(' Date: Mon, 16 Oct 2023 11:29:07 -0700 Subject: [PATCH 270/290] linkify stack lines for cell references --- .../notebook-renderers/src/stackTraceHelper.ts | 14 ++++++++++---- .../src/test/stackTraceHelper.test.ts | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index 3228628029d..a43b431fef4 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -29,14 +29,16 @@ export function formatStackTrace(stack: string) { return cleaned; } +const fileRegex = /^File\s+(.+):\d+/; +const lineNumberRegex = /([ ->]*?)(\d+)(.*)/; +const cellRegex = /^(Cell\s+In\[(\d+)\])(,\s+line \d+)$/; + function isIpythonStackTrace(stack: string) { + // at least one group will point to the Cell within the notebook const cellIdentifier = /^Cell In\[\d+\], line \d+$/gm; return cellIdentifier.test(stack); } -const fileRegex = /^File\s+(.+):\d+/; -const lineNumberRegex = /([ ->]*?)(\d+)(.*)/; - function linkifyStack(stack: string) { const lines = stack.split('\n'); @@ -49,8 +51,12 @@ function linkifyStack(stack: string) { if (fileRegex.test(original)) { const fileMatch = lines[i].match(fileRegex); fileOrCell = fileMatch![1]; - console.log(`matched file ${fileOrCell}`); // REMOVE continue; + } else if (cellRegex.test(original)) { + lines[i] = original.replace(cellRegex, (_s, cellLabel, executionCount, suffix) => { + fileOrCell = `vscode-notebook-cell:?execution=${executionCount}`; + return `${cellLabel}${suffix}`; + }); } else if (!fileOrCell || original.trim() === '') { // we don't have a location, so don't linkify anything fileOrCell = undefined; diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index b40ec59e652..045d2ed06c6 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -31,6 +31,8 @@ suite('StackTraceHelper', () => { '----> 2 raise Exception\n'; const formatted = formatStackTrace(stack); + assert.ok(formatted.indexOf('Cell In[3]') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); assert.ok(formatted.indexOf('2') > 0, formatted); }); From 4540b9ba1f8214cfa4f75ee824c40627eaecf738 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Mon, 16 Oct 2023 15:57:14 -0700 Subject: [PATCH 271/290] older Ipython, failing test --- .../src/stackTraceHelper.ts | 40 +++++++++++---- .../src/test/stackTraceHelper.test.ts | 50 ++++++++++++------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index a43b431fef4..20235787cc0 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -22,21 +22,27 @@ export function formatStackTrace(stack: string) { return `${prefix}${num}${suffix}\n`; }); - if (isIpythonStackTrace(stack)) { - return linkifyStack(stack); + if (isIpythonStackTrace(cleaned)) { + return linkifyStack(cleaned); } return cleaned; } -const fileRegex = /^File\s+(.+):\d+/; -const lineNumberRegex = /([ ->]*?)(\d+)(.*)/; -const cellRegex = /^(Cell\s+In\[(\d+)\])(,\s+line \d+)$/; +const formatSequence = /\u001b\[.+?m/g; +const fileRegex = /File\s+(?:\u001b\[.+?m)?(.+):(\d+)/; +const lineNumberRegex = /((?:\u001b\[.+?m)?[ ->]*?)(\d+)(.*)/; +const cellRegex = /(Cell\s+(?:\u001b\[.+?m)?In\s*\[(\d+)\])(,\s*line \d+)/; +// older versions of IPython ~8.3.0 +const inputRegex = /(Input\s+?(?:\u001b\[.+?m)In\s*\[(\d+)\])(.*?)/; function isIpythonStackTrace(stack: string) { // at least one group will point to the Cell within the notebook - const cellIdentifier = /^Cell In\[\d+\], line \d+$/gm; - return cellIdentifier.test(stack); + return cellRegex.test(stack); +} + +function stripFormatting(text: string) { + return text.replace(formatSequence, ''); } function linkifyStack(stack: string) { @@ -50,22 +56,34 @@ function linkifyStack(stack: string) { console.log(`linkify ${original}`); // REMOVE if (fileRegex.test(original)) { const fileMatch = lines[i].match(fileRegex); - fileOrCell = fileMatch![1]; + fileOrCell = stripFormatting(fileMatch![1]); + console.log(`matched file ${fileOrCell}`); // REMOVE continue; } else if (cellRegex.test(original)) { lines[i] = original.replace(cellRegex, (_s, cellLabel, executionCount, suffix) => { - fileOrCell = `vscode-notebook-cell:?execution=${executionCount}`; - return `${cellLabel}${suffix}`; + fileOrCell = `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}`; + return `${stripFormatting(cellLabel)}${suffix}`; }); + console.log(`matched cell ${fileOrCell}`); // REMOVE + continue; + } else if (inputRegex.test(original)) { + lines[i] = original.replace(inputRegex, (_s, cellLabel, executionCount, suffix) => { + fileOrCell = `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}`; + return `${stripFormatting(cellLabel)}${suffix}`; + }); + console.log(`matched cell ${fileOrCell}`); // REMOVE + continue; } else if (!fileOrCell || original.trim() === '') { // we don't have a location, so don't linkify anything fileOrCell = undefined; continue; } else if (lineNumberRegex.test(original)) { - console.log(`linkify line ${original}`); // REMOVE + lines[i] = original.replace(lineNumberRegex, (_s, prefix, num, suffix) => { return `${prefix}${num}${suffix}`; }); + console.log(`matched line ${lines[i]}`); // REMOVE + continue; } } diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index 045d2ed06c6..d3350292403 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -20,15 +20,16 @@ suite('StackTraceHelper', () => { test('IPython stack line numbers are linkified', () => { const stack = - '---------------------------------------------------------------------------\n' + - 'Exception Traceback(most recent call last)\n' + - 'Cell In[3], line 2\n' + - ' 1 import myLib\n' + - '----> 2 myLib.throwEx()\n' + + '\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n' + + '\u001b[1;31mException\u001b[0m Traceback (most recent call last)\n' + + 'Cell \u001b[1;32mIn[3], line 2\u001b[0m\n' + + '\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmyLib\u001b[39;00m\n' + + '\u001b[1;32m----> 2\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n' + '\n' + - 'File C:\\venvs\\myLib.py:2, in throwEx()\n' + - ' 1 def throwEx():\n' + - '----> 2 raise Exception\n'; + 'File \u001b[1;32mC:\\venvs\\myLib.py:2\u001b[0m, in \u001b[0;36mthrowEx\u001b[1;34m()\u001b[0m\n' + + '\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mthrowEx\u001b[39m():\n' + + '\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m\n\n' + + '\u001b[1;31mException\u001b[0m\n:'; const formatted = formatStackTrace(stack); assert.ok(formatted.indexOf('Cell In[3]') > 0, formatted); @@ -36,18 +37,33 @@ suite('StackTraceHelper', () => { assert.ok(formatted.indexOf('2') > 0, formatted); }); - test('IPython stack trace lines without associated location are not linkified', () => { + test('IPython stack line numbers are linkified for IPython 8.3', () => { const stack = - '---------------------------------------------------------------------------\n' + - 'Exception Traceback(most recent call last)\n' + - 'File C:\\venvs\\myLib.py:2, in throwEx()\n' + - '\n' + - 'unkown reference' + - ' 1 import myLib\n' + // trace lines without an associated file - '----> 2 myLib.throwEx()\n'; + '\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n' + + '\u001b[1;31mException\u001b[0m Traceback (most recent call last)\n' + + 'Input \u001b[1;32mIn [2]\u001b[0m, in \u001b[0;36m\u001b[1;34m()\u001b[0m\n' + + '\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmyLib\u001b[39;00m\n' + + '\u001b[1;32m----> 2\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n'; const formatted = formatStackTrace(stack); - assert.ok(formatted.indexOf('Input [2]') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); + }); + + test('IPython stack trace lines without associated location are not linkified', () => { + const stack = + '\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n' + + '\u001b[1;31mException\u001b[0m Traceback (most recent call last)\n' + + 'Cell \u001b[1;32mIn[3], line 2\u001b[0m\n' + + '\n' + + 'unknown source\n' + + '\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mthrowEx\u001b[39m():\n' + + '\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m\n\n' + + '\u001b[1;31mException\u001b[0m\n:'; + + const formatted = formatStackTrace(stack); + assert.ok(!/\d<\/a>/.test(formatted), formatted); }); }); From 3b6848c4e6b2ed2a0f4e7b9c897b35c1d63f6eec Mon Sep 17 00:00:00 2001 From: aamunger Date: Tue, 17 Oct 2023 09:08:29 -0700 Subject: [PATCH 272/290] pass test --- extensions/notebook-renderers/src/stackTraceHelper.ts | 3 +-- .../notebook-renderers/src/test/stackTraceHelper.test.ts | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index 20235787cc0..dbab8718f94 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -37,8 +37,7 @@ const cellRegex = /(Cell\s+(?:\u001b\[.+?m)?In\s*\[(\d+)\])(,\s*line \d+)/; const inputRegex = /(Input\s+?(?:\u001b\[.+?m)In\s*\[(\d+)\])(.*?)/; function isIpythonStackTrace(stack: string) { - // at least one group will point to the Cell within the notebook - return cellRegex.test(stack); + return cellRegex.test(stack) || inputRegex.test(stack) || fileRegex.test(stack); } function stripFormatting(text: string) { diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index d3350292403..59404c78633 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -46,9 +46,8 @@ suite('StackTraceHelper', () => { '\u001b[1;32m----> 2\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n'; const formatted = formatStackTrace(stack); - assert.ok(formatted.indexOf('Input [2]') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); + assert.ok(formatted.indexOf('Input In [2]') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); }); test('IPython stack trace lines without associated location are not linkified', () => { From a9ee16c1351edfaec823519eec2dde2b3cc6ebd7 Mon Sep 17 00:00:00 2001 From: aamunger Date: Tue, 17 Oct 2023 11:10:03 -0700 Subject: [PATCH 273/290] handle new URI format from webview --- .../src/stackTraceHelper.ts | 22 +++++---- .../src/test/stackTraceHelper.test.ts | 4 +- .../view/renderers/backLayerWebView.ts | 45 ++++++++++++++++--- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index dbab8718f94..e221a779c62 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -44,10 +44,15 @@ function stripFormatting(text: string) { return text.replace(formatSequence, ''); } +type cellLocation = { kind: 'cell'; path: string }; +type fileLocation = { kind: 'file'; path: string }; + +type location = cellLocation | fileLocation; + function linkifyStack(stack: string) { const lines = stack.split('\n'); - let fileOrCell: string | undefined; + let fileOrCell: location | undefined; for (const i in lines) { @@ -55,20 +60,20 @@ function linkifyStack(stack: string) { console.log(`linkify ${original}`); // REMOVE if (fileRegex.test(original)) { const fileMatch = lines[i].match(fileRegex); - fileOrCell = stripFormatting(fileMatch![1]); + fileOrCell = { kind: 'file', path: stripFormatting(fileMatch![1]) }; console.log(`matched file ${fileOrCell}`); // REMOVE continue; } else if (cellRegex.test(original)) { lines[i] = original.replace(cellRegex, (_s, cellLabel, executionCount, suffix) => { - fileOrCell = `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}`; - return `${stripFormatting(cellLabel)}${suffix}`; + fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}` }; + return `${stripFormatting(cellLabel)}${suffix}`; }); console.log(`matched cell ${fileOrCell}`); // REMOVE continue; } else if (inputRegex.test(original)) { lines[i] = original.replace(inputRegex, (_s, cellLabel, executionCount, suffix) => { - fileOrCell = `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}`; - return `${stripFormatting(cellLabel)}${suffix}`; + fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}` }; + return `${stripFormatting(cellLabel)}${suffix}`; }); console.log(`matched cell ${fileOrCell}`); // REMOVE continue; @@ -77,9 +82,10 @@ function linkifyStack(stack: string) { fileOrCell = undefined; continue; } else if (lineNumberRegex.test(original)) { - lines[i] = original.replace(lineNumberRegex, (_s, prefix, num, suffix) => { - return `${prefix}${num}${suffix}`; + return fileOrCell?.kind === 'file' ? + `${prefix}${num}${suffix}` : + `${prefix}${num}${suffix}`; }); console.log(`matched line ${lines[i]}`); // REMOVE continue; diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index 59404c78633..2b9cd73c95a 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -33,7 +33,7 @@ suite('StackTraceHelper', () => { const formatted = formatStackTrace(stack); assert.ok(formatted.indexOf('Cell In[3]') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); assert.ok(formatted.indexOf('2') > 0, formatted); }); @@ -47,7 +47,7 @@ suite('StackTraceHelper', () => { const formatted = formatStackTrace(stack); assert.ok(formatted.indexOf('Input In [2]') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); }); test('IPython stack trace lines without associated location are not linkified', () => { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 65ece00b65c..1cb11aaee93 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -907,18 +907,54 @@ export class BackLayerWebView extends Themable { } private _handleNotebookCellResource(uri: URI) { - const lineMatch = /\?line=(\d+)$/.exec(uri.fragment); + const lineMatch = /(?:^|&)line=([^&]+)/.exec(uri.query); + let editorOptions: ITextEditorOptions | undefined = undefined; if (lineMatch) { const parsedLineNumber = parseInt(lineMatch[1], 10); + if (!isNaN(parsedLineNumber)) { + const lineNumber = parsedLineNumber; + + editorOptions = { + selection: { startLineNumber: lineNumber, startColumn: 1 } + }; + } + } + + const executionMatch = /(?:^|&)execution=([^&]+)/.exec(uri.query); + const notebookResource = uri.path.length > 0 ? uri : this.documentUri; + if (executionMatch) { + const executionCount = parseInt(executionMatch[1], 10); + if (!isNaN(executionCount)) { + const notebookModel = this.notebookService.getNotebookTextModel(notebookResource); + const cell = notebookModel?.cells.find(cell => { + return cell.internalMetadata.executionOrder === executionCount; + }); + if (cell?.uri) { + this.openerService.open(cell.uri, { + fromUserGesture: true, + fromWorkspace: true, + editorOptions: editorOptions + }); + return; + } + } + } + + // URLs built by the jupyter extension put the line query param in the fragment + // They also have the cell fragment pre-calculated + const fragmentLineMatch = /\?line=(\d+)$/.exec(uri.fragment); + if (fragmentLineMatch) { + const parsedLineNumber = parseInt(fragmentLineMatch[1], 10); if (!isNaN(parsedLineNumber)) { const lineNumber = parsedLineNumber + 1; - const fragment = uri.fragment.substring(0, lineMatch.index); + const fragment = uri.fragment.substring(0, fragmentLineMatch.index); // open the uri with selection const editorOptions: ITextEditorOptions = { selection: { startLineNumber: lineNumber, startColumn: 1, endLineNumber: lineNumber, endColumn: 1 } }; - this.openerService.open(uri.with({ fragment }), { + + this.openerService.open(notebookResource.with({ fragment }), { fromUserGesture: true, fromWorkspace: true, editorOptions: editorOptions @@ -927,8 +963,7 @@ export class BackLayerWebView extends Themable { } } - this.openerService.open(uri, { fromUserGesture: true, fromWorkspace: true }); - return uri; + this.openerService.open(notebookResource, { fromUserGesture: true, fromWorkspace: true }); } private _handleResourceOpening(href: string) { From 55794b6c76b19f826aa9f4a88524385f5b835a50 Mon Sep 17 00:00:00 2001 From: aamunger Date: Tue, 17 Oct 2023 11:18:27 -0700 Subject: [PATCH 274/290] handle new URI format from webview --- .../notebook-renderers/src/stackTraceHelper.ts | 14 +++++++------- .../src/test/stackTraceHelper.test.ts | 8 ++++---- .../browser/view/renderers/backLayerWebView.ts | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index e221a779c62..df326592935 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -57,29 +57,29 @@ function linkifyStack(stack: string) { for (const i in lines) { const original = lines[i]; - console.log(`linkify ${original}`); // REMOVE if (fileRegex.test(original)) { const fileMatch = lines[i].match(fileRegex); fileOrCell = { kind: 'file', path: stripFormatting(fileMatch![1]) }; - console.log(`matched file ${fileOrCell}`); // REMOVE + continue; } else if (cellRegex.test(original)) { lines[i] = original.replace(cellRegex, (_s, cellLabel, executionCount, suffix) => { - fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}` }; + fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution_count=${stripFormatting(executionCount)}` }; return `${stripFormatting(cellLabel)}${suffix}`; }); - console.log(`matched cell ${fileOrCell}`); // REMOVE + continue; } else if (inputRegex.test(original)) { lines[i] = original.replace(inputRegex, (_s, cellLabel, executionCount, suffix) => { - fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution=${stripFormatting(executionCount)}` }; + fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution_count=${stripFormatting(executionCount)}` }; return `${stripFormatting(cellLabel)}${suffix}`; }); - console.log(`matched cell ${fileOrCell}`); // REMOVE + continue; } else if (!fileOrCell || original.trim() === '') { // we don't have a location, so don't linkify anything fileOrCell = undefined; + continue; } else if (lineNumberRegex.test(original)) { lines[i] = original.replace(lineNumberRegex, (_s, prefix, num, suffix) => { @@ -87,7 +87,7 @@ function linkifyStack(stack: string) { `${prefix}${num}${suffix}` : `${prefix}${num}${suffix}`; }); - console.log(`matched line ${lines[i]}`); // REMOVE + continue; } } diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index 2b9cd73c95a..8a72201aa2e 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -32,8 +32,8 @@ suite('StackTraceHelper', () => { '\u001b[1;31mException\u001b[0m\n:'; const formatted = formatStackTrace(stack); - assert.ok(formatted.indexOf('Cell In[3]') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); + assert.ok(formatted.indexOf('Cell In[3]') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); assert.ok(formatted.indexOf('2') > 0, formatted); }); @@ -46,8 +46,8 @@ suite('StackTraceHelper', () => { '\u001b[1;32m----> 2\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n'; const formatted = formatStackTrace(stack); - assert.ok(formatted.indexOf('Input In [2]') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); + assert.ok(formatted.indexOf('Input In [2]') > 0, formatted); + assert.ok(formatted.indexOf('2') > 0, formatted); }); test('IPython stack trace lines without associated location are not linkified', () => { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 1cb11aaee93..214cf9c2380 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -920,7 +920,7 @@ export class BackLayerWebView extends Themable { } } - const executionMatch = /(?:^|&)execution=([^&]+)/.exec(uri.query); + const executionMatch = /(?:^|&)execution_count=([^&]+)/.exec(uri.query); const notebookResource = uri.path.length > 0 ? uri : this.documentUri; if (executionMatch) { const executionCount = parseInt(executionMatch[1], 10); From 4448839e4d5e86d81c7d2b1112fb829171db6e82 Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 18 Oct 2023 09:59:33 -0700 Subject: [PATCH 275/290] fix IW cell links --- .../contrib/interactive/browser/interactive.contribution.ts | 4 +++- .../notebook/browser/view/renderers/backLayerWebView.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index a2007e163bc..d291c4c130f 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -135,14 +135,16 @@ export class InteractiveDocumentContribution extends Disposable implements IWork createEditorInput: ({ resource, options }) => { const data = CellUri.parse(resource); let cellOptions: IResourceEditorInput | undefined; + let IwResource = resource; if (data) { cellOptions = { resource, options }; + IwResource = data.notebook; } const notebookOptions = { ...options, cellOptions } as INotebookEditorOptions; - const editorInput = createEditor(resource, this.instantiationService); + const editorInput = createEditor(IwResource, this.instantiationService); return { editor: editorInput, options: notebookOptions diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 214cf9c2380..bd9bdd0e7e8 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -926,7 +926,9 @@ export class BackLayerWebView extends Themable { const executionCount = parseInt(executionMatch[1], 10); if (!isNaN(executionCount)) { const notebookModel = this.notebookService.getNotebookTextModel(notebookResource); - const cell = notebookModel?.cells.find(cell => { + // look for the most recently added cell with the matching execution count + // more likely to be correct in notebooks, an much more likely for the interactive window + const cell = notebookModel?.cells.slice().reverse().find(cell => { return cell.internalMetadata.executionOrder === executionCount; }); if (cell?.uri) { From 4c2c49d5b0b27c5e3e22c5e23d364e8859286b7f Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 18 Oct 2023 10:26:25 -0700 Subject: [PATCH 276/290] added line link --- extensions/notebook-renderers/src/stackTraceHelper.ts | 10 +++++++++- .../src/test/stackTraceHelper.test.ts | 8 +++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index df326592935..9238f74222e 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -34,7 +34,7 @@ const fileRegex = /File\s+(?:\u001b\[.+?m)?(.+):(\d+)/; const lineNumberRegex = /((?:\u001b\[.+?m)?[ ->]*?)(\d+)(.*)/; const cellRegex = /(Cell\s+(?:\u001b\[.+?m)?In\s*\[(\d+)\])(,\s*line \d+)/; // older versions of IPython ~8.3.0 -const inputRegex = /(Input\s+?(?:\u001b\[.+?m)In\s*\[(\d+)\])(.*?)/; +const inputRegex = /(Input\s+?(?:\u001b\[.+?m)In\s*\[(\d+)\])(.*)/; function isIpythonStackTrace(stack: string) { return cellRegex.test(stack) || inputRegex.test(stack) || fileRegex.test(stack); @@ -65,6 +65,10 @@ function linkifyStack(stack: string) { } else if (cellRegex.test(original)) { lines[i] = original.replace(cellRegex, (_s, cellLabel, executionCount, suffix) => { fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution_count=${stripFormatting(executionCount)}` }; + const lineNumberMatch = /line (\d+)/i.exec(suffix); + if (lineNumberMatch) { + suffix = `, line ${lineNumberMatch[1]}`; + } return `${stripFormatting(cellLabel)}${suffix}`; }); @@ -72,6 +76,10 @@ function linkifyStack(stack: string) { } else if (inputRegex.test(original)) { lines[i] = original.replace(inputRegex, (_s, cellLabel, executionCount, suffix) => { fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution_count=${stripFormatting(executionCount)}` }; + const lineNumberMatch = //i.exec(suffix); + if (lineNumberMatch) { + suffix = `, line ${lineNumberMatch[1]}`; + } return `${stripFormatting(cellLabel)}${suffix}`; }); diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index 8a72201aa2e..cdf0af4f05d 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -33,6 +33,7 @@ suite('StackTraceHelper', () => { const formatted = formatStackTrace(stack); assert.ok(formatted.indexOf('Cell In[3]') > 0, formatted); + assert.ok(formatted.indexOf('line 2') > 0, formatted); assert.ok(formatted.indexOf('2') > 0, formatted); assert.ok(formatted.indexOf('2') > 0, formatted); }); @@ -42,12 +43,13 @@ suite('StackTraceHelper', () => { '\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n' + '\u001b[1;31mException\u001b[0m Traceback (most recent call last)\n' + 'Input \u001b[1;32mIn [2]\u001b[0m, in \u001b[0;36m\u001b[1;34m()\u001b[0m\n' + - '\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmyLib\u001b[39;00m\n' + - '\u001b[1;32m----> 2\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n'; + '\u001b[0;32m 4\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmyLib\u001b[39;00m\n' + + '\u001b[1;32m----> 5\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n'; const formatted = formatStackTrace(stack); assert.ok(formatted.indexOf('Input In [2]') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); + assert.ok(formatted.indexOf('line 5') > 0, formatted); + assert.ok(formatted.indexOf('5') > 0, formatted); }); test('IPython stack trace lines without associated location are not linkified', () => { From de13a70b430de9f9a7c1c72ec253f7f92681e70d Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 18 Oct 2023 10:37:58 -0700 Subject: [PATCH 277/290] clean up --- .../browser/view/renderers/backLayerWebView.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index bd9bdd0e7e8..b30fabc2a64 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -765,7 +765,7 @@ export class BackLayerWebView extends Themable { this.openerService.open(data.href, { fromUserGesture: true, fromWorkspace: true }); } else if (matchesScheme(data.href, Schemas.vscodeNotebookCell)) { const uri = URI.parse(data.href); - this._handleNotebookCellResource(uri); + await this._handleNotebookCellResource(uri); } else if (!/^[\w\-]+:/.test(data.href)) { // Uri without scheme, such as a file path this._handleResourceOpening(tryDecodeURIComponent(data.href)); @@ -907,6 +907,8 @@ export class BackLayerWebView extends Themable { } private _handleNotebookCellResource(uri: URI) { + const notebookResource = uri.path.length > 0 ? uri : this.documentUri; + const lineMatch = /(?:^|&)line=([^&]+)/.exec(uri.query); let editorOptions: ITextEditorOptions | undefined = undefined; if (lineMatch) { @@ -921,23 +923,22 @@ export class BackLayerWebView extends Themable { } const executionMatch = /(?:^|&)execution_count=([^&]+)/.exec(uri.query); - const notebookResource = uri.path.length > 0 ? uri : this.documentUri; if (executionMatch) { const executionCount = parseInt(executionMatch[1], 10); if (!isNaN(executionCount)) { const notebookModel = this.notebookService.getNotebookTextModel(notebookResource); - // look for the most recently added cell with the matching execution count - // more likely to be correct in notebooks, an much more likely for the interactive window + // multiple cells with the same execution count can exist if the kernel is restarted + // so look for the most recently added cell with the matching execution count. + // Somewhat more likely to be correct in notebooks, an much more likely for the interactive window const cell = notebookModel?.cells.slice().reverse().find(cell => { return cell.internalMetadata.executionOrder === executionCount; }); if (cell?.uri) { - this.openerService.open(cell.uri, { + return this.openerService.open(cell.uri, { fromUserGesture: true, fromWorkspace: true, editorOptions: editorOptions }); - return; } } } @@ -956,16 +957,15 @@ export class BackLayerWebView extends Themable { selection: { startLineNumber: lineNumber, startColumn: 1, endLineNumber: lineNumber, endColumn: 1 } }; - this.openerService.open(notebookResource.with({ fragment }), { + return this.openerService.open(notebookResource.with({ fragment }), { fromUserGesture: true, fromWorkspace: true, editorOptions: editorOptions }); - return; } } - this.openerService.open(notebookResource, { fromUserGesture: true, fromWorkspace: true }); + return this.openerService.open(notebookResource, { fromUserGesture: true, fromWorkspace: true }); } private _handleResourceOpening(href: string) { From 2b721ec29831459afe2e739724909ece2fa69f65 Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 18 Oct 2023 15:59:27 -0700 Subject: [PATCH 278/290] use named capture groups --- .../src/stackTraceHelper.ts | 30 ++++++------- .../src/test/stackTraceHelper.test.ts | 43 ++++++++++++++----- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/extensions/notebook-renderers/src/stackTraceHelper.ts b/extensions/notebook-renderers/src/stackTraceHelper.ts index 9238f74222e..e72c3b8a88c 100644 --- a/extensions/notebook-renderers/src/stackTraceHelper.ts +++ b/extensions/notebook-renderers/src/stackTraceHelper.ts @@ -32,9 +32,9 @@ export function formatStackTrace(stack: string) { const formatSequence = /\u001b\[.+?m/g; const fileRegex = /File\s+(?:\u001b\[.+?m)?(.+):(\d+)/; const lineNumberRegex = /((?:\u001b\[.+?m)?[ ->]*?)(\d+)(.*)/; -const cellRegex = /(Cell\s+(?:\u001b\[.+?m)?In\s*\[(\d+)\])(,\s*line \d+)/; +const cellRegex = /(?Cell\s+(?:\u001b\[.+?m)?In\s*\[(?\d+)\],\s*)(?line (?\d+)).*/; // older versions of IPython ~8.3.0 -const inputRegex = /(Input\s+?(?:\u001b\[.+?m)In\s*\[(\d+)\])(.*)/; +const inputRegex = /(?Input\s+?(?:\u001b\[.+?m)(?In\s*\[(?\d+)\]))(?.*)/; function isIpythonStackTrace(stack: string) { return cellRegex.test(stack) || inputRegex.test(stack) || fileRegex.test(stack); @@ -63,25 +63,19 @@ function linkifyStack(stack: string) { continue; } else if (cellRegex.test(original)) { - lines[i] = original.replace(cellRegex, (_s, cellLabel, executionCount, suffix) => { - fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution_count=${stripFormatting(executionCount)}` }; - const lineNumberMatch = /line (\d+)/i.exec(suffix); - if (lineNumberMatch) { - suffix = `, line ${lineNumberMatch[1]}`; - } - return `${stripFormatting(cellLabel)}${suffix}`; - }); + fileOrCell = { + kind: 'cell', + path: stripFormatting(original.replace(cellRegex, 'vscode-notebook-cell:?execution_count=$')) + }; + lines[i] = original.replace(cellRegex, `$\'>line $`); continue; } else if (inputRegex.test(original)) { - lines[i] = original.replace(inputRegex, (_s, cellLabel, executionCount, suffix) => { - fileOrCell = { kind: 'cell', path: `vscode-notebook-cell:?execution_count=${stripFormatting(executionCount)}` }; - const lineNumberMatch = //i.exec(suffix); - if (lineNumberMatch) { - suffix = `, line ${lineNumberMatch[1]}`; - } - return `${stripFormatting(cellLabel)}${suffix}`; - }); + fileOrCell = { + kind: 'cell', + path: stripFormatting(original.replace(inputRegex, 'vscode-notebook-cell:?execution_count=$')) + }; + lines[i] = original.replace(inputRegex, `Input \'>$$`); continue; } else if (!fileOrCell || original.trim() === '') { diff --git a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts index cdf0af4f05d..e65efe3ee29 100644 --- a/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts +++ b/extensions/notebook-renderers/src/test/stackTraceHelper.test.ts @@ -6,6 +6,7 @@ import { formatStackTrace } from '../stackTraceHelper'; import * as assert from 'assert'; +// The stack frames for these tests can be retreived by using the raw json for a notebook with an error suite('StackTraceHelper', () => { test('Non Ipython stack trace is left alone', () => { @@ -18,6 +19,11 @@ suite('StackTraceHelper', () => { assert.equal(formatStackTrace(stack), stack); }); + const formatSequence = /\u001b\[.+?m/g; + function stripAsciiFormatting(text: string) { + return text.replace(formatSequence, ''); + } + test('IPython stack line numbers are linkified', () => { const stack = '\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n' + @@ -31,25 +37,40 @@ suite('StackTraceHelper', () => { '\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m\n\n' + '\u001b[1;31mException\u001b[0m\n:'; - const formatted = formatStackTrace(stack); - assert.ok(formatted.indexOf('Cell In[3]') > 0, formatted); - assert.ok(formatted.indexOf('line 2') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); - assert.ok(formatted.indexOf('2') > 0, formatted); + const formatted = stripAsciiFormatting(formatStackTrace(stack)); + assert.ok(formatted.indexOf('Cell In[3], line 2') > 0, 'Missing line link in ' + formatted); + assert.ok(formatted.indexOf('2') > 0, 'Missing frame link in ' + formatted); + assert.ok(formatted.indexOf('2') > 0, 'Missing frame link in ' + formatted); }); + + test('IPython stack line numbers are linkified for IPython 8.3', () => { + // stack frames within functions do not list the line number, i.e. + // 'Input In [1], in myfunc()' vs + // 'Input In [2], in ()' const stack = '\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n' + '\u001b[1;31mException\u001b[0m Traceback (most recent call last)\n' + 'Input \u001b[1;32mIn [2]\u001b[0m, in \u001b[0;36m\u001b[1;34m()\u001b[0m\n' + - '\u001b[0;32m 4\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmyLib\u001b[39;00m\n' + - '\u001b[1;32m----> 5\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n'; + '\u001b[0;32m 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\'\u001b[39m\u001b[38;5;124mipykernel\u001b[39m\u001b[38;5;124m\'\u001b[39m, ipykernel\u001b[38;5;241m.\u001b[39m__version__)\n' + + '\u001b[0;32m 4\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\'\u001b[39m\u001b[38;5;124mipython\u001b[39m\u001b[38;5;124m\'\u001b[39m, IPython\u001b[38;5;241m.\u001b[39m__version__)\n' + + '\u001b[1;32m----> 5\u001b[0m \u001b[43mmyfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n' + + '\n\n' + + 'Input \u001b[1;32mIn [1]\u001b[0m, in \u001b[0;36mmyfunc\u001b[1;34m()\u001b[0m\n' + + '\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mmyfunc\u001b[39m():\n' + + '\u001b[1;32m----> 4\u001b[0m \u001b[43mmyLib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mthrowEx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n' + + '\n\n' + + 'File \u001b[1;32mC:\\venvs\\myLib.py:2\u001b[0m, in \u001b[0;36mthrowEx\u001b[1;34m()\u001b[0m\n' + + '\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mthrowEx\u001b[39m():\n' + + '\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m\n' + + '\n' + + '\u001b[1;31mException\u001b[0m:\n'; - const formatted = formatStackTrace(stack); - assert.ok(formatted.indexOf('Input In [2]') > 0, formatted); - assert.ok(formatted.indexOf('line 5') > 0, formatted); - assert.ok(formatted.indexOf('5') > 0, formatted); + const formatted = stripAsciiFormatting(formatStackTrace(stack)); + assert.ok(formatted.indexOf('Input \'>In [2], in ') > 0, 'Missing cell link in ' + formatted); + assert.ok(formatted.indexOf('Input \'>In [1], in myfunc()') > 0, 'Missing cell link in ' + formatted); + assert.ok(formatted.indexOf('5') > 0, 'Missing frame link in ' + formatted); }); test('IPython stack trace lines without associated location are not linkified', () => { From 0bef70e27a8fe1fb32db6f17bf71f2c03432bf2d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 19 Oct 2023 09:39:52 -0700 Subject: [PATCH 279/290] Make sure codeactions contribution is an array (#196005) Fixes #196000 --- .../contrib/codeActions/browser/codeActionsContribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts b/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts index 8adbf6243a2..70ca709c5be 100644 --- a/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts +++ b/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts @@ -81,7 +81,7 @@ export class CodeActionsContribution extends Disposable implements IWorkbenchCon super(); codeActionsExtensionPoint.setHandler(extensionPoints => { - this._contributedCodeActions = extensionPoints.flatMap(x => x.value); + this._contributedCodeActions = extensionPoints.flatMap(x => x.value).filter(x => Array.isArray(x.actions)); this.updateConfigurationSchema(this._contributedCodeActions); this._onDidChangeContributions.fire(); }); From b598801d4ac5e0e21dbc80a426baa1df200de36b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 19 Oct 2023 19:11:52 +0200 Subject: [PATCH 280/290] Make streaming edits so that each line is typed out according to the response speed (#196010) --- .../browser/inlineChatController.ts | 25 ++-- .../browser/inlineChatLivePreviewWidget.ts | 6 + .../browser/inlineChatStrategies.ts | 117 ++++++++++++++++-- .../inlineChat/browser/inlineChatWidget.ts | 1 + 4 files changed, 131 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 4e15cd82405..e2fadfb2e21 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -25,7 +25,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { EditResponse, EmptyResponse, ErrorResponse, ExpansionState, IInlineChatSessionService, MarkdownResponse, Session, SessionExchange, SessionPrompt } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; -import { EditModeStrategy, LivePreviewStrategy, LiveStrategy, PreviewStrategy } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies'; +import { EditModeStrategy, LivePreviewStrategy, LiveStrategy, PreviewStrategy, ProgressingEditsOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies'; import { InlineChatZoneWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatWidget'; import { CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_LAST_FEEDBACK, IInlineChatRequest, IInlineChatResponse, INLINE_CHAT_ID, EditMode, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, InlineChatResponseType, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, InlineChateResponseTypes, CTX_INLINE_CHAT_RESPONSE_TYPES, CTX_INLINE_CHAT_USER_DID_EDIT, IInlineChatProgressItem } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { IChatAccessibilityService, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; @@ -38,6 +38,7 @@ import { TextEdit } from 'vs/editor/common/languages'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { onUnexpectedError } from 'vs/base/common/errors'; import { MarkdownString } from 'vs/base/common/htmlContent'; +import { MovingAverage } from 'vs/base/common/numbers'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', @@ -247,8 +248,8 @@ export class InlineChatController implements IEditorContribution { } } if (this._activeSession) { - this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.wholeRange.value); widgetPosition = this._strategy?.getWidgetPosition() ?? widgetPosition; + this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.wholeRange.value); } this._zone.value.show(widgetPosition); } @@ -556,6 +557,9 @@ export class InlineChatController implements IEditorContribution { const progressEdits: TextEdit[][] = []; const markdownContents = new MarkdownString('', { supportThemeIcons: true, supportHtml: true, isTrusted: false }); + const avgDuration = new MovingAverage(); + let round = 0; + let t1 = Date.now(); const progress = new AsyncProgress(async data => { this._log('received chunk', data, request); if (data.message) { @@ -573,8 +577,11 @@ export class InlineChatController implements IEditorContribution { throw new Error('Progress in NOT supported in non-live mode'); } progressEdits.push(data.edits); - await this._makeChanges(data.edits, true); - await this._strategy?.renderProgressChanges(); + avgDuration.update(Date.now() - t1); + await this._makeChanges(data.edits, true, { duration: avgDuration.value, round: round++ }); + t1 = Date.now(); // don't measure how long `_makeChanges` takes + // TODO@jrieken this still isn't the true speed because the progress itself is async which + // makes an artifical queue, so that towards the end duration (now() -t1) is almost 0 } if (data.markdownFragment) { markdownContents.appendMarkdown(data.markdownFragment); @@ -601,7 +608,7 @@ export class InlineChatController implements IEditorContribution { } else if (reply) { const editResponse = new EditResponse(this._activeSession.textModelN.uri, modelAltVersionIdNow, reply, progressEdits); for (let i = progressEdits.length; i < editResponse.allLocalEdits.length; i++) { - await this._makeChanges(editResponse.allLocalEdits[i], true); + await this._makeChanges(editResponse.allLocalEdits[i], true, undefined); } response = editResponse; } else { @@ -656,7 +663,7 @@ export class InlineChatController implements IEditorContribution { return State.SHOW_RESPONSE; } - private async _makeChanges(lastEdits: TextEdit[], computeMoreMinimalEdits: boolean) { + private async _makeChanges(lastEdits: TextEdit[], computeMoreMinimalEdits: boolean, opts: ProgressingEditsOptions | undefined) { assertType(this._activeSession); assertType(this._strategy); @@ -673,7 +680,11 @@ export class InlineChatController implements IEditorContribution { try { this._ignoreModelContentChanged = true; this._activeSession.wholeRange.trackEdits(editOperations); - await this._strategy.makeChanges(editOperations); + if (opts) { + await this._strategy.makeProgressiveChanges(editOperations, opts); + } else { + await this._strategy.makeChanges(editOperations); + } this._ctxDidEdit.set(this._activeSession.hasChangedText); } finally { this._ignoreModelContentChanged = false; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index c95b92258bc..321f358f16c 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -48,6 +48,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { private _dim: Dimension | undefined; private _isVisible: boolean = false; + private _lineRanges: readonly LineRangeMapping[] | undefined; constructor( editor: ICodeEditor, @@ -145,6 +146,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { this._cleanupFullDiff(); super.hide(); this._isVisible = false; + this._lineRanges = undefined; } override show(): void { @@ -154,6 +156,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { showForChanges(changes: readonly LineRangeMapping[]): void { const hasFocus = this._diffEditor.hasTextFocus(); this._isVisible = true; + this._lineRanges = changes; const onlyInserts = changes.every(change => change.original.isEmpty); @@ -178,6 +181,9 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { } } + get startLine(): number | undefined { + return this._lineRanges?.[0]?.modified.startLineNumber; + } private _renderInsertWithHighlight(changes: readonly LineRangeMapping[]) { assertType(this.editor.hasModel()); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index a3447e3b5a9..232f72d70f9 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -4,24 +4,27 @@ *--------------------------------------------------------------------------------------------*/ import { equals, tail } from 'vs/base/common/arrays'; +import { AsyncIterableObject, DeferredAsyncIterableObject } from 'vs/base/common/async'; import { Event } from 'vs/base/common/event'; import { Lazy } from 'vs/base/common/lazy'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; -import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; +import { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; +import { IRange } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { LineRangeMapping } from 'vs/editor/common/diff/rangeMapping'; import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon'; import { TextEdit } from 'vs/editor/common/languages'; -import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model'; +import { ICursorStateComputer, IIdentifiedSingleEditOperation, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation, TrackedRangeStickiness } from 'vs/editor/common/model'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { countWords, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter'; import { InlineChatFileCreatePreviewWidget, InlineChatLivePreviewWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget'; import { EditResponse, Session } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; import { InlineChatWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatWidget'; @@ -38,12 +41,12 @@ export abstract class EditModeStrategy { abstract cancel(): Promise; + abstract makeProgressiveChanges(edits: ISingleEditOperation[], timings: { duration: number }): Promise; + abstract makeChanges(edits: ISingleEditOperation[]): Promise; abstract undoChanges(altVersionId: number): Promise; - abstract renderProgressChanges(): Promise; - abstract renderChanges(response: EditResponse): Promise; abstract hasFocus(): boolean; @@ -126,7 +129,7 @@ export class PreviewStrategy extends EditModeStrategy { // nothing to do } - override async renderProgressChanges(): Promise { + override async makeProgressiveChanges(): Promise { // nothing to do } @@ -225,6 +228,11 @@ class InlineDiffDecorations { } } +export interface ProgressingEditsOptions { + duration: number; + round: number; +} + export class LiveStrategy extends EditModeStrategy { protected _diffEnabled: boolean = false; @@ -322,8 +330,19 @@ export class LiveStrategy extends EditModeStrategy { LiveStrategy._undoModelUntil(textModelN, altVersionId); } - override async renderProgressChanges(): Promise { - // nothing to do + override async makeProgressiveChanges(edits: ISingleEditOperation[], opts: ProgressingEditsOptions): Promise { + + if (opts.round === 0) { + this._session.textModelN.pushStackElement(); + } + + const durationInSec = opts.duration / 1000; + for (const edit of edits) { + const wordCount = countWords(edit.text ?? ''); + const speed = wordCount / durationInSec; + // console.log({ durationInSec, wordCount, speed: wordCount / durationInSec }); + await performAsyncTextEdit(this._session.textModelN, asProgressiveEdit(edit, speed)); + } } override async renderChanges(response: EditResponse) { @@ -474,8 +493,9 @@ export class LivePreviewStrategy extends LiveStrategy { } } - override async renderProgressChanges(): Promise { - return this._renderDiffZones(); + override async makeProgressiveChanges(edits: ISingleEditOperation[], timings: { duration: number; round: number }): Promise { + await super.makeProgressiveChanges(edits, timings); + await this._renderDiffZones(); } override async renderChanges(response: EditResponse) { @@ -496,9 +516,15 @@ export class LivePreviewStrategy extends LiveStrategy { override getWidgetPosition(): Position | undefined { for (let i = this._diffZonePool.length - 1; i >= 0; i--) { const zone = this._diffZonePool[i]; - if (zone.isVisible && zone.position) { + if (zone.isVisible) { // above last view zone - return zone.position; + if (zone.position) { + // can be undefined when the zone isn't attached yet + return zone.position; + } + if (zone.startLine) { + return new Position(zone.startLine, 1); + } } } return undefined; @@ -511,3 +537,72 @@ function showSingleCreateFile(accessor: ServicesAccessor, edit: EditResponse) { editorService.openEditor({ resource: edit.singleCreateFileEdit.uri }, SIDE_GROUP); } } + +export interface AsyncTextEdit { + readonly range: IRange; + readonly newText: AsyncIterable; +} + +export async function performAsyncTextEdit(model: ITextModel, edit: AsyncTextEdit) { + + const [id] = model.deltaDecorations([], [{ + range: edit.range, + options: { + description: 'asyncTextEdit', + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges + } + }]); + + let first = true; + for await (const part of edit.newText) { + + if (model.isDisposed()) { + break; + } + + const range = model.getDecorationRange(id); + if (!range) { + throw new Error('FAILED to perform async replace edit because the anchor decoration was removed'); + } + + const edit = first + ? EditOperation.replace(range, part) // first edit needs to override the "anchor" + : EditOperation.insert(range.getEndPosition(), part); + + model.pushEditOperations(null, [edit], () => null); + first = false; + } +} + +export function asAsyncEdit(edit: IIdentifiedSingleEditOperation): AsyncTextEdit { + return { + range: edit.range, + newText: AsyncIterableObject.fromArray([edit.text ?? '']) + } satisfies AsyncTextEdit; +} + +export function asProgressiveEdit(edit: IIdentifiedSingleEditOperation, wordsPerSec: number): AsyncTextEdit { + + wordsPerSec = Math.max(10, wordsPerSec); + + const stream = new DeferredAsyncIterableObject(); + let newText = edit.text ?? ''; + // const wordCount = countWords(newText); + + const handle = setInterval(() => { + + const r = getNWords(newText, 1); + stream.emit(r.value); + newText = newText.substring(r.value.length); + if (r.isFullString) { + clearInterval(handle); + stream.complete(); + } + + }, 1000 / wordsPerSec); + + return { + range: edit.range, + newText: stream.asyncIterable + }; +} diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index a4223bb8d8d..b94166b5110 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -923,6 +923,7 @@ export class InlineChatZoneWidget extends ZoneWidget { } override show(position: Position): void { + position = position.lineNumber === 1 ? position.delta(-1) : position; super.show(position, this._computeHeightInLines()); this.widget.focus(); this._ctxVisible.set(true); From b99baeb1f54710d026dd27cd86e284bf1e1bc5c2 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 19 Oct 2023 10:50:48 -0700 Subject: [PATCH 281/290] fix #195998 --- .../accessibility/browser/accessibleNotificationService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts index 7e8503931d9..407af81c487 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleNotificationService.ts @@ -53,7 +53,6 @@ export class AccessibleNotificationService extends Disposable implements IAccess const audioCueSetting: NotificationSetting = this._configurationService.getValue(audioCue.settingsKey); if (this._shouldNotify(audioCueSetting, userGesture)) { this._logService.debug('AccessibleNotificationService playing sound: ', audioCue.name); - console.log('AccessibleNotificationService playing sound: ', audioCue.name); // Play sound bypasses the usual audio cue checks IE screen reader optimized, auto, etc. this._audioCueService.playSound(audioCue.sound.getSound(), true); return; @@ -61,7 +60,6 @@ export class AccessibleNotificationService extends Disposable implements IAccess const alertSettingValue: NotificationSetting = this._configurationService.getValue(alertSetting); if (this._shouldNotify(alertSettingValue, userGesture)) { this._logService.debug('AccessibleNotificationService alerting: ', alertMessage); - console.log('AccessibleNotificationService alerting: ', alertMessage); this._accessibilityService.alert(alertMessage); } } From 0f7dcd90a8aa4a66c34e891a4ee11c2ad04e3842 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 19 Oct 2023 10:44:41 -0700 Subject: [PATCH 282/290] cli: fix description for built-in serve-web command --- src/vs/platform/environment/node/argv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 49a204179ba..79046c7fa20 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -70,7 +70,7 @@ export const OPTIONS: OptionDescriptions> = { }, 'serve-web': { type: 'subcommand', - description: 'Make the current machine accessible from vscode.dev or other machines through a secure tunnel', + description: 'Run a server that displays the editor UI in browsers.', options: { 'cli-data-dir': { type: 'string', args: 'dir', description: localize('cliDataDir', "Directory where CLI metadata should be stored.") }, 'disable-telemetry': { type: 'boolean' }, From 31a23ea65c95894b9dbb841d6ae35f85a79c313a Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 19 Oct 2023 11:12:40 -0700 Subject: [PATCH 283/290] fix #195990 --- .../accessibility/browser/accessibleView.ts | 20 +++++++++++--- .../terminalAccessibleBufferProvider.ts | 26 +------------------ 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index c73385b4246..324d3c04b43 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -34,6 +34,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { IContextViewDelegate, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess'; @@ -499,7 +500,7 @@ export class AccessibleView extends Disposable { }); this._updateToolbar(provider.actions, provider.options.type); - const handleEscape = (e: KeyboardEvent | IKeyboardEvent): void => { + const hide = (e: KeyboardEvent | IKeyboardEvent): void => { e.stopPropagation(); this._contextViewService.hideContextView(); this._updateContextKeys(provider, false); @@ -508,8 +509,8 @@ export class AccessibleView extends Disposable { }; const disposableStore = new DisposableStore(); disposableStore.add(this._editorWidget.onKeyDown((e) => { - if (e.keyCode === KeyCode.Escape) { - handleEscape(e); + if (e.keyCode === KeyCode.Escape || shouldHide(e.browserEvent, this._keybindingService)) { + hide(e); } else if (e.keyCode === KeyCode.KeyH && provider.options.readMoreUrl) { const url: string = provider.options.readMoreUrl!; alert(AccessibilityHelpNLS.openingDocs); @@ -522,7 +523,7 @@ export class AccessibleView extends Disposable { disposableStore.add(addDisposableListener(this._toolbar.getElement(), EventType.KEY_DOWN, (e: KeyboardEvent) => { const keyboardEvent = new StandardKeyboardEvent(e); if (keyboardEvent.equals(KeyCode.Escape)) { - handleEscape(e); + hide(e); } })); disposableStore.add(this._editorWidget.onDidBlurEditorWidget(() => { @@ -765,3 +766,14 @@ export interface IAccessibleViewSymbol extends IPickerQuickAccessItem { firstListItem?: string; lineNumber?: number; } + +function shouldHide(event: KeyboardEvent, keybindingService: IKeybindingService): boolean { + const standardKeyboardEvent = new StandardKeyboardEvent(event); + const resolveResult = keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); + + const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded; + if (keybindingService.inChordMode || isValidChord) { + return false; + } + return event.key.length === 1 && !event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey; +} diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts index 36988986a57..b13925febeb 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleBufferProvider.ts @@ -3,15 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/model'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver'; import { TerminalCapability, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ICurrentPartialCommand } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; @@ -34,9 +30,7 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements @IModelService _modelService: IModelService, @IConfigurationService configurationService: IConfigurationService, @IContextKeyService _contextKeyService: IContextKeyService, - @ITerminalService _terminalService: ITerminalService, - @IKeybindingService private readonly _keybindingService: IKeybindingService, - @IContextViewService private readonly _contextViewService: IContextViewService + @ITerminalService _terminalService: ITerminalService ) { super(); this.options.customHelp = customHelp; @@ -56,14 +50,6 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements })); } - onKeyDown(e: IKeyboardEvent): void { - if (!shouldFocusTerminal(e.browserEvent, this._keybindingService)) { - return; - } - this._contextViewService.hideContextView(); - this._instance.focus(); - } - onClose() { this._instance.focus(); } @@ -130,13 +116,3 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements } export interface ICommandWithEditorLine { command: ITerminalCommand | ICurrentPartialCommand; lineNumber: number } -function shouldFocusTerminal(event: KeyboardEvent, keybindingService: IKeybindingService): boolean { - const standardKeyboardEvent = new StandardKeyboardEvent(event); - const resolveResult = keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); - - const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded; - if (keybindingService.inChordMode || isValidChord) { - return false; - } - return event.key.length === 1 && !event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey; -} From 4ca813237c7ab368a6f86e67817e155fcab62404 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Thu, 19 Oct 2023 11:20:45 -0700 Subject: [PATCH 284/290] Fix toolbar padding-inline-start regression --- src/vs/workbench/contrib/chat/browser/media/chat.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index d8c8fe803e5..58e6ae06adf 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -279,6 +279,9 @@ margin: 0 0 8px 0; } +.interactive-item-container .interactive-result-code-block .monaco-toolbar .monaco-action-bar .actions-container { + padding-inline-start: unset; +} .interactive-response .interactive-response-error-details { display: flex; From b4aeaa52ca43a29cc3c57d021248ce6a7fff968a Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Thu, 19 Oct 2023 10:47:29 -0700 Subject: [PATCH 285/290] dont focus output if for certain link clicks --- .../browser/view/renderers/webviewPreloads.ts | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 113c4dc11af..2ca6b9cda0f 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -162,12 +162,12 @@ async function webviewPreloads(ctx: PreloadContext) { return; } + let outputFocus: { id: string } | undefined = undefined; for (const node of event.composedPath()) { if (node instanceof HTMLElement && node.classList.contains('output')) { - // output - postNotebookMessage('outputFocus', { - id: node.id, - }); + outputFocus = { + id: node.id + }; break; } } @@ -175,8 +175,15 @@ async function webviewPreloads(ctx: PreloadContext) { for (const node of event.composedPath()) { if (node instanceof HTMLAnchorElement && node.href) { if (node.href.startsWith('blob:')) { + if (outputFocus) { + postNotebookMessage('outputFocus', outputFocus); + } + handleBlobUrlClick(node.href, node.download); } else if (node.href.startsWith('data:')) { + if (outputFocus) { + postNotebookMessage('outputFocus', outputFocus); + } handleDataUrl(node.href, node.download); } else if (node.getAttribute('href')?.trim().startsWith('#')) { // Scrolling to location within current doc @@ -209,6 +216,9 @@ async function webviewPreloads(ctx: PreloadContext) { } else { const href = node.getAttribute('href'); if (href) { + if (href.startsWith('command:') && outputFocus) { + postNotebookMessage('outputFocus', outputFocus); + } postNotebookMessage('clicked-link', { href }); } } @@ -218,6 +228,10 @@ async function webviewPreloads(ctx: PreloadContext) { return; } } + + if (outputFocus) { + postNotebookMessage('outputFocus', outputFocus); + } }; const handleDataUrl = async (data: string | ArrayBuffer | null, downloadName: string) => { From 518ee1937e59e24cf67fee2026cd781081809d77 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 19 Oct 2023 12:49:53 -0700 Subject: [PATCH 286/290] Fix showing agent and slash completions after text in chat (#196030) --- .../chat/browser/contrib/chatInputEditorContrib.ts | 11 ++++++++--- .../workbench/contrib/chat/common/chatParserTypes.ts | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index e6d57bf6efb..1376e00ddde 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -29,7 +29,7 @@ import { ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget'; import { SelectAndInsertFileAction, dynamicReferenceDecorationType } from 'vs/workbench/contrib/chat/browser/contrib/chatDynamicReferences'; import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { chatSlashCommandBackground, chatSlashCommandForeground } from 'vs/workbench/contrib/chat/common/chatColors'; -import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes'; +import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser'; import { IChatService, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables'; @@ -330,6 +330,11 @@ class AgentCompletions extends Disposable { return null; } + if (!model.getValue().trim().match(new RegExp(`^${chatAgentLeader}\\w*$`))) { + // Only when the input only contains the start of an agent + return; + } + const parsedRequest = (await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(widget.viewModel.sessionId, model.getValue())).parts; const usedAgent = parsedRequest.find(p => p instanceof ChatRequestAgentPart); if (usedAgent && !Range.containsPosition(usedAgent.editorRange, position)) { @@ -420,8 +425,8 @@ class AgentCompletions extends Disposable { return; } - if (model.getValue().trim() !== '/') { - // Only when the input only contains a slash + if (!model.getValue().trim().match(new RegExp(`^${chatSubcommandLeader}\\w*$`))) { + // Only when the input only contains the start of a slash command return; } diff --git a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts index 5c9e368d58e..a44a92d6bdf 100644 --- a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts @@ -34,7 +34,10 @@ export class ChatRequestTextPart implements IParsedChatRequestPart { } } -export const chatVariableLeader = '#'; // warning, this also shows up in a regex in the parser +// warning, these also show up in a regex in the parser +export const chatVariableLeader = '#'; +export const chatAgentLeader = '@'; +export const chatSubcommandLeader = '/'; /** * An invocation of a static variable that can be resolved by the variable service From 33dca2ce7f3fd2b5492c92d8b4abc2a80d05ad1e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 19 Oct 2023 22:38:26 +0200 Subject: [PATCH 287/290] fix #195997 (#196007) --- .../browser/parts/auxiliarybar/media/auxiliaryBarPart.css | 8 ++++++++ .../workbench/browser/parts/sidebar/media/sidebarpart.css | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css b/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css index 2c0c99d85cc..0b2a5c80740 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css +++ b/src/vs/workbench/browser/parts/auxiliarybar/media/auxiliaryBarPart.css @@ -31,3 +31,11 @@ .monaco-workbench .part.auxiliarybar > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item:not(.checked):hover .action-label { outline: var(--vscode-contrastActiveBorder, unset) dashed 1px !important; } + +.monaco-workbench .auxiliarybar.part.pane-composite-part > .composite.title.has-composite-bar > .title-actions { + flex: inherit; +} + +.monaco-workbench .auxiliarybar.pane-composite-part > .title.has-composite-bar > .title-actions .monaco-action-bar .action-item { + max-width: 150px; +} diff --git a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css index 4b0289f87ef..5d0a0da2e63 100644 --- a/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css +++ b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css @@ -63,3 +63,11 @@ .monaco-workbench .sidebar.pane-composite-part > .title > .composite-bar-container { flex: 1; } + +.monaco-workbench .sidebar.part.pane-composite-part > .composite.title.has-composite-bar > .title-actions { + flex: inherit; +} + +.monaco-workbench .sidebar.pane-composite-part > .title.has-composite-bar > .title-actions .monaco-action-bar .action-item { + max-width: 150px; +} From fa3f2cc6936e632ee2c603ea34dcd59b72de46e9 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 19 Oct 2023 13:52:31 -0700 Subject: [PATCH 288/290] fix #196039 --- .../editor/contrib/format/browser/format.ts | 32 ------------------- .../contrib/format/browser/formatActions.ts | 3 +- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/vs/editor/contrib/format/browser/format.ts b/src/vs/editor/contrib/format/browser/format.ts index 6bd3ef94d3f..1f7518057ac 100644 --- a/src/vs/editor/contrib/format/browser/format.ts +++ b/src/vs/editor/contrib/format/browser/format.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { alert } from 'vs/base/browser/ui/aria/aria'; import { asArray, isNonEmptyArray } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; @@ -20,12 +19,10 @@ import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; -import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, FormattingOptions, TextEdit } from 'vs/editor/common/languages'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FormattingEdit } from 'vs/editor/contrib/format/browser/formattingEdit'; -import * as nls from 'vs/nls'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ExtensionIdentifierSet } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -35,33 +32,6 @@ import { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistr import { ILogService } from 'vs/platform/log/common/log'; import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; -export function alertFormattingEdits(edits: ISingleEditOperation[]): void { - - edits = edits.filter(edit => edit.range); - if (!edits.length) { - return; - } - - let { range } = edits[0]; - for (let i = 1; i < edits.length; i++) { - range = Range.plusRange(range, edits[i].range); - } - const { startLineNumber, endLineNumber } = range; - if (startLineNumber === endLineNumber) { - if (edits.length === 1) { - alert(nls.localize('hint11', "Made 1 formatting edit on line {0}", startLineNumber)); - } else { - alert(nls.localize('hintn1', "Made {0} formatting edits on line {1}", edits.length, startLineNumber)); - } - } else { - if (edits.length === 1) { - alert(nls.localize('hint1n', "Made 1 formatting edit between lines {0} and {1}", startLineNumber, endLineNumber)); - } else { - alert(nls.localize('hintnn', "Made {0} formatting edits between lines {1} and {2}", edits.length, startLineNumber, endLineNumber)); - } - } -} - export function getRealAndSyntheticDocumentFormattersOrdered( documentFormattingEditProvider: LanguageFeatureRegistry, documentRangeFormattingEditProvider: LanguageFeatureRegistry, @@ -280,7 +250,6 @@ export async function formatDocumentRangesWithProvider( if (isCodeEditor(editorOrModel)) { // use editor to apply edits FormattingEdit.execute(editorOrModel, allEdits, true); - alertFormattingEdits(allEdits); editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), ScrollType.Immediate); } else { @@ -374,7 +343,6 @@ export async function formatDocumentWithProvider( FormattingEdit.execute(editorOrModel, edits, mode !== FormattingMode.Silent); if (mode !== FormattingMode.Silent) { - alertFormattingEdits(edits); editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), ScrollType.Immediate); } diff --git a/src/vs/editor/contrib/format/browser/formatActions.ts b/src/vs/editor/contrib/format/browser/formatActions.ts index 3ba32683d95..733b909ae6d 100644 --- a/src/vs/editor/contrib/format/browser/formatActions.ts +++ b/src/vs/editor/contrib/format/browser/formatActions.ts @@ -18,7 +18,7 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; -import { alertFormattingEdits, formatDocumentRangesWithSelectedProvider, formatDocumentWithSelectedProvider, FormattingMode, getOnTypeFormattingEdits } from 'vs/editor/contrib/format/browser/format'; +import { formatDocumentRangesWithSelectedProvider, formatDocumentWithSelectedProvider, FormattingMode, getOnTypeFormattingEdits } from 'vs/editor/contrib/format/browser/format'; import { FormattingEdit } from 'vs/editor/contrib/format/browser/formattingEdit'; import * as nls from 'vs/nls'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; @@ -142,7 +142,6 @@ export class FormatOnType implements IEditorContribution { } if (isNonEmptyArray(edits)) { FormattingEdit.execute(this._editor, edits, true); - alertFormattingEdits(edits); } }).finally(() => { unbind.dispose(); From 5d1a6be2323a5db86bd1a3200e98054212f30610 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 19 Oct 2023 14:04:19 -0700 Subject: [PATCH 289/290] alert clear when action is run from acc view --- .../browser/accessibilityContributions.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts index 4b288d0dc48..643099e1da6 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts @@ -43,7 +43,7 @@ import { CommentAccessibilityHelpNLS } from 'vs/workbench/contrib/comments/brows import { CommentCommandId } from 'vs/workbench/contrib/comments/common/commentCommandIds'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { AudioCue } from 'vs/platform/audioCues/browser/audioCueService'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { AccessibleNotificationEvent, IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility'; export class EditorAccessibilityHelpContribution extends Disposable { static ID: 'editorAccessibilityHelpContribution'; @@ -228,6 +228,7 @@ export class NotificationAccessibleViewContribution extends Disposable { const accessibleViewService = accessor.get(IAccessibleViewService); const listService = accessor.get(IListService); const commandService = accessor.get(ICommandService); + const accessibleNotificationService = accessor.get(IAccessibleNotificationService); function renderAccessibleView(): boolean { const notification = getNotificationFromContext(listService); @@ -288,7 +289,7 @@ export class NotificationAccessibleViewContribution extends Disposable { }, verbositySettingKey: AccessibilityVerbositySettingId.Notification, options: { type: AccessibleViewType.View }, - actions: getActionsFromNotification(notification) + actions: getActionsFromNotification(notification, accessibleNotificationService) }); return true; } @@ -297,7 +298,7 @@ export class NotificationAccessibleViewContribution extends Disposable { } } -function getActionsFromNotification(notification: INotificationViewItem): IAction[] | undefined { +function getActionsFromNotification(notification: INotificationViewItem, accessibleNotificationService: IAccessibleNotificationService): IAction[] | undefined { let actions = undefined; if (notification.actions) { actions = []; @@ -323,7 +324,12 @@ function getActionsFromNotification(notification: INotificationViewItem): IActio manageExtension.class = ThemeIcon.asClassName(Codicon.gear); } if (actions) { - actions.push({ id: 'clearNotification', label: localize('clearNotification', "Clear Notification"), tooltip: localize('clearNotification', "Clear Notification"), run: () => notification.close(), enabled: true, class: ThemeIcon.asClassName(Codicon.clearAll) }); + actions.push({ + id: 'clearNotification', label: localize('clearNotification', "Clear Notification"), tooltip: localize('clearNotification', "Clear Notification"), run: () => { + notification.close(); + accessibleNotificationService.notify(AccessibleNotificationEvent.Clear); + }, enabled: true, class: ThemeIcon.asClassName(Codicon.clearAll) + }); } return actions; } From a2aed6d28f71811cb2ea15ba042d8f9918b0db5a Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 19 Oct 2023 23:17:21 +0200 Subject: [PATCH 290/290] add InteractiveEditorSession.input (#196045) --- src/vs/workbench/api/common/extHostInlineChat.ts | 1 + .../contrib/inlineChat/browser/inlineChatController.ts | 2 +- src/vs/workbench/contrib/inlineChat/common/inlineChat.ts | 1 + src/vscode-dts/vscode.proposed.interactive.d.ts | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostInlineChat.ts b/src/vs/workbench/api/common/extHostInlineChat.ts index 90b1900d4e8..5612bac33fd 100644 --- a/src/vs/workbench/api/common/extHostInlineChat.ts +++ b/src/vs/workbench/api/common/extHostInlineChat.ts @@ -127,6 +127,7 @@ export class ExtHostInteractiveEditor implements ExtHostInlineChatShape { return { id, placeholder: session.placeholder, + input: session.input, slashCommands: session.slashCommands?.map(c => ({ command: c.command, detail: c.detail, refer: c.refer, executeImmediately: c.executeImmediately })), wholeRange: typeConvert.Range.from(session.wholeRange), message: session.message diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index e2fadfb2e21..75edb299587 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -354,7 +354,7 @@ export class InlineChatController implements IEditorContribution { this._updatePlaceholder(); this._zone.value.widget.updateInfo(this._activeSession.session.message ?? localize('welcome.1', "AI-generated code may be incorrect")); this._zone.value.widget.preferredExpansionState = this._activeSession.lastExpansionState; - this._zone.value.widget.value = this._activeSession.lastInput?.value ?? this._zone.value.widget.value; + this._zone.value.widget.value = this._activeSession.session.input ?? this._activeSession.lastInput?.value ?? this._zone.value.widget.value; this._sessionStore.add(this._zone.value.widget.onDidChangeInput(_ => { const start = this._zone.value.position; if (!start || !this._zone.value.widget.hasFocus() || !this._zone.value.widget.value || !this._editor.hasModel()) { diff --git a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts index 807bbb2c2c0..73ed2a13340 100644 --- a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts +++ b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts @@ -31,6 +31,7 @@ export interface IInlineChatSlashCommand { export interface IInlineChatSession { id: number; placeholder?: string; + input?: string; message?: string; slashCommands?: IInlineChatSlashCommand[]; wholeRange?: IRange; diff --git a/src/vscode-dts/vscode.proposed.interactive.d.ts b/src/vscode-dts/vscode.proposed.interactive.d.ts index 262522a6710..8df047e4764 100644 --- a/src/vscode-dts/vscode.proposed.interactive.d.ts +++ b/src/vscode-dts/vscode.proposed.interactive.d.ts @@ -20,6 +20,7 @@ declare module 'vscode' { // todo@API make classes export interface InteractiveEditorSession { placeholder?: string; + input?: string; slashCommands?: InteractiveEditorSlashCommand[]; wholeRange?: Range; message?: string;