From af20479b57fddab63c842515357ebe3ca8f183e6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 1 Apr 2022 03:02:38 -0700 Subject: [PATCH 001/135] Allow null in terminal defaultProfile enum Fixes #146437 --- src/vs/platform/terminal/common/terminalProfiles.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/terminal/common/terminalProfiles.ts b/src/vs/platform/terminal/common/terminalProfiles.ts index 1b4d411e501..37b166d82c1 100644 --- a/src/vs/platform/terminal/common/terminalProfiles.ts +++ b/src/vs/platform/terminal/common/terminalProfiles.ts @@ -5,19 +5,24 @@ import { Codicon } from 'vs/base/common/codicons'; import { URI, UriComponents } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; import { IExtensionTerminalProfile, ITerminalProfile, TerminalIcon } from 'vs/platform/terminal/common/terminal'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; export function createProfileSchemaEnums(detectedProfiles: ITerminalProfile[], extensionProfiles?: readonly IExtensionTerminalProfile[]): { - values: string[] | undefined; + values: (string | null)[] | undefined; markdownDescriptions: string[] | undefined; } { - const result = detectedProfiles.map(e => { + const result: { name: string | null; description: string }[] = [{ + name: null, + description: localize('terminalAutomaticProfile', 'Automatically detect the default') + }]; + result.push(...detectedProfiles.map(e => { return { name: e.profileName, description: createProfileDescription(e) }; - }); + })); if (extensionProfiles) { result.push(...extensionProfiles.map(extensionProfile => { return { From 424cc864b537c39c57de68c8a2564595a16ab8ea Mon Sep 17 00:00:00 2001 From: Leonardo Montini Date: Fri, 1 Apr 2022 15:06:08 +0200 Subject: [PATCH 002/135] 143543 replaced true and false with on and off in debug.inlineValues --- src/vs/workbench/contrib/debug/browser/debug.contribution.ts | 2 +- .../workbench/contrib/debug/browser/debugEditorContribution.ts | 2 +- src/vs/workbench/contrib/debug/common/debug.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 11f4ef0ce63..8330e2aab7c 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -419,7 +419,7 @@ configurationRegistry.registerConfiguration({ }, 'debug.inlineValues': { type: ['boolean', 'string'], - 'enum': [true, false, 'auto'], + 'enum': ['on', 'off', 'auto'], description: nls.localize({ comment: ['This is the description for a setting'], key: 'inlineValues' }, "Show variable values inline in editor while debugging."), 'enumDescriptions': [ nls.localize('inlineValues.on', 'Always show variable values inline in editor while debugging.'), diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 81133f8fade..a0fbf2da5a1 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -627,7 +627,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { const model = this.editor.getModel(); const inlineValuesSetting = this.configurationService.getValue('debug').inlineValues; - const inlineValuesTurnedOn = inlineValuesSetting === true || (inlineValuesSetting === 'auto' && model && this.languageFeaturesService.inlineValuesProvider.has(model)); + const inlineValuesTurnedOn = inlineValuesSetting === true || inlineValuesSetting === 'on' || (inlineValuesSetting === 'auto' && model && this.languageFeaturesService.inlineValuesProvider.has(model)); if (!inlineValuesTurnedOn || !model || !stackFrame || model.uri.toString() !== stackFrame.source.uri.toString()) { if (!this.removeInlineValuesScheduler.isScheduled()) { this.removeInlineValuesScheduler.schedule(); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 7fd322d2d11..be21bf957ef 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -611,7 +611,7 @@ export interface IDebugConfiguration { allowBreakpointsEverywhere: boolean; openDebug: 'neverOpen' | 'openOnSessionStart' | 'openOnFirstSessionStart' | 'openOnDebugBreak'; openExplorerOnEnd: boolean; - inlineValues: boolean | 'auto'; + inlineValues: boolean | 'auto' | 'on' | 'off'; toolBarLocation: 'floating' | 'docked' | 'hidden'; showInStatusBar: 'never' | 'always' | 'onFirstSessionStart'; internalConsoleOptions: 'neverOpen' | 'openOnSessionStart' | 'openOnFirstSessionStart'; From 7d7a3fba79085b50d5e1d39d3f73188322c789c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mangeonjean?= Date: Fri, 1 Apr 2022 16:05:48 +0200 Subject: [PATCH 003/135] Fix folding blocks being freezed while computing new ones --- .../editor/contrib/folding/browser/folding.ts | 72 +++++++++---------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 5efbf7963dc..bf6aaa8d8bd 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -472,7 +472,7 @@ export class FoldingController extends Disposable implements IEditorContribution } private onEditorMouseUp(e: IEditorMouseEvent): void { - const foldingModel = this.getFoldingModel(); + const foldingModel = this.foldingModel; if (!foldingModel || !this.mouseDownInfo || !e.target) { return; } @@ -495,47 +495,43 @@ export class FoldingController extends Disposable implements IEditorContribution } } - foldingModel.then(foldingModel => { - if (foldingModel) { - let region = foldingModel.getRegionAtLine(lineNumber); - if (region && region.startLineNumber === lineNumber) { - let isCollapsed = region.isCollapsed; - if (iconClicked || isCollapsed) { - let surrounding = e.event.altKey; - let toToggle = []; - if (surrounding) { - let filter = (otherRegion: FoldingRegion) => !otherRegion.containedBy(region!) && !region!.containedBy(otherRegion); - let toMaybeToggle = foldingModel.getRegionsInside(null, filter); - for (const r of toMaybeToggle) { - if (r.isCollapsed) { - toToggle.push(r); - } - } - // if any surrounding regions are folded, unfold those. Otherwise, fold all surrounding - if (toToggle.length === 0) { - toToggle = toMaybeToggle; - } + let region = foldingModel.getRegionAtLine(lineNumber); + if (region && region.startLineNumber === lineNumber) { + let isCollapsed = region.isCollapsed; + if (iconClicked || isCollapsed) { + let surrounding = e.event.altKey; + let toToggle = []; + if (surrounding) { + let filter = (otherRegion: FoldingRegion) => !otherRegion.containedBy(region!) && !region!.containedBy(otherRegion); + let toMaybeToggle = foldingModel.getRegionsInside(null, filter); + for (const r of toMaybeToggle) { + if (r.isCollapsed) { + toToggle.push(r); } - else { - let recursive = e.event.middleButton || e.event.shiftKey; - if (recursive) { - for (const r of foldingModel.getRegionsInside(region)) { - if (r.isCollapsed === isCollapsed) { - toToggle.push(r); - } - } - } - // when recursive, first only collapse all children. If all are already folded or there are no children, also fold parent. - if (isCollapsed || !recursive || toToggle.length === 0) { - toToggle.push(region); - } - } - foldingModel.toggleCollapseState(toToggle); - this.reveal({ lineNumber, column: 1 }); + } + // if any surrounding regions are folded, unfold those. Otherwise, fold all surrounding + if (toToggle.length === 0) { + toToggle = toMaybeToggle; } } + else { + let recursive = e.event.middleButton || e.event.shiftKey; + if (recursive) { + for (const r of foldingModel.getRegionsInside(region)) { + if (r.isCollapsed === isCollapsed) { + toToggle.push(r); + } + } + } + // when recursive, first only collapse all children. If all are already folded or there are no children, also fold parent. + if (isCollapsed || !recursive || toToggle.length === 0) { + toToggle.push(region); + } + } + foldingModel.toggleCollapseState(toToggle); + this.reveal({ lineNumber, column: 1 }); } - }).then(undefined, onUnexpectedError); + } } public reveal(position: IPosition): void { From 1305aac01ec4b1db6c0391e1ed1d010b32315a36 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 1 Apr 2022 18:03:29 +0200 Subject: [PATCH 004/135] [css] Add CSS formatting option to place open brace on new line. Fixes #146398 --- .../client/src/cssClient.ts | 7 +- extensions/css-language-features/package.json | 66 +++++++++++++++++++ .../css-language-features/package.nls.json | 9 +++ .../css-language-features/server/package.json | 2 +- .../css-language-features/server/yarn.lock | 8 +-- 5 files changed, 85 insertions(+), 7 deletions(-) diff --git a/extensions/css-language-features/client/src/cssClient.ts b/extensions/css-language-features/client/src/cssClient.ts index 35774d6ed29..282c347bdd8 100644 --- a/extensions/css-language-features/client/src/cssClient.ts +++ b/extensions/css-language-features/client/src/cssClient.ts @@ -32,9 +32,12 @@ interface CSSFormatSettings { newlineBetweenSelectors?: boolean; newlineBetweenRules?: boolean; spaceAroundSelectorSeparator?: boolean; + braceStyle?: 'collapse' | 'expand'; + preserveNewLines?: boolean; + maxPreserveNewLines?: number | null; } -const cssFormatSettingKeys: (keyof CSSFormatSettings)[] = ['newlineBetweenSelectors', 'newlineBetweenRules', 'spaceAroundSelectorSeparator']; +const cssFormatSettingKeys: (keyof CSSFormatSettings)[] = ['newlineBetweenSelectors', 'newlineBetweenRules', 'spaceAroundSelectorSeparator', 'braceStyle', 'preserveNewLines', 'maxPreserveNewLines']; export function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime) { @@ -196,7 +199,7 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua if (formatterSettings) { for (const key of cssFormatSettingKeys) { const val = formatterSettings[key]; - if (val !== undefined) { + if (val !== undefined && val !== null) { params.options[key] = val; } } diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index 12ec5c76cd0..e9ea587d4db 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -331,6 +331,28 @@ "scope": "resource", "default": false, "markdownDescription": "%css.format.spaceAroundSelectorSeparator.desc%" + }, + "css.format.braceStyle": { + "type": "string", + "scope": "resource", + "default": "collapse", + "enum": ["collapse", "expand"], + "markdownDescription": "%css.format.braceStyle.desc%" + }, + "css.format.preserveNewLines": { + "type": "boolean", + "scope": "resource", + "default": true, + "markdownDescription": "%css.format.preserveNewLines.desc%" + }, + "css.format.maxPreserveNewLines": { + "type": [ + "number", + "null" + ], + "scope": "resource", + "default": null, + "markdownDescription": "%css.format.maxPreserveNewLines.desc%" } } }, @@ -611,6 +633,28 @@ "scope": "resource", "default": false, "markdownDescription": "%scss.format.spaceAroundSelectorSeparator.desc%" + }, + "scss.format.braceStyle": { + "type": "string", + "scope": "resource", + "default": "collapse", + "enum": ["collapse", "expand"], + "markdownDescription": "%scss.format.braceStyle.desc%" + }, + "scss.format.preserveNewLines": { + "type": "boolean", + "scope": "resource", + "default": true, + "markdownDescription": "%scss.format.preserveNewLines.desc%" + }, + "scss.format.maxPreserveNewLines": { + "type": [ + "number", + "null" + ], + "scope": "resource", + "default": null, + "markdownDescription": "%scss.format.maxPreserveNewLines.desc%" } } }, @@ -892,6 +936,28 @@ "scope": "resource", "default": false, "markdownDescription": "%less.format.spaceAroundSelectorSeparator.desc%" + }, + "less.format.braceStyle": { + "type": "string", + "scope": "resource", + "default": "collapse", + "enum": ["collapse", "expand"], + "markdownDescription": "%less.format.braceStyle.desc%" + }, + "less.format.preserveNewLines": { + "type": "boolean", + "scope": "resource", + "default": true, + "markdownDescription": "%less.format.preserveNewLines.desc%" + }, + "less.format.maxPreserveNewLines": { + "type": [ + "number", + "null" + ], + "scope": "resource", + "default": null, + "markdownDescription": "%less.format.maxPreserveNewLines.desc%" } } } diff --git a/extensions/css-language-features/package.nls.json b/extensions/css-language-features/package.nls.json index fbcaed2113a..784eaa531b7 100644 --- a/extensions/css-language-features/package.nls.json +++ b/extensions/css-language-features/package.nls.json @@ -34,6 +34,9 @@ "css.format.newlineBetweenSelectors.desc": "Separate selectors with a new line.", "css.format.newlineBetweenRules.desc": "Separate rulesets by a blank line.", "css.format.spaceAroundSelectorSeparator.desc": "Ensure a space character around selector separators '>', '+', '~' (e.g. `a > b`).", + "css.format.braceStyle.desc": "Put braces on the same line as rules (`collapse`) or put braces on own line (`expand`).", + "css.format.preserveNewLines.desc": "Whether existing line breaks before elements should be preserved.", + "css.format.maxPreserveNewLines.desc": "Maximum number of line breaks to be preserved in one chunk, when `#css.format.preserveNewLines#` is enabled.", "less.title": "LESS", "less.completion.triggerPropertyValueCompletion.desc": "By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.", "less.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end of line when completing CSS properties.", @@ -65,6 +68,9 @@ "less.format.newlineBetweenSelectors.desc": "Separate selectors with a new line.", "less.format.newlineBetweenRules.desc": "Separate rulesets by a blank line.", "less.format.spaceAroundSelectorSeparator.desc": "Ensure a space character around selector separators '>', '+', '~' (e.g. `a > b`).", + "less.format.braceStyle.desc": "Put braces on the same line as rules (`collapse`) or put braces on own line (`expand`).", + "less.format.preserveNewLines.desc": "Whether existing line breaks before elements should be preserved.", + "less.format.maxPreserveNewLines.desc": "Maximum number of line breaks to be preserved in one chunk, when `#less.format.preserveNewLines#` is enabled.", "scss.title": "SCSS (Sass)", "scss.completion.triggerPropertyValueCompletion.desc": "By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.", "scss.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end of line when completing CSS properties.", @@ -96,6 +102,9 @@ "scss.format.newlineBetweenSelectors.desc": "Separate selectors with a new line.", "scss.format.newlineBetweenRules.desc": "Separate rulesets by a blank line.", "scss.format.spaceAroundSelectorSeparator.desc": "Ensure a space character around selector separators '>', '+', '~' (e.g. `a > b`).", + "scss.format.braceStyle.desc": "Put braces on the same line as rules (`collapse`) or put braces on own line (`expand`).", + "scss.format.preserveNewLines.desc": "Whether existing line breaks before elements should be preserved.", + "scss.format.maxPreserveNewLines.desc": "Maximum number of line breaks to be preserved in one chunk, when `#scss.format.preserveNewLines#` is enabled.", "css.colorDecorators.enable.deprecationMessage": "The setting `css.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.", "scss.colorDecorators.enable.deprecationMessage": "The setting `scss.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.", "less.colorDecorators.enable.deprecationMessage": "The setting `less.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`." diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index fc604a23125..865414065cf 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -10,7 +10,7 @@ "main": "./out/node/cssServerMain", "browser": "./dist/browser/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^5.3.0", + "vscode-css-languageservice": "^5.4.1", "vscode-languageserver": "^7.0.0", "vscode-uri": "^3.0.3" }, diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index 6615d59d27a..a781f65f7cf 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -12,10 +12,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-css-languageservice@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.3.0.tgz#48b800865c5b6ca7ab43225c63e8a4f1f24ec9b0" - integrity sha512-ujWW855AoJlE4ETU17Gff7unlZZTHDA0w26itk9EQFMfJqi9lE6S67zOsMvcPmJf55MrnGQbojDYZRiDVaFjdA== +vscode-css-languageservice@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.4.1.tgz#6bb309d617c40f5b4b7752d05f1cbb9b2eaab102" + integrity sha512-W7D3GKFXf97ReAaU4EZ2nxVO1kQhztbycJgc1b/Ipr0h8zYWr88BADmrXu02z+lsCS84D7Sr4hoUzDKeaFn2Kg== dependencies: vscode-languageserver-textdocument "^1.0.4" vscode-languageserver-types "^3.16.0" From 1269764e678b69117e0ceb3d510b4999be2561b4 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Fri, 1 Apr 2022 12:09:27 -0400 Subject: [PATCH 005/135] Fix invalid tab references --- src/vs/workbench/api/common/extHostEditorTabs.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/common/extHostEditorTabs.ts b/src/vs/workbench/api/common/extHostEditorTabs.ts index 18edeb5c4d1..9d44025e7ef 100644 --- a/src/vs/workbench/api/common/extHostEditorTabs.ts +++ b/src/vs/workbench/api/common/extHostEditorTabs.ts @@ -36,9 +36,9 @@ class ExtHostEditorTab { } get apiObject(): vscode.Tab { - // Don't want to lose reference to parent `this` in the getters - const that = this; if (!this._apiObject) { + // Don't want to lose reference to parent `this` in the getters + const that = this; const obj: vscode.Tab = { get isActive() { // We use a getter function here to always ensure at most 1 active tab per group and prevent iteration for being required @@ -120,9 +120,9 @@ class ExtHostEditorTabGroup { } get apiObject(): vscode.TabGroup { - // Don't want to lose reference to parent `this` in the getters - const that = this; if (!this._apiObject) { + // Don't want to lose reference to parent `this` in the getters + const that = this; const obj: vscode.TabGroup = { get isActive() { // We use a getter function here to always ensure at most 1 active group and prevent iteration for being required From 74a7062f7412fb8a465b662495e35f35d85163d0 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 1 Apr 2022 09:52:04 -0700 Subject: [PATCH 006/135] sharing base cell editor options for the same language. --- .../notebook/browser/notebookBrowser.ts | 7 ++ .../notebook/browser/notebookEditorWidget.ts | 114 +++++++++++++++++- .../view/cellParts/cellEditorOptions.ts | 90 +++----------- .../browser/view/cellParts/codeCell.ts | 2 +- .../browser/view/cellParts/markdownCell.ts | 3 +- .../browser/view/renderers/cellRenderer.ts | 2 +- 6 files changed, 139 insertions(+), 79 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index aed8ee62af8..7153bcfe26c 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -26,6 +26,7 @@ import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookKe import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; import { cellRangesToIndexes, ICellRange, reduceCellRanges } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { IWebview } from 'vs/workbench/contrib/webview/browser/webview'; +import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; //#region Shared commands export const EXPAND_CELL_INPUT_COMMAND_ID = 'notebook.cell.expandCellInput'; @@ -628,6 +629,11 @@ export interface IActiveNotebookEditor extends INotebookEditor { getNextVisibleCellIndex(index: number): number; } +export interface IBaseCellEditorOptions extends IDisposable { + readonly value: IEditorOptions; + readonly onDidChange: Event; +} + /** * A mix of public interface and internal one (used by internal rendering code, e.g., cellRenderer) */ @@ -637,6 +643,7 @@ export interface INotebookEditorDelegate extends INotebookEditor { readonly creationOptions: INotebookEditorCreationOptions; readonly onDidChangeOptions: Event; readonly onDidChangeDecorations: Event; + getBaseCellEditorOptions(language: string): IBaseCellEditorOptions; createMarkupPreview(cell: ICellViewModel): Promise; unhideMarkupPreviews(cells: readonly ICellViewModel[]): Promise; hideMarkupPreviews(cells: readonly ICellViewModel[]): Promise; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 6d01c4d0220..aa1bcc7853f 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -21,6 +21,7 @@ import { Color, RGBA } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { deepClone } from 'vs/base/common/objects'; import { setTimeout0 } from 'vs/base/common/platform'; import { extname, isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; @@ -48,7 +49,7 @@ import { contrastBorder, diffInserted, diffRemoved, editorBackground, errorForeg import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PANEL_BORDER, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors'; -import { CellEditState, CellFindMatchWithIndex, CellFocusMode, CellLayoutContext, IActiveNotebookEditorDelegate, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IInsetRenderOutput, IModelDecorationsChangeAccessor, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorDelegate, INotebookEditorMouseEvent, INotebookEditorOptions, INotebookEditorViewState, INotebookViewCellsUpdateEvent, INotebookWebviewMessage, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFindMatchWithIndex, CellFocusMode, CellLayoutContext, IActiveNotebookEditorDelegate, IBaseCellEditorOptions, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IInsetRenderOutput, IModelDecorationsChangeAccessor, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorDelegate, INotebookEditorMouseEvent, INotebookEditorOptions, INotebookEditorViewState, INotebookViewCellsUpdateEvent, INotebookWebviewMessage, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; import { notebookDebug } from 'vs/workbench/contrib/notebook/browser/notebookLogger'; @@ -87,6 +88,100 @@ import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; const $ = DOM.$; +export class BaseCellEditorOptions extends Disposable implements IBaseCellEditorOptions { + private static fixedEditorOptions: IEditorOptions = { + scrollBeyondLastLine: false, + scrollbar: { + verticalScrollbarSize: 14, + horizontal: 'auto', + useShadows: true, + verticalHasArrows: false, + horizontalHasArrows: false, + alwaysConsumeMouseWheel: false + }, + renderLineHighlightOnlyWhenFocus: true, + overviewRulerLanes: 0, + selectOnLineNumbers: false, + lineNumbers: 'off', + lineDecorationsWidth: 0, + folding: true, + fixedOverflowWidgets: true, + minimap: { enabled: false }, + renderValidationDecorations: 'on', + lineNumbersMinChars: 3 + }; + + private _localDisposableStore = this._register(new DisposableStore()); + private readonly _onDidChange = this._register(new Emitter()); + readonly onDidChange: Event = this._onDidChange.event; + private _value: IEditorOptions; + + get value(): Readonly { + return this._value; + } + + constructor(readonly notebookEditor: INotebookEditorDelegate, readonly notebookOptions: NotebookOptions, readonly configurationService: IConfigurationService, readonly language: string) { + super(); + this._register(configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor') || e.affectsConfiguration('notebook')) { + this._recomputeOptions(); + } + })); + + this._register(notebookOptions.onDidChangeOptions(e => { + if (e.cellStatusBarVisibility || e.editorTopPadding || e.editorOptionsCustomizations) { + this._recomputeOptions(); + } + })); + + this._register(this.notebookEditor.onDidChangeModel(() => { + this._localDisposableStore.clear(); + + if (this.notebookEditor.hasModel()) { + this._localDisposableStore.add(this.notebookEditor.onDidChangeOptions(() => { + this._recomputeOptions(); + })); + + this._recomputeOptions(); + } + })); + + if (this.notebookEditor.hasModel()) { + this._localDisposableStore.add(this.notebookEditor.onDidChangeOptions(() => { + this._recomputeOptions(); + })); + } + + this._value = this._computeEditorOptions(); + } + + private _recomputeOptions(): void { + this._value = this._computeEditorOptions(); + this._onDidChange.fire(); + } + + private _computeEditorOptions() { + const editorOptions = deepClone(this.configurationService.getValue('editor', { overrideIdentifier: this.language })); + const layoutConfig = this.notebookOptions.getLayoutConfiguration(); + const editorOptionsOverrideRaw = layoutConfig.editorOptionsCustomizations ?? {}; + const editorOptionsOverride: { [key: string]: any } = {}; + for (const key in editorOptionsOverrideRaw) { + if (key.indexOf('editor.') === 0) { + editorOptionsOverride[key.substring(7)] = editorOptionsOverrideRaw[key]; + } + } + const computed = Object.freeze({ + ...editorOptions, + ...BaseCellEditorOptions.fixedEditorOptions, + ...editorOptionsOverride, + ...{ padding: { top: 12, bottom: 12 } }, + readOnly: this.notebookEditor.isReadOnly + }); + + return computed; + } +} + export function getDefaultNotebookCreationOptions(): INotebookEditorCreationOptions { // We inlined the id to avoid loading comment contrib in tests const skipContributions = ['editor.contrib.review']; @@ -229,6 +324,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD return this._list.visibleRanges || []; } + private _baseCellEditorOptions = new Map(); + readonly isEmbedded: boolean; private _readOnly: boolean; @@ -452,6 +549,19 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } //#region Editor Core + + getBaseCellEditorOptions(language: string): IBaseCellEditorOptions { + const existingOptions = this._baseCellEditorOptions.get(language); + + if (existingOptions) { + return existingOptions; + } else { + const options = new BaseCellEditorOptions(this, this.notebookOptions, this.configurationService, language); + this._baseCellEditorOptions.set(language, options); + return options; + } + } + private _updateForNotebookConfiguration() { if (!this._overlayContainer) { return; @@ -2810,6 +2920,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD this.viewModel?.dispose(); this._renderedEditors.clear(); + this._baseCellEditorOptions.forEach(v => v.dispose()); + this._baseCellEditorOptions.clear(); super.dispose(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts index 00d68c38911..3059080c7d5 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { deepClone } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import { IEditorOptions, LineNumbersType } from 'vs/editor/common/config/editorOptions'; import { localize } from 'vs/nls'; @@ -17,7 +15,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { Registry } from 'vs/platform/registry/common/platform'; import { ActiveEditorContext } from 'vs/workbench/common/contextkeys'; import { INotebookCellToolbarActionContext, INotebookCommandContext, NotebookMultiCellAction, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; -import { ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IBaseCellEditorOptions, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NOTEBOOK_CELL_LINE_NUMBERS, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { NotebookCellInternalMetadata, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -25,66 +23,18 @@ import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOp import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; export class CellEditorOptions extends CellPart { - private static fixedEditorOptions: IEditorOptions = { - scrollBeyondLastLine: false, - scrollbar: { - verticalScrollbarSize: 14, - horizontal: 'auto', - useShadows: true, - verticalHasArrows: false, - horizontalHasArrows: false, - alwaysConsumeMouseWheel: false - }, - renderLineHighlightOnlyWhenFocus: true, - overviewRulerLanes: 0, - selectOnLineNumbers: false, - lineNumbers: 'off', - lineDecorationsWidth: 0, - folding: true, - fixedOverflowWidgets: true, - minimap: { enabled: false }, - renderValidationDecorations: 'on', - lineNumbersMinChars: 3 - }; - - private _value: IEditorOptions; private _lineNumbers: 'on' | 'off' | 'inherit' = 'inherit'; private readonly _onDidChange = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - private _localDisposableStore = this._register(new DisposableStore()); + private _value: IEditorOptions; - constructor(readonly notebookEditor: INotebookEditorDelegate, readonly notebookOptions: NotebookOptions, readonly configurationService: IConfigurationService, readonly language: string) { + constructor(private readonly base: IBaseCellEditorOptions, readonly notebookOptions: NotebookOptions, readonly configurationService: IConfigurationService) { super(); - this._register(configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('editor') || e.affectsConfiguration('notebook')) { - this._recomputeOptions(); - } + + this._register(base.onDidChange(() => { + this._recomputeOptions(); })); - this._register(notebookOptions.onDidChangeOptions(e => { - if (e.cellStatusBarVisibility || e.editorTopPadding || e.editorOptionsCustomizations) { - this._recomputeOptions(); - } - })); - - this._register(this.notebookEditor.onDidChangeModel(() => { - this._localDisposableStore.clear(); - - if (this.notebookEditor.hasModel()) { - this._localDisposableStore.add(this.notebookEditor.onDidChangeOptions(() => { - this._recomputeOptions(); - })); - - this._recomputeOptions(); - } - })); - - if (this.notebookEditor.hasModel()) { - this._localDisposableStore.add(this.notebookEditor.onDidChangeOptions(() => { - this._recomputeOptions(); - })); - } - this._value = this._computeEditorOptions(); } @@ -102,25 +52,17 @@ export class CellEditorOptions extends CellPart { private _computeEditorOptions() { const renderLineNumbers = this.configurationService.getValue<'on' | 'off'>('notebook.lineNumbers') === 'on'; const lineNumbers: LineNumbersType = renderLineNumbers ? 'on' : 'off'; - const editorOptions = deepClone(this.configurationService.getValue('editor', { overrideIdentifier: this.language })); - const layoutConfig = this.notebookOptions.getLayoutConfiguration(); - const editorOptionsOverrideRaw = layoutConfig.editorOptionsCustomizations ?? {}; - const editorOptionsOverride: { [key: string]: any } = {}; - for (const key in editorOptionsOverrideRaw) { - if (key.indexOf('editor.') === 0) { - editorOptionsOverride[key.substring(7)] = editorOptionsOverrideRaw[key]; - } - } - const computed = { - ...editorOptions, - ...CellEditorOptions.fixedEditorOptions, - ... { lineNumbers }, - ...editorOptionsOverride, - ...{ padding: { top: 12, bottom: 12 } }, - readOnly: this.notebookEditor.isReadOnly - }; - return computed; + const value = this.base.value; + + if (value.lineNumbers !== lineNumbers) { + return { + ...value, + ...{ lineNumbers } + }; + } else { + return Object.assign({}, value); + } } getUpdatedValue(internalMetadata: NotebookCellInternalMetadata, cellUri: URI): IEditorOptions { 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 41083dab251..3f2df96e305 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts @@ -53,7 +53,7 @@ export class CodeCell extends Disposable { ) { super(); - const cellEditorOptions = this._register(new CellEditorOptions(this.notebookEditor, this.notebookEditor.notebookOptions, this.configurationService, this.viewCell.language)); + const cellEditorOptions = this._register(new CellEditorOptions(this.notebookEditor.getBaseCellEditorOptions(viewCell.language), this.notebookEditor.notebookOptions, this.configurationService)); this._outputContainerRenderer = this.instantiationService.createInstance(CellOutputContainer, notebookEditor, viewCell, templateData, { limit: 500 }); this.cellParts = [...templateData.cellParts, cellEditorOptions, this._outputContainerRenderer]; diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts index b1b5077afea..bf119feb15c 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts @@ -59,8 +59,7 @@ export class StatefulMarkdownCell extends Disposable { this.constructDOM(); this.editorPart = templateData.editorPart; - - this.cellEditorOptions = this._register(new CellEditorOptions(this.notebookEditor, this.notebookEditor.notebookOptions, this.configurationService, this.viewCell.language)); + this.cellEditorOptions = this._register(new CellEditorOptions(this.notebookEditor.getBaseCellEditorOptions(viewCell.language), this.notebookEditor.notebookOptions, this.configurationService)); this.cellEditorOptions.setLineNumbers(this.viewCell.lineNumbers); this.editorOptions = this.cellEditorOptions.getValue(this.viewCell.internalMetadata, this.viewCell.uri); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 1beeb548519..02beef093cf 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -98,7 +98,7 @@ abstract class AbstractCellRenderer { language: string, protected dndController: CellDragAndDropController | undefined ) { - this.editorOptions = new CellEditorOptions(notebookEditor, notebookEditor.notebookOptions, configurationService, language); + this.editorOptions = new CellEditorOptions(this.notebookEditor.getBaseCellEditorOptions(language), this.notebookEditor.notebookOptions, configurationService); } dispose() { From f919f6c7fb96b6c0af1e44f909ef7a0a596d76e5 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Fri, 1 Apr 2022 13:04:41 -0400 Subject: [PATCH 007/135] bump distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a6ef958814f..aa55c9d0ad4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.67.0", - "distro": "7ee3b198b317d29648533b3713783234658d7968", + "distro": "044c89b614724e7c07260fbfd36f607ebce52c99", "author": { "name": "Microsoft Corporation" }, From 62e4fdbbc72e59862a79ff89d664ebda5e321e97 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 1 Apr 2022 10:16:08 -0700 Subject: [PATCH 008/135] Fixed terminal profile tests --- .../test/common/terminalProfiles.test.ts | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/terminal/test/common/terminalProfiles.test.ts b/src/vs/platform/terminal/test/common/terminalProfiles.test.ts index c6f7520c0ed..4720794b4f8 100644 --- a/src/vs/platform/terminal/test/common/terminalProfiles.test.ts +++ b/src/vs/platform/terminal/test/common/terminalProfiles.test.ts @@ -12,8 +12,12 @@ suite('terminalProfiles', () => { suite('createProfileSchemaEnums', () => { test('should return an empty array when there are no profiles', () => { deepStrictEqual(createProfileSchemaEnums([]), { - values: [], - markdownDescriptions: [] + values: [ + null + ], + markdownDescriptions: [ + 'Automatically detect the default' + ] }); }); test('should return a single entry when there is one profile', () => { @@ -23,8 +27,14 @@ suite('terminalProfiles', () => { isDefault: true }; deepStrictEqual(createProfileSchemaEnums([profile]), { - values: ['name'], - markdownDescriptions: ['$(terminal) name\n- path: path'] + values: [ + null, + 'name' + ], + markdownDescriptions: [ + 'Automatically detect the default', + '$(terminal) name\n- path: path' + ] }); }); test('should show all profile information', () => { @@ -42,8 +52,14 @@ suite('terminalProfiles', () => { overrideName: true }; deepStrictEqual(createProfileSchemaEnums([profile]), { - values: ['name'], - markdownDescriptions: [`$(zap) name\n- path: path\n- args: ['a','b']\n- overrideName: true\n- color: terminal.ansiRed\n- env: {\"c\":\"d\",\"e\":\"f\"}`] + values: [ + null, + 'name' + ], + markdownDescriptions: [ + 'Automatically detect the default', + `$(zap) name\n- path: path\n- args: ['a','b']\n- overrideName: true\n- color: terminal.ansiRed\n- env: {\"c\":\"d\",\"e\":\"f\"}` + ] }); }); test('should return a multiple entries when there are multiple profiles', () => { @@ -58,8 +74,13 @@ suite('terminalProfiles', () => { isDefault: false }; deepStrictEqual(createProfileSchemaEnums([profile1, profile2]), { - values: ['name', 'foo'], + values: [ + null, + 'name', + 'foo' + ], markdownDescriptions: [ + 'Automatically detect the default', '$(terminal) name\n- path: path', '$(terminal) foo\n- path: bar' ] From 86cc884a9e1742a3fddd4e8c36b20cbf198d7260 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 1 Apr 2022 13:18:59 -0400 Subject: [PATCH 009/135] on move of terminal from or to the panel, hide find widget (#146568) --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 1 + src/vs/workbench/contrib/terminal/browser/terminalEditor.ts | 1 + src/vs/workbench/contrib/terminal/browser/terminalService.ts | 4 ++++ .../workbench/contrib/terminal/browser/terminalTabbedView.ts | 1 + 4 files changed, 7 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 4f75519bfd9..c48979fa4d6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -146,6 +146,7 @@ export interface ITerminalService extends ITerminalInstanceHost { onDidInputInstanceData: Event; onDidRegisterProcessSupport: Event; onDidChangeConnectionState: Event; + onDidRequestHideFindWidget: Event; /** * Creates a terminal. diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index c5701e6d38d..71eeff2a7ac 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -75,6 +75,7 @@ export class TerminalEditor extends EditorPane { this._findWidget = instantiationService.createInstance(TerminalFindWidget, this._findState); this._dropdownMenu = this._register(menuService.createMenu(MenuId.TerminalNewDropdownContext, _contextKeyService)); this._instanceMenu = this._register(menuService.createMenu(MenuId.TerminalEditorInstanceContext, _contextKeyService)); + this._register(this._terminalService.onDidRequestHideFindWidget(() => this.hideFindWidget())); } override async setInput(newInput: TerminalEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 31995a09e77..8402e0e5362 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -141,6 +141,8 @@ export class TerminalService implements ITerminalService { get onDidRegisterProcessSupport(): Event { return this._onDidRegisterProcessSupport.event; } private readonly _onDidChangeConnectionState = new Emitter(); get onDidChangeConnectionState(): Event { return this._onDidChangeConnectionState.event; } + private readonly _onDidRequestHideFindWidget = new Emitter(); + get onDidRequestHideFindWidget(): Event { return this._onDidRequestHideFindWidget.event; } constructor( @IContextKeyService private _contextKeyService: IContextKeyService, @@ -720,6 +722,7 @@ export class TerminalService implements ITerminalService { } sourceGroup.removeInstance(source); this._terminalEditorService.openEditor(source); + this._onDidRequestHideFindWidget.fire(); } async moveToTerminalView(source?: ITerminalInstance, target?: ITerminalInstance, side?: 'before' | 'after'): Promise { @@ -766,6 +769,7 @@ export class TerminalService implements ITerminalService { this._onDidChangeInstances.fire(); this._onDidChangeActiveGroup.fire(this._terminalGroupService.activeGroup); this._terminalGroupService.showPanel(true); + this._onDidRequestHideFindWidget.fire(); } protected _initInstanceListeners(instance: ITerminalInstance): void { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index 19c33f1825a..eec5a502976 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -133,6 +133,7 @@ export class TerminalTabbedView extends Disposable { this._register(this._terminalGroupService.onDidChangeInstances(() => this._refreshShowTabs())); this._register(this._terminalGroupService.onDidChangeGroups(() => this._refreshShowTabs())); this._register(this._themeService.onDidColorThemeChange(theme => this._updateTheme(theme))); + this._register(this._terminalService.onDidRequestHideFindWidget(() => this.hideFindWidget())); this._updateTheme(); this._findWidget.focusTracker.onDidFocus(() => this._terminalContainer.classList.add(CssClass.FindFocus)); From 114b340f7a11a9d93e31ba3723c5f2b1756b5640 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 1 Apr 2022 00:03:40 -0700 Subject: [PATCH 010/135] Fix explicit references to own file --- .../src/languageFeatures/references.ts | 4 +- .../src/languageFeatures/rename.ts | 5 +- .../src/test/references.test.ts | 18 +++++- .../src/test/rename.test.ts | 57 ++++++++++++++++++- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/extensions/markdown-language-features/src/languageFeatures/references.ts b/extensions/markdown-language-features/src/languageFeatures/references.ts index c2d56f8e3fb..65db2003423 100644 --- a/extensions/markdown-language-features/src/languageFeatures/references.ts +++ b/extensions/markdown-language-features/src/languageFeatures/references.ts @@ -218,8 +218,8 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference } } else { // Triggered on a link without a fragment so we only require matching the file and ignore fragments - // But exclude cases where the file is referencing itself - if (link.sourceResource.fsPath !== targetDoc.uri.fsPath) { + // But exclude cases where the file is implicitly referencing itself + if (!link.sourceText.startsWith('#') || link.sourceResource.fsPath !== targetDoc.uri.fsPath) { references.push({ kind: 'link', isTriggerLocation, diff --git a/extensions/markdown-language-features/src/languageFeatures/rename.ts b/extensions/markdown-language-features/src/languageFeatures/rename.ts index 19478795e65..66f05a2173d 100644 --- a/extensions/markdown-language-features/src/languageFeatures/rename.ts +++ b/extensions/markdown-language-features/src/languageFeatures/rename.ts @@ -56,7 +56,10 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide return triggerRef.link.sourceHrefRange; } } else { - return triggerRef.fragmentLocation?.range ?? triggerRef.location.range; + if (triggerRef.fragmentLocation) { + return triggerRef.fragmentLocation.range; + } + throw new Error(localize('renameNoFiles', "Renaming files is currently not supported")); } } } diff --git a/extensions/markdown-language-features/src/test/references.test.ts b/extensions/markdown-language-features/src/test/references.test.ts index 4b7f9532cec..319fcec7817 100644 --- a/extensions/markdown-language-features/src/test/references.test.ts +++ b/extensions/markdown-language-features/src/test/references.test.ts @@ -312,7 +312,7 @@ suite('markdown: find all references', () => { const otherUri = workspacePath('sub', 'other.md'); const doc = new InMemoryDocument(docUri, joinLines( - `[other](./sub/other)`, + `[other](./sub/other)`, // trigger here )); const refs = await getReferences(doc, new vscode.Position(0, 15), new InMemoryWorkspaceMarkdownDocuments([ @@ -328,6 +328,22 @@ suite('markdown: find all references', () => { ); }); + test('Should find explicit references to own file ', async () => { + const uri = workspacePath('doc.md'); + const doc = new InMemoryDocument(uri, joinLines( + `[bare](doc.md)`, // trigger here + `[rel](./doc.md)`, + `[abs](/doc.md)`, + )); + + const refs = await getReferences(doc, new vscode.Position(0, 12), new InMemoryWorkspaceMarkdownDocuments([doc])); + assertReferencesEqual(refs!, + { uri, line: 0 }, + { uri, line: 1 }, + { uri, line: 2 }, + ); + }); + suite('Reference links', () => { test('Should find reference links within file from link', async () => { const docUri = workspacePath('doc.md'); diff --git a/extensions/markdown-language-features/src/test/rename.test.ts b/extensions/markdown-language-features/src/test/rename.test.ts index e22453f3e02..3f92f70e8bd 100644 --- a/extensions/markdown-language-features/src/test/rename.test.ts +++ b/extensions/markdown-language-features/src/test/rename.test.ts @@ -208,6 +208,52 @@ suite('markdown: rename', () => { }); }); + test('Rename on link in other file should pick up all refs', async () => { + const uri = workspacePath('doc.md'); + const otherUri = workspacePath('other.md'); + const doc = new InMemoryDocument(uri, joinLines( + `### A b C`, + `[text](#a-b-c)`, + )); + + const otherDoc = new InMemoryDocument(otherUri, joinLines( + `[text](#a-b-c)`, + `[text](./doc.md#a-b-c)`, + `[text](./doc#a-b-c)` + )); + + const expectedEdits = [ + { + uri: uri, edits: [ + new vscode.TextEdit(new vscode.Range(0, 4, 0, 9), 'New Header'), + new vscode.TextEdit(new vscode.Range(1, 8, 1, 13), 'new-header'), + ] + }, { + uri: otherUri, edits: [ + new vscode.TextEdit(new vscode.Range(1, 16, 1, 21), 'new-header'), + new vscode.TextEdit(new vscode.Range(2, 13, 2, 18), 'new-header'), + ] + } + ]; + + { + // Rename on header with file extension + const edit = await getRenameEdits(otherDoc, new vscode.Position(1, 17), "New Header", new InMemoryWorkspaceMarkdownDocuments([ + doc, + otherDoc + ])); + assertEditsEqual(edit!, ...expectedEdits); + } + { + // Rename on header without extension + const edit = await getRenameEdits(otherDoc, new vscode.Position(2, 15), "New Header", new InMemoryWorkspaceMarkdownDocuments([ + doc, + otherDoc + ])); + assertEditsEqual(edit!, ...expectedEdits); + } + }); + test('Rename on ref should rename refs and def', async () => { const uri = workspacePath('doc.md'); const doc = new InMemoryDocument(uri, joinLines( @@ -246,7 +292,6 @@ suite('markdown: rename', () => { }); }); - test('Rename should not be supported on link text', async () => { const uri = workspacePath('doc.md'); const doc = new InMemoryDocument(uri, joinLines( @@ -256,4 +301,14 @@ suite('markdown: rename', () => { await assert.rejects(getRenameRange(doc, new vscode.Position(1, 2), new InMemoryWorkspaceMarkdownDocuments([doc]))); }); + + test('Rename should not be supported on bare file references', async () => { + const uri = workspacePath('doc.md'); + const doc = new InMemoryDocument(uri, joinLines( + `[text](./doc.md)`, + `[other](./doc.md)`, + )); + + await assert.rejects(getRenameRange(doc, new vscode.Position(0, 10), new InMemoryWorkspaceMarkdownDocuments([doc]))); + }); }); From ca267e3f5ef25d7d42d5afc17bf53801003239be Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 1 Apr 2022 00:07:22 -0700 Subject: [PATCH 011/135] Error on rename in bare file links in definition --- .../src/languageFeatures/rename.ts | 5 ++++- .../src/test/rename.test.ts | 12 +++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/extensions/markdown-language-features/src/languageFeatures/rename.ts b/extensions/markdown-language-features/src/languageFeatures/rename.ts index 66f05a2173d..ab11f2b210d 100644 --- a/extensions/markdown-language-features/src/languageFeatures/rename.ts +++ b/extensions/markdown-language-features/src/languageFeatures/rename.ts @@ -53,7 +53,10 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide if (triggerRef.link.refRange.contains(position)) { return triggerRef.link.refRange; } else { - return triggerRef.link.sourceHrefRange; + if (triggerRef.fragmentLocation) { + return triggerRef.fragmentLocation.range; + } + throw new Error(localize('renameNoFiles', "Renaming files is currently not supported")); } } else { if (triggerRef.fragmentLocation) { diff --git a/extensions/markdown-language-features/src/test/rename.test.ts b/extensions/markdown-language-features/src/test/rename.test.ts index 3f92f70e8bd..0a9c59fac9d 100644 --- a/extensions/markdown-language-features/src/test/rename.test.ts +++ b/extensions/markdown-language-features/src/test/rename.test.ts @@ -302,7 +302,7 @@ suite('markdown: rename', () => { await assert.rejects(getRenameRange(doc, new vscode.Position(1, 2), new InMemoryWorkspaceMarkdownDocuments([doc]))); }); - test('Rename should not be supported on bare file references', async () => { + test('Rename should not be supported on bare file link', async () => { const uri = workspacePath('doc.md'); const doc = new InMemoryDocument(uri, joinLines( `[text](./doc.md)`, @@ -311,4 +311,14 @@ suite('markdown: rename', () => { await assert.rejects(getRenameRange(doc, new vscode.Position(0, 10), new InMemoryWorkspaceMarkdownDocuments([doc]))); }); + + test('Rename should not be supported on bare file link in definition', async () => { + const uri = workspacePath('doc.md'); + const doc = new InMemoryDocument(uri, joinLines( + `[text](./doc.md)`, + `[ref]: ./doc.md`, + )); + + await assert.rejects(getRenameRange(doc, new vscode.Position(1, 10), new InMemoryWorkspaceMarkdownDocuments([doc]))); + }); }); From e9636bbce19f6855a9a86158ded8f6568e4c7462 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 1 Apr 2022 11:14:28 -0700 Subject: [PATCH 012/135] Don't have space in snippet Fixes #146503 --- extensions/javascript/snippets/javascript.code-snippets | 6 +++--- .../typescript-basics/snippets/typescript.code-snippets | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/javascript/snippets/javascript.code-snippets b/extensions/javascript/snippets/javascript.code-snippets index ac5cd5549f1..47a6f40d202 100644 --- a/extensions/javascript/snippets/javascript.code-snippets +++ b/extensions/javascript/snippets/javascript.code-snippets @@ -149,12 +149,12 @@ ], "description": "Set Interval Function" }, - "Import external module.": { - "prefix": "import statement", + "Import Statement": { + "prefix": "import", "body": [ "import { $0 } from \"${1:module}\";" ], - "description": "Import external module." + "description": "Import external module" }, "Region Start": { "prefix": "#region", diff --git a/extensions/typescript-basics/snippets/typescript.code-snippets b/extensions/typescript-basics/snippets/typescript.code-snippets index 49ebefbac9a..0162ef50975 100644 --- a/extensions/typescript-basics/snippets/typescript.code-snippets +++ b/extensions/typescript-basics/snippets/typescript.code-snippets @@ -44,12 +44,12 @@ ], "description": "Private Method Definition" }, - "Import external module.": { - "prefix": "import statement", + "Import Statement": { + "prefix": "import", "body": [ "import { $0 } from \"${1:module}\";" ], - "description": "Import external module." + "description": "Import external module" }, "Property getter": { "prefix": "get", From acab0012379071c89da9141f51344a2b12c0ec9d Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Fri, 1 Apr 2022 14:24:35 -0400 Subject: [PATCH 013/135] Remove active change events --- .../workbench/api/common/extHostEditorTabs.ts | 12 -- .../test/browser/extHostEditorTabs.test.ts | 145 ------------------ src/vscode-dts/vscode.proposed.tabs.d.ts | 13 -- 3 files changed, 170 deletions(-) diff --git a/src/vs/workbench/api/common/extHostEditorTabs.ts b/src/vs/workbench/api/common/extHostEditorTabs.ts index 9d44025e7ef..cbd2effae0c 100644 --- a/src/vs/workbench/api/common/extHostEditorTabs.ts +++ b/src/vs/workbench/api/common/extHostEditorTabs.ts @@ -202,9 +202,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { private readonly _proxy: MainThreadEditorTabsShape; private readonly _onDidChangeTabs = new Emitter(); - private readonly _onDidChangeActiveTab = new Emitter(); private readonly _onDidChangeTabGroups = new Emitter(); - private readonly _onDidChangeActiveTabGroup = new Emitter(); // Have to use ! because this gets initialized via an RPC proxy private _activeGroupId!: number; @@ -223,9 +221,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { const obj: vscode.TabGroups = { // never changes -> simple value onDidChangeTabGroups: that._onDidChangeTabGroups.event, - onDidChangeActiveTabGroup: that._onDidChangeActiveTabGroup.event, onDidChangeTabs: that._onDidChangeTabs.event, - onDidChangeActiveTab: that._onDidChangeActiveTab.event, // dynamic -> getters get groups() { return Object.freeze(that._extHostTabGroups.map(group => group.apiObject)); @@ -283,7 +279,6 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { const activeTabGroupId = assertIsDefined(tabGroups.find(group => group.isActive === true)?.groupId); if (activeTabGroupId !== undefined && this._activeGroupId !== activeTabGroupId) { this._activeGroupId = activeTabGroupId; - this._onDidChangeActiveTabGroup.fire(this.tabGroups.activeTabGroup); } this._onDidChangeTabGroups.fire(this._extHostTabGroups.map(g => g.apiObject)); } @@ -295,11 +290,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { } group.acceptGroupDtoUpdate(groupDto); if (groupDto.isActive) { - const oldActiveGroupId = this._activeGroupId; this._activeGroupId = groupDto.groupId; - if (oldActiveGroupId !== this._activeGroupId) { - this._onDidChangeActiveTabGroup.fire(group.apiObject); - } } this._onDidChangeTabGroups.fire([group.apiObject]); } @@ -313,9 +304,6 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { // We don't want to fire a change event with a closed tab to prevent an invalid tabs from being received if (operation.kind !== TabModelOperationKind.TAB_CLOSE) { this._onDidChangeTabs.fire([tab.apiObject]); - if (tab.apiObject.isActive) { - this._onDidChangeActiveTab.fire(tab.apiObject); - } } } } diff --git a/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts b/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts index c9fe89b33c7..a9ff3908319 100644 --- a/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts +++ b/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts @@ -155,68 +155,6 @@ suite('ExtHostEditorTabs', function () { assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup, first); }); - // TODO @lramos15 Change this test because now it only fires when id changes - test.skip('onDidChangeActiveTabGroup fires properly', function () { - const extHostEditorTabs = new ExtHostEditorTabs( - SingleProxyRPCProtocol(new class extends mock() { - // override/implement $moveTab or $closeTab - }) - ); - - let count = 0; - let activeTabGroupFromEvent: vscode.TabGroup | undefined = undefined; - extHostEditorTabs.tabGroups.onDidChangeActiveTabGroup((tabGroup) => { - count++; - activeTabGroupFromEvent = tabGroup; - }); - - - assert.strictEqual(extHostEditorTabs.tabGroups.groups.length, 0); - assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup, undefined); - assert.strictEqual(count, 0); - const tabModel = [{ - isActive: true, - viewColumn: 0, - groupId: 12, - tabs: [], - activeTab: undefined - }]; - extHostEditorTabs.$acceptEditorTabModel(tabModel); - assert.ok(extHostEditorTabs.tabGroups.activeTabGroup); - let activeTabGroup: vscode.TabGroup = extHostEditorTabs.tabGroups.activeTabGroup; - assert.strictEqual(count, 1); - assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); - // Firing again with same model shouldn't cause a change - extHostEditorTabs.$acceptEditorTabModel(tabModel); - assert.strictEqual(count, 1); - // Changing a property should fire a change - tabModel[0].viewColumn = 1; - extHostEditorTabs.$acceptEditorTabModel(tabModel); - assert.strictEqual(count, 2); - activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup; - assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); - // Changing the active tab group should fire a change - tabModel[0].isActive = false; - tabModel.push({ - isActive: true, - viewColumn: 0, - groupId: 13, - tabs: [], - activeTab: undefined - }); - extHostEditorTabs.$acceptEditorTabModel(tabModel); - assert.strictEqual(count, 3); - activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup; - assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); - - // Empty tab model should fire a change and return undefined - extHostEditorTabs.$acceptEditorTabModel([]); - assert.strictEqual(count, 4); - activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup; - assert.strictEqual(activeTabGroup, undefined); - assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); - }); - test('Ensure reference stability', function () { const extHostEditorTabs = new ExtHostEditorTabs( @@ -519,89 +457,6 @@ suite('ExtHostEditorTabs', function () { assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup?.activeTab, undefined); }); - test('Active tab change event', function () { - - const extHostEditorTabs = new ExtHostEditorTabs( - SingleProxyRPCProtocol(new class extends mock() { - // override/implement $moveTab or $closeTab - }) - ); - - let activeTabChangeCount = 0; - extHostEditorTabs.tabGroups.onDidChangeActiveTab((activeTab) => { - if (activeTab.isActive === false) { - throw new Error('Active tab changed fired on inactive tab'); - } - activeTabChangeCount++; - }); - - const tab1: IEditorTabDto = createTabDto({ - id: 'uniquestring', - isActive: true, - label: 'label1', - }); - - const tab2: IEditorTabDto = createTabDto({ - isActive: false, - id: 'uniquestring2', - label: 'label2', - }); - - const tab3: IEditorTabDto = createTabDto({ - isActive: false, - id: 'uniquestring3', - label: 'label3', - }); - - extHostEditorTabs.$acceptEditorTabModel([{ - isActive: true, - viewColumn: 0, - groupId: 12, - tabs: [tab1, tab2, tab3] - }]); - - // Accepting a model doesn't fire an active tab change event - assert.strictEqual(activeTabChangeCount, 0); - - // Switching active tab works - tab1.isActive = false; - tab2.isActive = true; - - extHostEditorTabs.$acceptTabOperation({ - groupId: 12, - index: 0, - kind: TabModelOperationKind.TAB_UPDATE, - tabDto: tab1 - }); - extHostEditorTabs.$acceptTabOperation({ - groupId: 12, - index: 1, - kind: TabModelOperationKind.TAB_UPDATE, - tabDto: tab2 - }); - // The active tab changed so it is fired once - assert.strictEqual(activeTabChangeCount, 1); - - //Closing tabs out works - tab3.isActive = true; - extHostEditorTabs.$acceptEditorTabModel([{ - isActive: true, - viewColumn: 0, - groupId: 12, - tabs: [tab3] - }]); - // Accepting a model doesn't fire an active tab change event - assert.strictEqual(activeTabChangeCount, 1); - tab3.label = 'Foobar'; - extHostEditorTabs.$acceptTabOperation({ - groupId: 12, - index: 0, - kind: TabModelOperationKind.TAB_UPDATE, - tabDto: tab3 - }); - // Something related to the active tab changed - assert.strictEqual(activeTabChangeCount, 2); - }); test('Tab operations patches open and close correctly', function () { const extHostEditorTabs = new ExtHostEditorTabs( SingleProxyRPCProtocol(new class extends mock() { diff --git a/src/vscode-dts/vscode.proposed.tabs.d.ts b/src/vscode-dts/vscode.proposed.tabs.d.ts index 91ba6ade9ce..0d369caef4f 100644 --- a/src/vscode-dts/vscode.proposed.tabs.d.ts +++ b/src/vscode-dts/vscode.proposed.tabs.d.ts @@ -145,19 +145,6 @@ declare module 'vscode' { */ readonly onDidChangeTabs: Event; - /** - * An {@link Event} which fires when an active tab changes. - * Similar to {@link TabGroup.onDidChangeTabs} but only on tabs - * with isActive equal to true. - */ - readonly onDidChangeActiveTab: Event; - - /** - * An {@link Event} which fires when the active group changes. - * This does not fire when the properties within the group change. - */ - readonly onDidChangeActiveTabGroup: Event; - /** * Closes the tab. This makes the tab object invalid and the tab * should no longer be used for further actions. From 943186d56cf7911a220a2b84254463a37c8777b5 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 1 Apr 2022 12:09:32 -0700 Subject: [PATCH 014/135] update nb tests. --- .../src/singlefolder-tests/notebook.editor.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts index 0b62d4e0549..eeffb282f91 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts @@ -107,8 +107,8 @@ import * as utils from '../utils'; assert.strictEqual(editor.document.uri.toString(), resource.toString()); }); - test.skip('Active/Visible Editor', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/139078 - const firstEditorOpen = utils.asPromise(vscode.window.onDidChangeActiveNotebookEditor); + test('Active/Visible Editor', async function () { + const firstEditorOpen = onDidOpenNotebookEditor(); const resource = await utils.createRandomFile(undefined, undefined, '.nbdtest'); const firstEditor = await vscode.window.showNotebookDocument(resource); await firstEditorOpen; @@ -116,14 +116,16 @@ import * as utils from '../utils'; assert.strictEqual(vscode.window.visibleNotebookEditors.includes(firstEditor), true); const secondEditor = await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Beside }); - assert.strictEqual(secondEditor === vscode.window.activeNotebookEditor, true); + // There is no guarantee that when `showNotebookDocument` resolves, the active notebook editor is already updated correctly. + // assert.strictEqual(secondEditor === vscode.window.activeNotebookEditor, true); assert.notStrictEqual(firstEditor, secondEditor); assert.strictEqual(vscode.window.visibleNotebookEditors.includes(secondEditor), true); assert.strictEqual(vscode.window.visibleNotebookEditors.includes(firstEditor), true); assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); + await utils.closeAllEditors(); }); - test.skip('Notebook Editor Event - onDidChangeVisibleNotebookEditors on open/close', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/139958 + test('Notebook Editor Event - onDidChangeVisibleNotebookEditors on open/close', async function () { const openedEditor = utils.asPromise(vscode.window.onDidChangeVisibleNotebookEditors); const resource = await utils.createRandomFile(undefined, undefined, '.nbdtest'); await vscode.window.showNotebookDocument(resource); From 1735a8fd756a70ee179b5bf7953e8359f76adf29 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 1 Apr 2022 13:01:16 -0700 Subject: [PATCH 015/135] xterm@4.19.0-beta.20 Fixes #145751 --- package.json | 10 +++++----- remote/package.json | 10 +++++----- remote/web/package.json | 6 +++--- remote/web/yarn.lock | 24 ++++++++++++------------ remote/yarn.lock | 40 ++++++++++++++++++++-------------------- yarn.lock | 40 ++++++++++++++++++++-------------------- 6 files changed, 65 insertions(+), 65 deletions(-) diff --git a/package.json b/package.json index aa55c9d0ad4..44fbbe4b042 100644 --- a/package.json +++ b/package.json @@ -84,12 +84,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "6.0.0", - "xterm": "4.19.0-beta.17", - "xterm-addon-search": "0.9.0-beta.17", - "xterm-addon-serialize": "0.7.0-beta.11", + "xterm": "4.19.0-beta.20", + "xterm-addon-search": "0.9.0-beta.18", + "xterm-addon-serialize": "0.7.0-beta.12", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.25", - "xterm-headless": "4.19.0-beta.17", + "xterm-addon-webgl": "0.12.0-beta.27", + "xterm-headless": "4.19.0-beta.20", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index 3ac3c183714..203c90916b6 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,12 +24,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "6.0.0", - "xterm": "4.19.0-beta.17", - "xterm-addon-search": "0.9.0-beta.17", - "xterm-addon-serialize": "0.7.0-beta.11", + "xterm": "4.19.0-beta.20", + "xterm-addon-search": "0.9.0-beta.18", + "xterm-addon-serialize": "0.7.0-beta.12", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.25", - "xterm-headless": "4.19.0-beta.17", + "xterm-addon-webgl": "0.12.0-beta.27", + "xterm-headless": "4.19.0-beta.20", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index fb333057023..1d3e920919e 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -10,9 +10,9 @@ "tas-client-umd": "0.1.4", "vscode-oniguruma": "1.6.1", "vscode-textmate": "6.0.0", - "xterm": "4.19.0-beta.17", - "xterm-addon-search": "0.9.0-beta.17", + "xterm": "4.19.0-beta.20", + "xterm-addon-search": "0.9.0-beta.18", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.25" + "xterm-addon-webgl": "0.12.0-beta.27" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 1185ff5dc1b..0fbfec54b2c 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -113,22 +113,22 @@ vscode-textmate@6.0.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-6.0.0.tgz#a3777197235036814ac9a92451492f2748589210" integrity sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ== -xterm-addon-search@0.9.0-beta.17: - version "0.9.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.17.tgz#4cd575fd67a010af3d0b224092527747bb87c219" - integrity sha512-/Q6xQ/HunP2BxJU4NTsLX9aH376tsT9dpcS+NFBDVbwB1iPF02JhedHmA4mxY3KGNyQflefhwyGGMKZfTau2iA== +xterm-addon-search@0.9.0-beta.18: + version "0.9.0-beta.18" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.18.tgz#5317aed1dc747f468ccb7ecd151fb00d82a8a19d" + integrity sha512-SAeA3thc2WJNYXwjOEJFLpZ1ZVOs22RLmz9a6WcrzXkvCjLZRvbRGwX25Ms+Dd7dVDQNbKVUzUJohspP/vYr0Q== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.25: - version "0.12.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.25.tgz#67fd222d245c4bf749b2abdf0acec640fb575bcd" - integrity sha512-QK0r6hi+plkMtHZrOlUO/IcDa9mnYxOKrqrmzbjxT6cuhXJf2EiWpBBY6Rkk0cVXtDOlkGO1b7hWvD3qeWeWvQ== +xterm-addon-webgl@0.12.0-beta.27: + version "0.12.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.27.tgz#afc5bc01d1ef3af9005fb9f6325a4db9c92aa8d9" + integrity sha512-P948trotU8FMHtaA7C2x97VpLq6QLSjO53kWNvONS0/XwEKQBIYCI7Jfri2wcLgfQg6Cn4OQGLoj2YBK3MMyww== -xterm@4.19.0-beta.17: - version "4.19.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.17.tgz#79b177eedd3bc835e1951f38318b5c0c04039896" - integrity sha512-NvfGJLfZa0SHGR6WttNfugRYizM20gVbWM/nVJAlyHruMZ/rfJj29MuPERJAZTNHtRnYplhAP8bSc3r7/2l+dg== +xterm@4.19.0-beta.20: + version "4.19.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.20.tgz#d8e970d8a8460c1d1a5ec9866f78f607a44c1349" + integrity sha512-IYI4ngSWzpV4sJXLWGEDF7vgLuUHn0CUQ42+TGv4H/hCGo4uru4s/D3Yws0ETb3a9VwRpZEPsigULaWTnhFusg== diff --git a/remote/yarn.lock b/remote/yarn.lock index 2d50c3bc983..381610e5a8d 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -914,35 +914,35 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-search@0.9.0-beta.17: - version "0.9.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.17.tgz#4cd575fd67a010af3d0b224092527747bb87c219" - integrity sha512-/Q6xQ/HunP2BxJU4NTsLX9aH376tsT9dpcS+NFBDVbwB1iPF02JhedHmA4mxY3KGNyQflefhwyGGMKZfTau2iA== +xterm-addon-search@0.9.0-beta.18: + version "0.9.0-beta.18" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.18.tgz#5317aed1dc747f468ccb7ecd151fb00d82a8a19d" + integrity sha512-SAeA3thc2WJNYXwjOEJFLpZ1ZVOs22RLmz9a6WcrzXkvCjLZRvbRGwX25Ms+Dd7dVDQNbKVUzUJohspP/vYr0Q== -xterm-addon-serialize@0.7.0-beta.11: - version "0.7.0-beta.11" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.11.tgz#d9d6a862b3d70fc6160e39bc235a2a9ef45e20d6" - integrity sha512-okirLeH8VpOxlnZkER2lN0emaTgWe/DHVGpY9ByfLIoYw506Ci2LRcOjyYwJBRTJcfLp3TGnwQSYfooCZHDndw== +xterm-addon-serialize@0.7.0-beta.12: + version "0.7.0-beta.12" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.12.tgz#4f845d8b1a9f9b7ae3f910455ce8c58b041babc7" + integrity sha512-b4Ug0B/RSJMux+KAcp+PXVqubVyXjN1yCQw1FOkgVYTpmd9AH/X+EcxKml5Lz8DsKmsXqfD9AlV3WpEeT+OtMw== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.25: - version "0.12.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.25.tgz#67fd222d245c4bf749b2abdf0acec640fb575bcd" - integrity sha512-QK0r6hi+plkMtHZrOlUO/IcDa9mnYxOKrqrmzbjxT6cuhXJf2EiWpBBY6Rkk0cVXtDOlkGO1b7hWvD3qeWeWvQ== +xterm-addon-webgl@0.12.0-beta.27: + version "0.12.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.27.tgz#afc5bc01d1ef3af9005fb9f6325a4db9c92aa8d9" + integrity sha512-P948trotU8FMHtaA7C2x97VpLq6QLSjO53kWNvONS0/XwEKQBIYCI7Jfri2wcLgfQg6Cn4OQGLoj2YBK3MMyww== -xterm-headless@4.19.0-beta.17: - version "4.19.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.17.tgz#0540b4526f31f2aab6d026f91ac56475260d45e0" - integrity sha512-A6CbJauiCDur5BZ6kHOCJ3rPLPAdX4JHMGazt0UoYkgbi0xQun+3P2M8C7Ll/NS/zZtv6aPJHAHeXu2TWqV5Lg== +xterm-headless@4.19.0-beta.20: + version "4.19.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.20.tgz#9e401920fcc24c2474e0bd45df932c62413594da" + integrity sha512-twp0vCyfdI4wVgDrwxaHk1FtC4UhTNNgbIPT6yVPjICOUkUTOvFjrQCNKHv2uMOJo9uAH2gyOsIqHdEP549rJA== -xterm@4.19.0-beta.17: - version "4.19.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.17.tgz#79b177eedd3bc835e1951f38318b5c0c04039896" - integrity sha512-NvfGJLfZa0SHGR6WttNfugRYizM20gVbWM/nVJAlyHruMZ/rfJj29MuPERJAZTNHtRnYplhAP8bSc3r7/2l+dg== +xterm@4.19.0-beta.20: + version "4.19.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.20.tgz#d8e970d8a8460c1d1a5ec9866f78f607a44c1349" + integrity sha512-IYI4ngSWzpV4sJXLWGEDF7vgLuUHn0CUQ42+TGv4H/hCGo4uru4s/D3Yws0ETb3a9VwRpZEPsigULaWTnhFusg== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index 03c1363d3dd..8187a7e0699 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12324,35 +12324,35 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.9.0-beta.17: - version "0.9.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.17.tgz#4cd575fd67a010af3d0b224092527747bb87c219" - integrity sha512-/Q6xQ/HunP2BxJU4NTsLX9aH376tsT9dpcS+NFBDVbwB1iPF02JhedHmA4mxY3KGNyQflefhwyGGMKZfTau2iA== +xterm-addon-search@0.9.0-beta.18: + version "0.9.0-beta.18" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.18.tgz#5317aed1dc747f468ccb7ecd151fb00d82a8a19d" + integrity sha512-SAeA3thc2WJNYXwjOEJFLpZ1ZVOs22RLmz9a6WcrzXkvCjLZRvbRGwX25Ms+Dd7dVDQNbKVUzUJohspP/vYr0Q== -xterm-addon-serialize@0.7.0-beta.11: - version "0.7.0-beta.11" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.11.tgz#d9d6a862b3d70fc6160e39bc235a2a9ef45e20d6" - integrity sha512-okirLeH8VpOxlnZkER2lN0emaTgWe/DHVGpY9ByfLIoYw506Ci2LRcOjyYwJBRTJcfLp3TGnwQSYfooCZHDndw== +xterm-addon-serialize@0.7.0-beta.12: + version "0.7.0-beta.12" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.12.tgz#4f845d8b1a9f9b7ae3f910455ce8c58b041babc7" + integrity sha512-b4Ug0B/RSJMux+KAcp+PXVqubVyXjN1yCQw1FOkgVYTpmd9AH/X+EcxKml5Lz8DsKmsXqfD9AlV3WpEeT+OtMw== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.25: - version "0.12.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.25.tgz#67fd222d245c4bf749b2abdf0acec640fb575bcd" - integrity sha512-QK0r6hi+plkMtHZrOlUO/IcDa9mnYxOKrqrmzbjxT6cuhXJf2EiWpBBY6Rkk0cVXtDOlkGO1b7hWvD3qeWeWvQ== +xterm-addon-webgl@0.12.0-beta.27: + version "0.12.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.27.tgz#afc5bc01d1ef3af9005fb9f6325a4db9c92aa8d9" + integrity sha512-P948trotU8FMHtaA7C2x97VpLq6QLSjO53kWNvONS0/XwEKQBIYCI7Jfri2wcLgfQg6Cn4OQGLoj2YBK3MMyww== -xterm-headless@4.19.0-beta.17: - version "4.19.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.17.tgz#0540b4526f31f2aab6d026f91ac56475260d45e0" - integrity sha512-A6CbJauiCDur5BZ6kHOCJ3rPLPAdX4JHMGazt0UoYkgbi0xQun+3P2M8C7Ll/NS/zZtv6aPJHAHeXu2TWqV5Lg== +xterm-headless@4.19.0-beta.20: + version "4.19.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.20.tgz#9e401920fcc24c2474e0bd45df932c62413594da" + integrity sha512-twp0vCyfdI4wVgDrwxaHk1FtC4UhTNNgbIPT6yVPjICOUkUTOvFjrQCNKHv2uMOJo9uAH2gyOsIqHdEP549rJA== -xterm@4.19.0-beta.17: - version "4.19.0-beta.17" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.17.tgz#79b177eedd3bc835e1951f38318b5c0c04039896" - integrity sha512-NvfGJLfZa0SHGR6WttNfugRYizM20gVbWM/nVJAlyHruMZ/rfJj29MuPERJAZTNHtRnYplhAP8bSc3r7/2l+dg== +xterm@4.19.0-beta.20: + version "4.19.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.20.tgz#d8e970d8a8460c1d1a5ec9866f78f607a44c1349" + integrity sha512-IYI4ngSWzpV4sJXLWGEDF7vgLuUHn0CUQ42+TGv4H/hCGo4uru4s/D3Yws0ETb3a9VwRpZEPsigULaWTnhFusg== y18n@^3.2.1: version "3.2.2" From 6fcf02f29a125db24f67bd9dc43110a02773edf0 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 1 Apr 2022 13:20:50 -0700 Subject: [PATCH 016/135] testing: re-enable possibly fixed tests --- test/unit/node/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/unit/node/index.js b/test/unit/node/index.js index d59ff18c3f5..8ef90e8dc4e 100644 --- a/test/unit/node/index.js +++ b/test/unit/node/index.js @@ -28,8 +28,6 @@ const excludeGlob = '**/{browser,electron-sandbox,electron-browser,electron-main const excludeModules = [ 'vs/platform/environment/test/node/nativeModules.test.js', // native modules are compiled against Electron and this test would fail with node.js 'vs/base/parts/storage/test/node/storage.test.js', // same as above, due to direct dependency to sqlite native module - 'vs/workbench/contrib/testing/test/common/testResultStorage.test.js', // TODO@connor4312 https://github.com/microsoft/vscode/issues/137853 - 'vs/workbench/contrib/testing/test/common/testResultService.test.js', // TODO@connor4312 https://github.com/microsoft/vscode/issues/137853 ]; /** From 0b9a6b5fb57757d719c43d6722eafa0fab3dff06 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 1 Apr 2022 14:47:59 -0700 Subject: [PATCH 017/135] re #141651. Disable find in preview/outputs in safari. --- .../contrib/find/notebookFindReplaceWidget.ts | 111 ++++++++++-------- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts index 38c9042b175..9e7e660b6b0 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget.ts @@ -34,6 +34,7 @@ import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { filterIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; import { NotebookFindFilters } from 'vs/workbench/contrib/notebook/browser/contrib/find/findFilters'; +import { isSafari } from 'vs/base/common/platform'; const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find"); const NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', "Find"); @@ -73,57 +74,73 @@ class NotebookFindFilterActionViewItem extends DropdownMenuActionViewItem { } private getActions(): IAction[] { - return [ - { - checked: this.filters.markupInput, - class: undefined, - enabled: !this.filters.markupPreview, - id: 'findInMarkdownInput', - label: NOTEBOOK_FIND_IN_MARKUP_INPUT, - run: async () => { - this.filters.markupInput = !this.filters.markupInput; - }, - tooltip: '', - dispose: () => null + const markdownInput: IAction = { + checked: this.filters.markupInput, + class: undefined, + enabled: !this.filters.markupPreview, + id: 'findInMarkdownInput', + label: NOTEBOOK_FIND_IN_MARKUP_INPUT, + run: async () => { + this.filters.markupInput = !this.filters.markupInput; }, - { - checked: this.filters.markupPreview, - class: undefined, - enabled: true, - id: 'findInMarkdownInput', - label: NOTEBOOK_FIND_IN_MARKUP_PREVIEW, - run: async () => { - this.filters.markupPreview = !this.filters.markupPreview; - }, - tooltip: '', - dispose: () => null + tooltip: '', + dispose: () => null + }; + + const markdownPreview: IAction = { + checked: this.filters.markupPreview, + class: undefined, + enabled: true, + id: 'findInMarkdownInput', + label: NOTEBOOK_FIND_IN_MARKUP_PREVIEW, + run: async () => { + this.filters.markupPreview = !this.filters.markupPreview; }, - new Separator(), - { - checked: this.filters.codeInput, - class: undefined, - enabled: true, - id: 'findInCodeInput', - label: NOTEBOOK_FIND_IN_CODE_INPUT, - run: async () => { - this.filters.codeInput = !this.filters.codeInput; - }, - tooltip: '', - dispose: () => null + tooltip: '', + dispose: () => null + }; + + const codeInput: IAction = { + checked: this.filters.codeInput, + class: undefined, + enabled: true, + id: 'findInCodeInput', + label: NOTEBOOK_FIND_IN_CODE_INPUT, + run: async () => { + this.filters.codeInput = !this.filters.codeInput; }, - { - checked: this.filters.codeOutput, - class: undefined, - enabled: true, - id: 'findInCodeOutput', - label: NOTEBOOK_FIND_IN_CODE_OUTPUT, - run: async () => { - this.filters.codeOutput = !this.filters.codeOutput; - }, - tooltip: '', - dispose: () => null + tooltip: '', + dispose: () => null + }; + + const codeOutput = { + checked: this.filters.codeOutput, + class: undefined, + enabled: true, + id: 'findInCodeOutput', + label: NOTEBOOK_FIND_IN_CODE_OUTPUT, + run: async () => { + this.filters.codeOutput = !this.filters.codeOutput; }, - ]; + tooltip: '', + dispose: () => null + }; + + if (isSafari) { + return [ + markdownInput, + codeInput + ]; + } else { + return [ + markdownInput, + markdownPreview, + new Separator(), + codeInput, + codeOutput, + ]; + } + } override updateChecked(): void { From 41e7b8519532f124c4178af9331ba23aa0600bd1 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 1 Apr 2022 15:05:35 -0700 Subject: [PATCH 018/135] fix #141377. 200 delay for async find. --- .../notebook/browser/contrib/find/findController.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts index 76eebf9ffe3..662b1929a2e 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts @@ -41,6 +41,7 @@ import { isEqual } from 'vs/base/common/resources'; const FIND_HIDE_TRANSITION = 'find-hide-transition'; const FIND_SHOW_TRANSITION = 'find-show-transition'; let MAX_MATCHES_COUNT_WIDTH = 69; +const PROGRESS_BAR_DELAY = 200; // show progress for at least 200ms export class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEditorContribution { static id: string = 'workbench.notebook.find'; @@ -76,9 +77,9 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote if (e.isSearching) { if (this._state.isSearching) { - this._progressBar.infinite().show(); + this._progressBar.infinite().show(PROGRESS_BAR_DELAY); } else { - this._progressBar.stop(); + this._progressBar.stop().hide(); } } @@ -148,7 +149,7 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote if (currentMatch.isModelMatch) { const match = currentMatch.match as FindMatch; - this._progressBar.infinite().show(); + this._progressBar.infinite().show(PROGRESS_BAR_DELAY); const replacePattern = this.replacePattern; const replaceString = replacePattern.buildReplaceString(match.matches, this._state.preserveCase); @@ -168,7 +169,7 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote return; } - this._progressBar.infinite().show(); + this._progressBar.infinite().show(PROGRESS_BAR_DELAY); const replacePattern = this.replacePattern; From 54511198204b96dc2b6677a8487d0db7034cf6bd Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 1 Apr 2022 11:43:50 -0700 Subject: [PATCH 019/135] Adopt SnippetTextEdit for drop --- .../src/languageFeatures/dropIntoEditor.ts | 6 +++--- src/vscode-dts/vscode.proposed.textEditorDrop.d.ts | 5 +---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts index dba36394bc0..c1e4dbcb89d 100644 --- a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts +++ b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts @@ -9,10 +9,10 @@ import * as URI from 'vscode-uri'; export function registerDropIntoEditor() { return vscode.workspace.onWillDropOnTextEditor(e => { - e.waitUntil((async () => { + e.waitUntil((async (): Promise => { const urlList = await e.dataTransfer.get('text/uri-list')?.asString(); if (!urlList) { - return; + return undefined; } const uris: vscode.Uri[] = []; @@ -41,7 +41,7 @@ export function registerDropIntoEditor() { } }); - return e.editor.insertSnippet(snippet, e.position); + return new vscode.SnippetTextEdit(new vscode.Range(e.position, e.position), snippet); })()); }); } diff --git a/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts b/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts index efddb06d421..43bf20425f4 100644 --- a/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts +++ b/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts @@ -48,10 +48,7 @@ declare module 'vscode' { * * @param thenable A thenable that delays saving. */ - waitUntil(thenable: Thenable): void; - - // - waitUntil(thenable: Thenable): void; + waitUntil(thenable: Thenable): void; token: CancellationToken; } From 44ffeba23714e9333aa5e68aa53685faeb280bf5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 1 Apr 2022 15:50:17 -0700 Subject: [PATCH 020/135] Switch to provider based model for on drop This simplifies implementing the provider and also give potentially gives us more control over how the drop happens --- .../src/extension.ts | 3 +- .../src/languageFeatures/dropIntoEditor.ts | 14 +-- src/vs/editor/common/languages.ts | 20 ++++ .../common/services/languageFeatures.ts | 4 +- .../services/languageFeaturesService.ts | 4 +- .../browser/mainThreadDocumentsAndEditors.ts | 2 +- .../api/browser/mainThreadEditors.ts | 82 +------------- .../api/browser/mainThreadLanguageFeatures.ts | 107 +++++++++++++++++- .../workbench/api/common/extHost.api.impl.ts | 8 +- .../workbench/api/common/extHost.protocol.ts | 3 +- .../api/common/extHostLanguageFeatures.ts | 38 ++++++- .../api/common/extHostTextEditors.ts | 42 +------ .../vscode.proposed.textEditorDrop.d.ts | 47 +------- 13 files changed, 188 insertions(+), 186 deletions(-) diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index eac0433c22b..abc4e70d6a4 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -49,8 +49,6 @@ export function activate(context: vscode.ExtensionContext) { logger.updateConfiguration(); previewManager.updateConfiguration(); })); - - context.subscriptions.push(registerDropIntoEditor()); } function registerMarkdownLanguageFeatures( @@ -72,6 +70,7 @@ function registerMarkdownLanguageFeatures( vscode.languages.registerReferenceProvider(selector, referencesProvider), vscode.languages.registerRenameProvider(selector, new MdRenameProvider(referencesProvider, githubSlugifier)), MdPathCompletionProvider.register(selector, engine, linkProvider), + registerDropIntoEditor(selector), ); } diff --git a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts index c1e4dbcb89d..14a2ace9db6 100644 --- a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts +++ b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts @@ -7,10 +7,10 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as URI from 'vscode-uri'; -export function registerDropIntoEditor() { - return vscode.workspace.onWillDropOnTextEditor(e => { - e.waitUntil((async (): Promise => { - const urlList = await e.dataTransfer.get('text/uri-list')?.asString(); +export function registerDropIntoEditor(selector: vscode.DocumentSelector) { + return vscode.languages.registerDocumentOnDropProvider(selector, new class implements vscode.DocumentOnDropProvider { + async provideDocumentOnDropEdits(document: vscode.TextDocument, position: vscode.Position, dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise { + const urlList = await dataTransfer.get('text/uri-list')?.asString(); if (!urlList) { return undefined; } @@ -30,7 +30,7 @@ export function registerDropIntoEditor() { const snippet = new vscode.SnippetString(); uris.forEach((uri, i) => { - const rel = path.relative(URI.Utils.dirname(e.editor.document.uri).fsPath, uri.fsPath); + const rel = path.relative(URI.Utils.dirname(document.uri).fsPath, uri.fsPath); snippet.appendText('['); snippet.appendTabstop(); @@ -41,7 +41,7 @@ export function registerDropIntoEditor() { } }); - return new vscode.SnippetTextEdit(new vscode.Range(e.position, e.position), snippet); - })()); + return new vscode.SnippetTextEdit(new vscode.Range(position, position), snippet); + } }); } diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts index b46e402b0f4..de092a4d1be 100644 --- a/src/vs/editor/common/languages.ts +++ b/src/vs/editor/common/languages.ts @@ -1968,3 +1968,23 @@ export enum ExternalUriOpenerPriority { Default = 2, Preferred = 3, } + +/** + * @internal + */ +export interface IDataTransferItem { + asString(): Thenable; + value: any; +} + +/** + * @internal + */ +export type IDataTransfer = Map; + +/** + * @internal + */ +export interface DocumentOnDropEditProvider { + provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: IDataTransfer, token: CancellationToken): ProviderResult; +} diff --git a/src/vs/editor/common/services/languageFeatures.ts b/src/vs/editor/common/services/languageFeatures.ts index 14bd7532635..e0ba2416582 100644 --- a/src/vs/editor/common/services/languageFeatures.ts +++ b/src/vs/editor/common/services/languageFeatures.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { LanguageFeatureRegistry, NotebookInfoResolver } from 'vs/editor/common/languageFeatureRegistry'; -import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; +import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentOnDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const ILanguageFeaturesService = createDecorator('ILanguageFeaturesService'); @@ -67,6 +67,8 @@ export interface ILanguageFeaturesService { readonly evaluatableExpressionProvider: LanguageFeatureRegistry; + readonly documentOnDropEditProvider: LanguageFeatureRegistry; + // -- setNotebookTypeResolver(resolver: NotebookInfoResolver | undefined): void; diff --git a/src/vs/editor/common/services/languageFeaturesService.ts b/src/vs/editor/common/services/languageFeaturesService.ts index 92f57d892a7..2ed7cebcf62 100644 --- a/src/vs/editor/common/services/languageFeaturesService.ts +++ b/src/vs/editor/common/services/languageFeaturesService.ts @@ -5,7 +5,7 @@ import { URI } from 'vs/base/common/uri'; import { LanguageFeatureRegistry, NotebookInfo, NotebookInfoResolver } from 'vs/editor/common/languageFeatureRegistry'; -import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; +import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentOnDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -40,7 +40,7 @@ export class LanguageFeaturesService implements ILanguageFeaturesService { readonly evaluatableExpressionProvider = new LanguageFeatureRegistry(this._score.bind(this)); readonly documentRangeSemanticTokensProvider = new LanguageFeatureRegistry(this._score.bind(this)); readonly documentSemanticTokensProvider = new LanguageFeatureRegistry(this._score.bind(this)); - + readonly documentOnDropEditProvider = new LanguageFeatureRegistry(this._score.bind(this)); private _notebookTypeResolver?: NotebookInfoResolver; diff --git a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts index 8c2a77ecd84..12b5786f94f 100644 --- a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts @@ -304,7 +304,7 @@ export class MainThreadDocumentsAndEditors { this._mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(extHostContext, this._modelService, this._textFileService, fileService, textModelResolverService, environmentService, uriIdentityService, workingCopyFileService, pathService)); extHostContext.set(MainContext.MainThreadDocuments, this._mainThreadDocuments); - this._mainThreadEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, this._editorService, this._editorGroupService, instantiationService)); + this._mainThreadEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, this._editorService, this._editorGroupService)); extHostContext.set(MainContext.MainThreadTextEditors, this._mainThreadEditors); // It is expected that the ctor of the state computer calls our `_onDelta`. diff --git a/src/vs/workbench/api/browser/mainThreadEditors.ts b/src/vs/workbench/api/browser/mainThreadEditors.ts index e44487a63f7..80babfd1c70 100644 --- a/src/vs/workbench/api/browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadEditors.ts @@ -14,7 +14,7 @@ import { IDecorationOptions, IDecorationRenderOptions } from 'vs/editor/common/e import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ITextEditorOptions, IResourceEditorInput, EditorActivation, EditorResolution } from 'vs/platform/editor/common/editor'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor'; import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType } from 'vs/workbench/api/common/extHost.protocol'; import { editorGroupToColumn, columnToEditorGroup, EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; @@ -27,13 +27,6 @@ import { ILineChange } from 'vs/editor/common/diff/diffComputer'; import { IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { IEditorControl } from 'vs/workbench/common/editor'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { DataTransferConverter } from 'vs/workbench/api/common/shared/dataTransfer'; -import { IPosition } from 'vs/editor/common/core/position'; -import { IDataTransfer, IDataTransferItem } from 'vs/workbench/common/dnd'; -import { extractEditorsDropData } from 'vs/workbench/browser/dnd'; -import { Mimes } from 'vs/base/common/mime'; -import { distinct } from 'vs/base/common/arrays'; -import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2'; export interface IMainThreadEditorLocator { getEditor(id: string): MainThreadTextEditor | undefined; @@ -51,7 +44,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { private _textEditorsListenersMap: { [editorId: string]: IDisposable[] }; private _editorPositionData: ITextEditorPositionData | null; private _registeredDecorationTypes: { [decorationType: string]: boolean }; - private readonly _dropIntoEditorListeners = new Map(); constructor( private readonly _editorLocator: IMainThreadEditorLocator, @@ -59,7 +51,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @IEditorService private readonly _editorService: IEditorService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, - @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { this._instanceId = String(++MainThreadTextEditors.INSTANCE_COUNT); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors); @@ -71,22 +62,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { this._toDispose.add(this._editorGroupService.onDidRemoveGroup(() => this._updateActiveAndVisibleTextEditors())); this._toDispose.add(this._editorGroupService.onDidMoveGroup(() => this._updateActiveAndVisibleTextEditors())); - const registerDropListenerOnEditor = (editor: ICodeEditor) => { - this._dropIntoEditorListeners.get(editor)?.dispose(); - this._dropIntoEditorListeners.set(editor, editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event))); - }; - - this._toDispose.add(_codeEditorService.onCodeEditorAdd(registerDropListenerOnEditor)); - - this._toDispose.add(_codeEditorService.onCodeEditorRemove(editor => { - this._dropIntoEditorListeners.get(editor)?.dispose(); - this._dropIntoEditorListeners.delete(editor); - })); - - for (const editor of this._codeEditorService.listCodeEditors()) { - registerDropListenerOnEditor(editor); - } - this._registeredDecorationTypes = Object.create(null); } @@ -99,8 +74,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { for (let decorationType in this._registeredDecorationTypes) { this._codeEditorService.removeDecorationType(decorationType); } - dispose(this._dropIntoEditorListeners.values()); - this._dropIntoEditorListeners.clear(); this._registeredDecorationTypes = Object.create(null); } @@ -140,59 +113,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { return result; } - private async onDropIntoEditor(editor: ICodeEditor, position: IPosition, dragEvent: DragEvent) { - if (!dragEvent.dataTransfer || !editor.hasModel()) { - return; - } - const id = this._editorLocator.getIdOfCodeEditor(editor); - if (typeof id !== 'string') { - return; - } - - const modelVersionNow = editor.getModel().getVersionId(); - - const textEditorDataTransfer: IDataTransfer = new Map(); - for (const item of dragEvent.dataTransfer.items) { - if (item.kind === 'string') { - const type = item.type; - const asStringValue = new Promise(resolve => item.getAsString(resolve)); - textEditorDataTransfer.set(type, { - asString: () => asStringValue, - value: undefined - }); - } - } - - if (!textEditorDataTransfer.has(Mimes.uriList.toLowerCase())) { - const editorData = (await this._instantiationService.invokeFunction(extractEditorsDropData, dragEvent)) - .filter(input => input.resource) - .map(input => input.resource!.toString()); - - if (editorData.length) { - const str = distinct(editorData).join('\n'); - textEditorDataTransfer.set(Mimes.uriList.toLowerCase(), { - asString: () => Promise.resolve(str), - value: undefined - }); - } - } - - if (textEditorDataTransfer.size === 0) { - return; - } - - const dataTransferDto = await DataTransferConverter.toDataTransferDTO(textEditorDataTransfer); - const edits = await this._proxy.$textEditorHandleDrop(id, position, dataTransferDto); - if (edits.length === 0) { - return; - } - - if (editor.getModel().getVersionId() === modelVersionNow) { - const [first] = edits; // TODO@jrieken define how to pick the "one snippet edit"; - performSnippetEdit(editor, first); - } - } - // --- from extension host process async $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index a4c3cfbc729..9664df7b430 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -3,14 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { distinct } from 'vs/base/common/arrays'; import { Emitter, Event } from 'vs/base/common/event'; import { ITextModel } from 'vs/editor/common/model'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import * as languages from 'vs/editor/common/languages'; import * as search from 'vs/workbench/contrib/search/common/search'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { Position as EditorPosition } from 'vs/editor/common/core/position'; +import { IPosition, Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange, IRange } from 'vs/editor/common/core/range'; import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, ILocationLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto, IdentifiableInlineCompletions, IdentifiableInlineCompletion, ITypeHierarchyItemDto, IInlayHintDto } from '../common/extHost.protocol'; import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; @@ -27,19 +28,33 @@ import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticToken import { revive } from 'vs/base/common/marshalling'; import { CancellationError } from 'vs/base/common/errors'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import { Mimes } from 'vs/base/common/mime'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2'; +import { DataTransferConverter } from 'vs/workbench/api/common/shared/dataTransfer'; +import { extractEditorsDropData } from 'vs/workbench/browser/dnd'; +import { IDataTransfer, IDataTransferItem } from 'vs/workbench/common/dnd'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) -export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape { +export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape { private readonly _proxy: ExtHostLanguageFeaturesShape; private readonly _registrations = new Map(); + private readonly _dropIntoEditorListeners = new Map(); + constructor( extHostContext: IExtHostContext, @ILanguageService private readonly _languageService: ILanguageService, @ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService, @ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService, + @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { + super(); + this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures); if (this._languageService) { @@ -69,13 +84,34 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha }); updateAllWordDefinitions(); } + + const registerDropListenerOnEditor = (editor: ICodeEditor) => { + this._dropIntoEditorListeners.get(editor)?.dispose(); + this._dropIntoEditorListeners.set(editor, editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event))); + }; + + this._register(_codeEditorService.onCodeEditorAdd(registerDropListenerOnEditor)); + + this._register(_codeEditorService.onCodeEditorRemove(editor => { + this._dropIntoEditorListeners.get(editor)?.dispose(); + this._dropIntoEditorListeners.delete(editor); + })); + + for (const editor of this._codeEditorService.listCodeEditors()) { + registerDropListenerOnEditor(editor); + } } - dispose(): void { + override dispose(): void { for (const registration of this._registrations.values()) { registration.dispose(); } this._registrations.clear(); + + dispose(this._dropIntoEditorListeners.values()); + this._dropIntoEditorListeners.clear(); + + super.dispose(); } $unregister(handle: number): void { @@ -850,6 +886,69 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha })); } + + // --- document drop Edits + + $registerDocumentOnDropProvider(handle: number, selector: IDocumentFilterDto[]): void { + this._registrations.set(handle, this._languageFeaturesService.documentOnDropEditProvider.register(selector, { + provideDocumentOnDropEdits: async (model, position, dataTransfer, token) => { + const dataTransferDto = await DataTransferConverter.toDataTransferDTO(dataTransfer); + return this._proxy.$provideDocumentOnDropEdits(handle, model.uri, position, dataTransferDto, token); + } + })); + } + + private async onDropIntoEditor(editor: ICodeEditor, position: IPosition, dragEvent: DragEvent) { + if (!dragEvent.dataTransfer || !editor.hasModel()) { + return; + } + + const model = editor.getModel(); + const modelVersionNow = model.getVersionId(); + + const textEditorDataTransfer: IDataTransfer = new Map(); + for (const item of dragEvent.dataTransfer.items) { + if (item.kind === 'string') { + const type = item.type; + const asStringValue = new Promise(resolve => item.getAsString(resolve)); + textEditorDataTransfer.set(type, { + asString: () => asStringValue, + value: undefined + }); + } + } + + if (!textEditorDataTransfer.has(Mimes.uriList.toLowerCase())) { + const editorData = (await this._instantiationService.invokeFunction(extractEditorsDropData, dragEvent)) + .filter(input => input.resource) + .map(input => input.resource!.toString()); + + if (editorData.length) { + const str = distinct(editorData).join('\n'); + textEditorDataTransfer.set(Mimes.uriList.toLowerCase(), { + asString: () => Promise.resolve(str), + value: undefined + }); + } + } + + if (textEditorDataTransfer.size === 0) { + return; + } + + const ordered = this._languageFeaturesService.documentOnDropEditProvider.ordered(model); + for (const provider of ordered) { + const edit = await provider.provideDocumentOnDropEdits(model, position, textEditorDataTransfer, CancellationToken.None); + if (editor.getModel().getVersionId() !== modelVersionNow) { + return; + } + + if (edit) { + performSnippetEdit(editor, edit); + return; + } + } + } } export class MainThreadDocumentSemanticTokensProvider implements languages.DocumentSemanticTokensProvider { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index bcdf64ad6bc..e59da75b06d 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -532,6 +532,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, createLanguageStatusItem(id: string, selector: vscode.DocumentSelector): vscode.LanguageStatusItem { return extHostLanguages.createLanguageStatusItem(extension, id, selector); + }, + registerDocumentOnDropProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentOnDropProvider): vscode.Disposable { + checkProposedApiEnabled(extension, 'textEditorDrop'); + return extHostLanguageFeatures.registerDocumentOnDropProvider(extension, selector, provider); } }; @@ -872,10 +876,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I onWillSaveTextDocument: (listener, thisArgs?, disposables?) => { return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables); }, - onWillDropOnTextEditor: (listener, thisArgs?, disposables?) => { - checkProposedApiEnabled(extension, 'textEditorDrop'); - return extHostEditors.onWillDropOnTextEditor(listener, thisArgs, disposables); - }, get notebookDocuments(): vscode.NotebookDocument[] { return extHostNotebook.notebookDocuments.map(d => d.apiNotebook); }, diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index c5e114a3f3b..c33567f8d99 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -390,6 +390,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void; + $registerDocumentOnDropProvider(handle: number, selector: IDocumentFilterDto[]): void; $setLanguageConfiguration(handle: number, languageId: string, configuration: ILanguageConfigurationDto): void; } @@ -1329,7 +1330,6 @@ export interface ISelectionChangeEvent { export interface ExtHostEditorsShape { $acceptEditorPropertiesChanged(id: string, props: IEditorPropertiesChangeData): void; $acceptEditorPositionData(data: ITextEditorPositionData): void; - $textEditorHandleDrop(id: string, position: IPosition, dataTransferDto: DataTransferDTO): Promise>; } export interface IDocumentsAndEditorsDelta { @@ -1734,6 +1734,7 @@ export interface ExtHostLanguageFeaturesShape { $provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise; $provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise; $releaseTypeHierarchy(handle: number, sessionId: string): void; + $provideDocumentOnDropEdits(handle: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise | undefined>; } export interface ExtHostQuickOpenShape { diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index e5ca7469fb0..2cc57319c69 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -35,6 +35,8 @@ import { isCancellationError } from 'vs/base/common/errors'; import { Emitter } from 'vs/base/common/event'; import { raceCancellationError } from 'vs/base/common/async'; import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { DataTransferConverter, DataTransferDTO } from 'vs/workbench/api/common/shared/dataTransfer'; +import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier'; // --- adapter @@ -1712,6 +1714,27 @@ class TypeHierarchyAdapter { return map?.get(itemId); } } + +class DocumentOnDropAdapter { + + constructor( + private readonly _documents: ExtHostDocuments, + private readonly _provider: vscode.DocumentOnDropProvider + ) { } + + async provideDocumentOnDropEdits(uri: URI, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise | undefined> { + const doc = this._documents.getDocument(uri); + const pos = typeConvert.Position.to(position); + const dataTransfer = DataTransferConverter.toDataTransfer(dataTransferDto); + + const edit = await this._provider.provideDocumentOnDropEdits(doc, pos, dataTransfer, token); + if (!edit) { + return undefined; + } + return typeConvert.SnippetTextEdit.from(edit); + } +} + type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter | DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter @@ -1720,7 +1743,8 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov | SelectionRangeAdapter | CallHierarchyAdapter | TypeHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter | InlineValuesAdapter - | LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter | InlineCompletionAdapterNew; + | LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter | InlineCompletionAdapterNew + | DocumentOnDropAdapter; class AdapterData { constructor( @@ -2341,6 +2365,18 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF this._withAdapter(handle, TypeHierarchyAdapter, adapter => Promise.resolve(adapter.releaseSession(sessionId)), undefined, undefined); } + // --- Document on drop + + registerDocumentOnDropProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentOnDropProvider) { + const handle = this._addNewAdapter(new DocumentOnDropAdapter(this._documents, provider), extension); + this._proxy.$registerDocumentOnDropProvider(handle, this._transformDocumentSelector(selector)); + return this._createDisposable(handle); + } + + $provideDocumentOnDropEdits(handle: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise | undefined> { + return this._withAdapter(handle, DocumentOnDropAdapter, adapter => Promise.resolve(adapter.provideDocumentOnDropEdits(URI.revive(resource), position, dataTransferDto, token)), undefined, undefined); + } + // --- configuration private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto { diff --git a/src/vs/workbench/api/common/extHostTextEditors.ts b/src/vs/workbench/api/common/extHostTextEditors.ts index e5373fe549c..b221ea9710c 100644 --- a/src/vs/workbench/api/common/extHostTextEditors.ts +++ b/src/vs/workbench/api/common/extHostTextEditors.ts @@ -3,20 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AsyncEmitter, Emitter, Event } from 'vs/base/common/event'; import * as arrays from 'vs/base/common/arrays'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/common/extHostTextEditor'; import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; -import { SnippetTextEdit, TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes'; +import { TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes'; import * as vscode from 'vscode'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { DataTransferConverter, DataTransferDTO } from 'vs/workbench/api/common/shared/dataTransfer'; -import { IPosition } from 'vs/editor/common/core/position'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier'; -import * as languages from 'vs/editor/common/languages'; export class ExtHostEditors implements ExtHostEditorsShape { @@ -26,7 +21,6 @@ export class ExtHostEditors implements ExtHostEditorsShape { private readonly _onDidChangeTextEditorViewColumn = new Emitter(); private readonly _onDidChangeActiveTextEditor = new Emitter(); private readonly _onDidChangeVisibleTextEditors = new Emitter(); - private readonly _onWillDropOnTextEditor = new AsyncEmitter(); readonly onDidChangeTextEditorSelection: Event = this._onDidChangeTextEditorSelection.event; readonly onDidChangeTextEditorOptions: Event = this._onDidChangeTextEditorOptions.event; @@ -34,7 +28,6 @@ export class ExtHostEditors implements ExtHostEditorsShape { readonly onDidChangeTextEditorViewColumn: Event = this._onDidChangeTextEditorViewColumn.event; readonly onDidChangeActiveTextEditor: Event = this._onDidChangeActiveTextEditor.event; readonly onDidChangeVisibleTextEditors: Event = this._onDidChangeVisibleTextEditors.event; - readonly onWillDropOnTextEditor: Event = this._onWillDropOnTextEditor.event; private readonly _proxy: MainThreadTextEditorsShape; @@ -166,33 +159,4 @@ export class ExtHostEditors implements ExtHostEditorsShape { getDiffInformation(id: string): Promise { return Promise.resolve(this._proxy.$getDiffInformation(id)); } - - // --- Text editor drag and drop - - async $textEditorHandleDrop(id: string, position: IPosition, dataTransferDto: DataTransferDTO): Promise> { - const textEditor = this._extHostDocumentsAndEditors.getEditor(id); - if (!textEditor) { - throw new Error('Unknown text editor'); - } - - const pos = TypeConverters.Position.to(position); - const dataTransfer = DataTransferConverter.toDataTransfer(dataTransferDto); - - const event = Object.freeze({ - editor: textEditor.value, - position: pos, - dataTransfer: dataTransfer - }); - - const edits: SnippetTextEdit[] = []; - - await this._onWillDropOnTextEditor.fireAsync(event, CancellationToken.None, async p => { - const value = await p; - if (value instanceof SnippetTextEdit) { - edits.push(value); - } - }); - - return edits.map(TypeConverters.SnippetTextEdit.from); - } } diff --git a/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts b/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts index 43bf20425f4..35a712c749c 100644 --- a/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts +++ b/src/vscode-dts/vscode.proposed.textEditorDrop.d.ts @@ -13,50 +13,11 @@ declare module 'vscode' { constructor(range: Range, snippet: SnippetString); } - - export interface TextEditorDropEvent { - /** - * The {@link TextEditor} the resource was dropped onto. - */ - readonly editor: TextEditor; - - /** - * The position in the file where the drop occurred - */ - readonly position: Position; - - /** - * The {@link DataTransfer data transfer} associated with this drop. - */ - readonly dataTransfer: DataTransfer; - - /** - * Allows to pause the event to delay apply the drop. - * - * *Note:* This function can only be called during event dispatch and not - * in an asynchronous manner: - * - * ```ts - * workspace.onWillDropOnTextEditor(event => { - * // async, will *throw* an error - * setTimeout(() => event.waitUntil(promise)); - * - * // sync, OK - * event.waitUntil(promise); - * }) - * ``` - * - * @param thenable A thenable that delays saving. - */ - waitUntil(thenable: Thenable): void; - - token: CancellationToken; + export interface DocumentOnDropProvider { + provideDocumentOnDropEdits(document: TextDocument, position: Position, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult; } - export namespace workspace { - /** - * Event fired when the user drops a resource into a text editor. - */ - export const onWillDropOnTextEditor: Event; + export namespace languages { + export function registerDocumentOnDropProvider(selector: DocumentSelector, provider: DocumentOnDropProvider): Disposable; } } From ae0f691839eff7dc0354224f7cff9ed3a128cf54 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 1 Apr 2022 16:32:53 -0700 Subject: [PATCH 021/135] _codeEditorService is optional in tests --- .../api/browser/mainThreadLanguageFeatures.ts | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 9664df7b430..be97123b3c9 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -85,20 +85,22 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread updateAllWordDefinitions(); } - const registerDropListenerOnEditor = (editor: ICodeEditor) => { - this._dropIntoEditorListeners.get(editor)?.dispose(); - this._dropIntoEditorListeners.set(editor, editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event))); - }; + if (this._codeEditorService) { + const registerDropListenerOnEditor = (editor: ICodeEditor) => { + this._dropIntoEditorListeners.get(editor)?.dispose(); + this._dropIntoEditorListeners.set(editor, editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event))); + }; - this._register(_codeEditorService.onCodeEditorAdd(registerDropListenerOnEditor)); + this._register(this._codeEditorService.onCodeEditorAdd(registerDropListenerOnEditor)); - this._register(_codeEditorService.onCodeEditorRemove(editor => { - this._dropIntoEditorListeners.get(editor)?.dispose(); - this._dropIntoEditorListeners.delete(editor); - })); + this._register(this._codeEditorService.onCodeEditorRemove(editor => { + this._dropIntoEditorListeners.get(editor)?.dispose(); + this._dropIntoEditorListeners.delete(editor); + })); - for (const editor of this._codeEditorService.listCodeEditors()) { - registerDropListenerOnEditor(editor); + for (const editor of this._codeEditorService.listCodeEditors()) { + registerDropListenerOnEditor(editor); + } } } From 24e73f3551a59166d34d0deecbb623c24af67645 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Sat, 2 Apr 2022 00:32:29 -0700 Subject: [PATCH 022/135] Update scm decorator width for modified (#146588) * Update scm decorator width for modified * Remove duplicate property --- src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index 055172e9e9b..8452bba60ca 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -1371,7 +1371,8 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor private setViewState(state: IViewState): void { this.viewState = state; this.stylesheet.textContent = ` - .monaco-editor .dirty-diff-modified,.monaco-editor .dirty-diff-added{border-left-width:${state.width}px;} + .monaco-editor .dirty-diff-modified { background-size: ${state.width}px 4.5px; } + .monaco-editor .dirty-diff-modified, .monaco-editor .dirty-diff-added{border-left-width:${state.width}px;} .monaco-editor .dirty-diff-modified, .monaco-editor .dirty-diff-added, .monaco-editor .dirty-diff-deleted { opacity: ${state.visibility === 'always' ? 1 : 0}; } @@ -1474,7 +1475,6 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) = if (editorGutterModifiedBackgroundColor) { collector.addRule(` .monaco-editor .dirty-diff-modified { - background-size: 3px 4.5px; background-repeat-x: no-repeat; background-image: linear-gradient(${linearGradient}); transition: opacity 0.5s; From 5467c8c4413be3a69960fe418d2c345bfbdf2b55 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Sun, 3 Apr 2022 20:52:45 -0700 Subject: [PATCH 023/135] Typo --- src/vs/platform/theme/common/colorRegistry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index a75435972fc..caf8e6786d8 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -289,7 +289,7 @@ export const editorErrorForeground = registerColor('editorError.foreground', { d export const editorErrorBorder = registerColor('editorError.border', { dark: null, light: null, hcDark: Color.fromHex('#E47777').transparent(0.8), hcLight: '#B5200D' }, nls.localize('errorBorder', 'Border color of error boxes in the editor.')); export const editorWarningBackground = registerColor('editorWarning.background', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('editorWarning.background', 'Background color of warning text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true); -export const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#CCA700', light: '#BF8803', hcDark: '#FFD3700', hcLight: '#895503' }, nls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.')); +export const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#CCA700', light: '#BF8803', hcDark: '#FFD37', hcLight: '#895503' }, nls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.')); export const editorWarningBorder = registerColor('editorWarning.border', { dark: null, light: null, hcDark: Color.fromHex('#FFCC00').transparent(0.8), hcLight: '#' }, nls.localize('warningBorder', 'Border color of warning boxes in the editor.')); export const editorInfoBackground = registerColor('editorInfo.background', { dark: null, light: null, hcDark: null, hcLight: null }, nls.localize('editorInfo.background', 'Background color of info text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true); From e8aefb5a41859bf86f2d36e3616b9086cb8b9b46 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 4 Apr 2022 11:52:02 +0530 Subject: [PATCH 024/135] #146027 self register services --- .../browser/userDataSyncEnablementService.ts | 45 +--------------- .../webUserDataSyncEnablementService.ts | 54 +++++++++++++++++++ src/vs/workbench/workbench.sandbox.main.ts | 4 +- src/vs/workbench/workbench.web.main.ts | 5 +- 4 files changed, 59 insertions(+), 49 deletions(-) create mode 100644 src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts index bfc01daa46e..8c815116f35 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IUserDataSyncEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncEnablementService as BaseUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSyncEnablementService'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -17,46 +18,4 @@ export class UserDataSyncEnablementService extends BaseUserDataSyncEnablementSer } -export class WebUserDataSyncEnablementService extends UserDataSyncEnablementService implements IUserDataSyncEnablementService { - - private enabled: boolean | undefined = undefined; - - override canToggleEnablement(): boolean { - return this.isTrusted() && super.canToggleEnablement(); - } - - override isEnabled(): boolean { - if (!this.isTrusted()) { - return false; - } - if (this.enabled === undefined) { - this.enabled = this.workbenchEnvironmentService.options?.settingsSyncOptions?.enabled; - } - if (this.enabled === undefined) { - this.enabled = super.isEnabled(); - } - return this.enabled; - } - - override setEnablement(enabled: boolean) { - if (enabled && !this.canToggleEnablement()) { - return; - } - if (this.enabled !== enabled) { - this.enabled = enabled; - super.setEnablement(enabled); - if (this.workbenchEnvironmentService.options?.settingsSyncOptions?.enablementHandler) { - this.workbenchEnvironmentService.options.settingsSyncOptions.enablementHandler(this.enabled); - } - } - } - - override getResourceSyncStateVersion(resource: SyncResource): string | undefined { - return resource === SyncResource.Extensions ? this.workbenchEnvironmentService.options?.settingsSyncOptions?.extensionsSyncStateVersion : undefined; - } - - private isTrusted(): boolean { - return !!this.workbenchEnvironmentService.options?.workspaceProvider?.trusted; - } - -} +registerSingleton(IUserDataSyncEnablementService, UserDataSyncEnablementService); diff --git a/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts b/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts new file mode 100644 index 00000000000..1224476ffdc --- /dev/null +++ b/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IUserDataSyncEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncEnablementService } from 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService'; + +export class WebUserDataSyncEnablementService extends UserDataSyncEnablementService implements IUserDataSyncEnablementService { + + private enabled: boolean | undefined = undefined; + + override canToggleEnablement(): boolean { + return this.isTrusted() && super.canToggleEnablement(); + } + + override isEnabled(): boolean { + if (!this.isTrusted()) { + return false; + } + if (this.enabled === undefined) { + this.enabled = this.workbenchEnvironmentService.options?.settingsSyncOptions?.enabled; + } + if (this.enabled === undefined) { + this.enabled = super.isEnabled(); + } + return this.enabled; + } + + override setEnablement(enabled: boolean) { + if (enabled && !this.canToggleEnablement()) { + return; + } + if (this.enabled !== enabled) { + this.enabled = enabled; + super.setEnablement(enabled); + if (this.workbenchEnvironmentService.options?.settingsSyncOptions?.enablementHandler) { + this.workbenchEnvironmentService.options.settingsSyncOptions.enablementHandler(this.enabled); + } + } + } + + override getResourceSyncStateVersion(resource: SyncResource): string | undefined { + return resource === SyncResource.Extensions ? this.workbenchEnvironmentService.options?.settingsSyncOptions?.extensionsSyncStateVersion : undefined; + } + + private isTrusted(): boolean { + return !!this.workbenchEnvironmentService.options?.workspaceProvider?.trusted; + } + +} + +registerSingleton(IUserDataSyncEnablementService, WebUserDataSyncEnablementService); diff --git a/src/vs/workbench/workbench.sandbox.main.ts b/src/vs/workbench/workbench.sandbox.main.ts index 2150dd3f14b..87f933f5fe0 100644 --- a/src/vs/workbench/workbench.sandbox.main.ts +++ b/src/vs/workbench/workbench.sandbox.main.ts @@ -81,14 +81,12 @@ import 'vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService'; import 'vs/workbench/services/files/electron-sandbox/elevatedFileService'; import 'vs/workbench/services/search/electron-sandbox/searchService'; import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService'; +import 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit'; -import { IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; -import { UserDataSyncEnablementService } from 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService'; registerSingleton(IUserDataInitializationService, UserDataInitializationService); -registerSingleton(IUserDataSyncEnablementService, UserDataSyncEnablementService); //#endregion diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index cb8ee5c4ce7..8f3d9020fd0 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -60,6 +60,7 @@ import 'vs/workbench/services/workingCopy/browser/workingCopyBackupService'; import 'vs/workbench/services/tunnel/browser/tunnelService'; import 'vs/workbench/services/files/browser/elevatedFileService'; import 'vs/workbench/services/workingCopy/browser/workingCopyHistoryService'; +import 'vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -72,7 +73,7 @@ import { ExtensionManagementService } from 'vs/workbench/services/extensionManag import { ILoggerService, LogLevel } from 'vs/platform/log/common/log'; import { FileLoggerService } from 'vs/platform/log/common/fileLog'; import { UserDataSyncMachinesService, IUserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines'; -import { IUserDataSyncStoreService, IUserDataSyncService, IUserDataAutoSyncService, IUserDataSyncBackupStoreService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncStoreService, IUserDataSyncService, IUserDataAutoSyncService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { UserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSyncBackupStoreService'; import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; @@ -87,9 +88,7 @@ import { ITimerService, TimerService } from 'vs/workbench/services/timer/browser import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { IDiagnosticsService, NullDiagnosticsService } from 'vs/platform/diagnostics/common/diagnostics'; -import { WebUserDataSyncEnablementService } from 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService'; -registerSingleton(IUserDataSyncEnablementService, WebUserDataSyncEnablementService); registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService); registerSingleton(IAccessibilityService, AccessibilityService, true); registerSingleton(IContextMenuService, ContextMenuService); From 0bc095362ea6a2227164e9bacdb8a0ea180af0fa Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 4 Apr 2022 09:53:22 +0200 Subject: [PATCH 025/135] Fix #146465 --- src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index 8452bba60ca..600b2af4b21 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -1475,7 +1475,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) = if (editorGutterModifiedBackgroundColor) { collector.addRule(` .monaco-editor .dirty-diff-modified { - background-repeat-x: no-repeat; + background-repeat: repeat-y; background-image: linear-gradient(${linearGradient}); transition: opacity 0.5s; } From 2ada17080cd3e351e093e5fce40d36f16db3124a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 10:13:08 +0200 Subject: [PATCH 026/135] Use `playwright` for desktop smoke tests (#146692) * Use `playwright` for desktop smoke tests * fix distro issues * tests - enable prefs tests for web --- .../darwin/product-build-darwin.yml | 6 +- .../linux/product-build-linux-client.yml | 6 +- .../win32/product-build-win32.yml | 6 +- src/vs/code/electron-main/app.ts | 2 +- src/vs/platform/driver/browser/baseDriver.ts | 205 ----------------- src/vs/platform/driver/browser/driver.ts | 211 +++++++++++++++++- src/vs/platform/driver/common/driver.ts | 10 +- src/vs/platform/driver/common/driverIpc.ts | 9 +- .../platform/driver/electron-main/driver.ts | 21 +- .../driver/electron-sandbox/driver.ts | 48 ++-- src/vs/platform/driver/node/driver.ts | 7 +- src/vs/platform/environment/common/argv.ts | 5 +- .../electron-main/environmentMainService.ts | 4 - src/vs/platform/environment/node/argv.ts | 2 +- src/vs/workbench/browser/window.ts | 14 +- .../electron-sandbox/desktop.main.ts | 6 - src/vs/workbench/electron-sandbox/window.ts | 24 ++ test/automation/src/application.ts | 10 +- test/automation/src/code.ts | 47 ++-- test/automation/src/driver.js | 8 +- test/automation/src/electronDriver.ts | 107 +++++---- test/automation/src/index.ts | 1 + ...htDriver.ts => playwrightBrowserDriver.ts} | 126 ++++++----- .../src/playwrightElectronDriver.ts | 61 +++++ .../tools/copy-driver-definition.js | 3 + test/automation/tools/copy-package-version.js | 3 + test/integration/browser/src/index.ts | 2 +- test/integration/electron/testrunner.js | 3 + .../src/areas/statusbar/statusbar.test.ts | 2 +- .../src/areas/workbench/data-loss.test.ts | 2 +- test/smoke/src/main.ts | 91 +++----- test/smoke/test/index.js | 18 +- test/unit/browser/index.js | 1 + test/unit/node/index.js | 1 + 34 files changed, 593 insertions(+), 479 deletions(-) delete mode 100644 src/vs/platform/driver/browser/baseDriver.ts rename test/automation/src/{playwrightDriver.ts => playwrightBrowserDriver.ts} (76%) create mode 100644 test/automation/src/playwrightElectronDriver.ts diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 6f4e8661cb2..1c529a95362 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -236,7 +236,7 @@ steps: - script: | set -e VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --web --headless + yarn smoketest-no-compile --web --tracing --headless timeoutInMinutes: 10 displayName: Run smoke tests (Browser, Chromium) condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) @@ -245,7 +245,7 @@ steps: set -e APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) APP_NAME="`ls $APP_ROOT | head -n 1`" - yarn smoketest-no-compile --build "$APP_ROOT/$APP_NAME" + yarn smoketest-no-compile --tracing --build "$APP_ROOT/$APP_NAME" # Increased timeout because this test downloads stable code timeoutInMinutes: 20 displayName: Run smoke tests (Electron) @@ -256,7 +256,7 @@ steps: APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) APP_NAME="`ls $APP_ROOT | head -n 1`" VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --build "$APP_ROOT/$APP_NAME" --remote + yarn smoketest-no-compile --tracing --remote --build "$APP_ROOT/$APP_NAME" timeoutInMinutes: 10 displayName: Run smoke tests (Remote) condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 35aad220604..5f15732ad85 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -259,7 +259,7 @@ steps: - script: | set -e VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --web --headless --electronArgs="--disable-dev-shm-usage" + yarn smoketest-no-compile --web --tracing --headless --electronArgs="--disable-dev-shm-usage" timeoutInMinutes: 10 displayName: Run smoke tests (Browser, Chromium) condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) @@ -267,7 +267,7 @@ steps: - script: | set -e APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - yarn smoketest-no-compile --build "$APP_PATH" --electronArgs="--disable-dev-shm-usage" + yarn smoketest-no-compile --tracing --build "$APP_PATH" # Increased timeout because this test downloads stable code timeoutInMinutes: 20 displayName: Run smoke tests (Electron) @@ -277,7 +277,7 @@ steps: set -e APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ - yarn smoketest-no-compile --build "$APP_PATH" --remote --electronArgs="--disable-dev-shm-usage" + yarn smoketest-no-compile --tracing --remote --build "$APP_PATH" timeoutInMinutes: 10 displayName: Run smoke tests (Remote) condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 001ce407218..cd18ffe4c7a 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -220,7 +220,7 @@ steps: . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)" - exec { yarn smoketest-no-compile --web --headless } + exec { yarn smoketest-no-compile --web --tracing --headless } displayName: Run smoke tests (Browser, Chromium) timeoutInMinutes: 10 condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) @@ -229,7 +229,7 @@ steps: . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - exec { yarn smoketest-no-compile --build "$AppRoot" } + exec { yarn smoketest-no-compile --tracing --build "$AppRoot" } displayName: Run smoke tests (Electron) # Increased timeout because this test downloads stable code timeoutInMinutes: 20 @@ -240,7 +240,7 @@ steps: $ErrorActionPreference = "Stop" $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)" - exec { yarn smoketest-no-compile --build "$AppRoot" --remote } + exec { yarn smoketest-no-compile --tracing --remote --build "$AppRoot" } displayName: Run smoke tests (Remote) timeoutInMinutes: 10 condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index d7459f90ea6..5d6b367dca0 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -524,7 +524,7 @@ export class CodeApplication extends Disposable { // Create driver if (this.environmentMainService.driverHandle) { - const server = await serveDriver(mainProcessElectronServer, this.environmentMainService.driverHandle, this.environmentMainService, appInstantiationService); + const server = await serveDriver(mainProcessElectronServer, this.environmentMainService.driverHandle, appInstantiationService); this.logService.info('Driver started at:', this.environmentMainService.driverHandle); this._register(server); diff --git a/src/vs/platform/driver/browser/baseDriver.ts b/src/vs/platform/driver/browser/baseDriver.ts deleted file mode 100644 index 9875672768a..00000000000 --- a/src/vs/platform/driver/browser/baseDriver.ts +++ /dev/null @@ -1,205 +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 { getClientArea, getTopLeftOffset } from 'vs/base/browser/dom'; -import { coalesce } from 'vs/base/common/arrays'; -import { language, locale } from 'vs/base/common/platform'; -import { IElement, ILocaleInfo, ILocalizedStrings, IWindowDriver } from 'vs/platform/driver/common/driver'; -import localizedStrings from 'vs/platform/localizations/common/localizedStrings'; - -export abstract class BaseWindowDriver implements IWindowDriver { - - abstract click(selector: string, xoffset?: number, yoffset?: number): Promise; - abstract doubleClick(selector: string): Promise; - - async setValue(selector: string, text: string): Promise { - const element = document.querySelector(selector); - - if (!element) { - return Promise.reject(new Error(`Element not found: ${selector}`)); - } - - const inputElement = element as HTMLInputElement; - inputElement.value = text; - - const event = new Event('input', { bubbles: true, cancelable: true }); - inputElement.dispatchEvent(event); - } - - async getTitle(): Promise { - return document.title; - } - - async isActiveElement(selector: string): Promise { - const element = document.querySelector(selector); - - if (element !== document.activeElement) { - const chain: string[] = []; - let el = document.activeElement; - - while (el) { - const tagName = el.tagName; - const id = el.id ? `#${el.id}` : ''; - const classes = coalesce(el.className.split(/\s+/g).map(c => c.trim())).map(c => `.${c}`).join(''); - chain.unshift(`${tagName}${id}${classes}`); - - el = el.parentElement; - } - - throw new Error(`Active element not found. Current active element is '${chain.join(' > ')}'. Looking for ${selector}`); - } - - return true; - } - - async getElements(selector: string, recursive: boolean): Promise { - const query = document.querySelectorAll(selector); - const result: IElement[] = []; - for (let i = 0; i < query.length; i++) { - const element = query.item(i); - result.push(this.serializeElement(element, recursive)); - } - - return result; - } - - private serializeElement(element: Element, recursive: boolean): IElement { - const attributes = Object.create(null); - - for (let j = 0; j < element.attributes.length; j++) { - const attr = element.attributes.item(j); - if (attr) { - attributes[attr.name] = attr.value; - } - } - - const children: IElement[] = []; - - if (recursive) { - for (let i = 0; i < element.children.length; i++) { - const child = element.children.item(i); - if (child) { - children.push(this.serializeElement(child, true)); - } - } - } - - const { left, top } = getTopLeftOffset(element as HTMLElement); - - return { - tagName: element.tagName, - className: element.className, - textContent: element.textContent || '', - attributes, - children, - left, - top - }; - } - - async getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number }> { - const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined; - return this._getElementXY(selector, offset); - } - - async typeInEditor(selector: string, text: string): Promise { - const element = document.querySelector(selector); - - if (!element) { - throw new Error(`Editor not found: ${selector}`); - } - - const textarea = element as HTMLTextAreaElement; - const start = textarea.selectionStart; - const newStart = start + text.length; - const value = textarea.value; - const newValue = value.substr(0, start) + text + value.substr(start); - - textarea.value = newValue; - textarea.setSelectionRange(newStart, newStart); - - const event = new Event('input', { 'bubbles': true, 'cancelable': true }); - textarea.dispatchEvent(event); - } - - async getTerminalBuffer(selector: string): Promise { - const element = document.querySelector(selector); - - if (!element) { - throw new Error(`Terminal not found: ${selector}`); - } - - const xterm = (element as any).xterm; - - if (!xterm) { - throw new Error(`Xterm not found: ${selector}`); - } - - const lines: string[] = []; - for (let i = 0; i < xterm.buffer.active.length; i++) { - lines.push(xterm.buffer.active.getLine(i)!.translateToString(true)); - } - - return lines; - } - - async writeInTerminal(selector: string, text: string): Promise { - const element = document.querySelector(selector); - - if (!element) { - throw new Error(`Element not found: ${selector}`); - } - - const xterm = (element as any).xterm; - - if (!xterm) { - throw new Error(`Xterm not found: ${selector}`); - } - - xterm._core.coreService.triggerDataEvent(text); - } - - getLocaleInfo(): Promise { - return Promise.resolve({ - language: language, - locale: locale - }); - } - - getLocalizedStrings(): Promise { - return Promise.resolve({ - open: localizedStrings.open, - close: localizedStrings.close, - find: localizedStrings.find - }); - } - - protected async _getElementXY(selector: string, offset?: { x: number; y: number }): Promise<{ x: number; y: number }> { - const element = document.querySelector(selector); - - if (!element) { - return Promise.reject(new Error(`Element not found: ${selector}`)); - } - - const { left, top } = getTopLeftOffset(element as HTMLElement); - const { width, height } = getClientArea(element as HTMLElement); - let x: number, y: number; - - if (offset) { - x = left + offset.x; - y = top + offset.y; - } else { - x = left + (width / 2); - y = top + (height / 2); - } - - x = Math.round(x); - y = Math.round(y); - - return { x, y }; - } - - abstract openDevTools(): Promise; -} diff --git a/src/vs/platform/driver/browser/driver.ts b/src/vs/platform/driver/browser/driver.ts index 7027a0d37b6..c57855c3828 100644 --- a/src/vs/platform/driver/browser/driver.ts +++ b/src/vs/platform/driver/browser/driver.ts @@ -3,23 +3,210 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { BaseWindowDriver } from 'vs/platform/driver/browser/baseDriver'; +import { getClientArea, getTopLeftOffset } from 'vs/base/browser/dom'; +import { coalesce } from 'vs/base/common/arrays'; +import { language, locale } from 'vs/base/common/platform'; +import { IElement, ILocaleInfo, ILocalizedStrings, IWindowDriver } from 'vs/platform/driver/common/driver'; +import localizedStrings from 'vs/platform/localizations/common/localizedStrings'; -class BrowserWindowDriver extends BaseWindowDriver { - click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise { - throw new Error('Method not implemented.'); +export class BrowserWindowDriver implements IWindowDriver { + + async setValue(selector: string, text: string): Promise { + const element = document.querySelector(selector); + + if (!element) { + return Promise.reject(new Error(`Element not found: ${selector}`)); + } + + const inputElement = element as HTMLInputElement; + inputElement.value = text; + + const event = new Event('input', { bubbles: true, cancelable: true }); + inputElement.dispatchEvent(event); } - doubleClick(selector: string): Promise { - throw new Error('Method not implemented.'); + + async getTitle(): Promise { + return document.title; } - openDevTools(): Promise { + + async isActiveElement(selector: string): Promise { + const element = document.querySelector(selector); + + if (element !== document.activeElement) { + const chain: string[] = []; + let el = document.activeElement; + + while (el) { + const tagName = el.tagName; + const id = el.id ? `#${el.id}` : ''; + const classes = coalesce(el.className.split(/\s+/g).map(c => c.trim())).map(c => `.${c}`).join(''); + chain.unshift(`${tagName}${id}${classes}`); + + el = el.parentElement; + } + + throw new Error(`Active element not found. Current active element is '${chain.join(' > ')}'. Looking for ${selector}`); + } + + return true; + } + + async getElements(selector: string, recursive: boolean): Promise { + const query = document.querySelectorAll(selector); + const result: IElement[] = []; + for (let i = 0; i < query.length; i++) { + const element = query.item(i); + result.push(this.serializeElement(element, recursive)); + } + + return result; + } + + private serializeElement(element: Element, recursive: boolean): IElement { + const attributes = Object.create(null); + + for (let j = 0; j < element.attributes.length; j++) { + const attr = element.attributes.item(j); + if (attr) { + attributes[attr.name] = attr.value; + } + } + + const children: IElement[] = []; + + if (recursive) { + for (let i = 0; i < element.children.length; i++) { + const child = element.children.item(i); + if (child) { + children.push(this.serializeElement(child, true)); + } + } + } + + const { left, top } = getTopLeftOffset(element as HTMLElement); + + return { + tagName: element.tagName, + className: element.className, + textContent: element.textContent || '', + attributes, + children, + left, + top + }; + } + + async getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number }> { + const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined; + return this._getElementXY(selector, offset); + } + + async typeInEditor(selector: string, text: string): Promise { + const element = document.querySelector(selector); + + if (!element) { + throw new Error(`Editor not found: ${selector}`); + } + + const textarea = element as HTMLTextAreaElement; + const start = textarea.selectionStart; + const newStart = start + text.length; + const value = textarea.value; + const newValue = value.substr(0, start) + text + value.substr(start); + + textarea.value = newValue; + textarea.setSelectionRange(newStart, newStart); + + const event = new Event('input', { 'bubbles': true, 'cancelable': true }); + textarea.dispatchEvent(event); + } + + async getTerminalBuffer(selector: string): Promise { + const element = document.querySelector(selector); + + if (!element) { + throw new Error(`Terminal not found: ${selector}`); + } + + const xterm = (element as any).xterm; + + if (!xterm) { + throw new Error(`Xterm not found: ${selector}`); + } + + const lines: string[] = []; + for (let i = 0; i < xterm.buffer.active.length; i++) { + lines.push(xterm.buffer.active.getLine(i)!.translateToString(true)); + } + + return lines; + } + + async writeInTerminal(selector: string, text: string): Promise { + const element = document.querySelector(selector); + + if (!element) { + throw new Error(`Element not found: ${selector}`); + } + + const xterm = (element as any).xterm; + + if (!xterm) { + throw new Error(`Xterm not found: ${selector}`); + } + + xterm._core.coreService.triggerDataEvent(text); + } + + getLocaleInfo(): Promise { + return Promise.resolve({ + language: language, + locale: locale + }); + } + + getLocalizedStrings(): Promise { + return Promise.resolve({ + open: localizedStrings.open, + close: localizedStrings.close, + find: localizedStrings.find + }); + } + + protected async _getElementXY(selector: string, offset?: { x: number; y: number }): Promise<{ x: number; y: number }> { + const element = document.querySelector(selector); + + if (!element) { + return Promise.reject(new Error(`Element not found: ${selector}`)); + } + + const { left, top } = getTopLeftOffset(element as HTMLElement); + const { width, height } = getClientArea(element as HTMLElement); + let x: number, y: number; + + if (offset) { + x = left + offset.x; + y = top + offset.y; + } else { + x = left + (width / 2); + y = top + (height / 2); + } + + x = Math.round(x); + y = Math.round(y); + + return { x, y }; + } + + click(selector: string, xoffset?: number, yoffset?: number): Promise { + + // This is actually not used in the playwright drivers + // that can implement `click` natively via the driver + throw new Error('Method not implemented.'); } } -export async function registerWindowDriver(): Promise { - (window).driver = new BrowserWindowDriver(); - - return Disposable.None; +export function registerWindowDriver(): void { + Object.assign(window, { driver: new BrowserWindowDriver() }); } diff --git a/src/vs/platform/driver/common/driver.ts b/src/vs/platform/driver/common/driver.ts index ca36bc4409b..6d23ce9748c 100644 --- a/src/vs/platform/driver/common/driver.ts +++ b/src/vs/platform/driver/common/driver.ts @@ -44,10 +44,9 @@ export interface IDriver { startTracing(windowId: number, name: string): Promise; stopTracing(windowId: number, name: string, persist: boolean): Promise; reloadWindow(windowId: number): Promise; - exitApplication(): Promise; + exitApplication(): Promise; dispatchKeybinding(windowId: number, keybinding: string): Promise; click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise; - doubleClick(windowId: number, selector: string): Promise; setValue(windowId: number, selector: string, text: string): Promise; getTitle(windowId: number): Promise; isActiveElement(windowId: number, selector: string): Promise; @@ -62,7 +61,6 @@ export interface IDriver { export interface IWindowDriver { click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise; - doubleClick(selector: string): Promise; setValue(selector: string, text: string): Promise; getTitle(): Promise; isActiveElement(selector: string): Promise; @@ -79,11 +77,7 @@ export interface IWindowDriver { export const ID = 'driverService'; export const IDriver = createDecorator(ID); -export interface IDriverOptions { - verbose: boolean; -} - export interface IWindowDriverRegistry { - registerWindowDriver(windowId: number): Promise; + registerWindowDriver(windowId: number): Promise; reloadWindowDriver(windowId: number): Promise; } diff --git a/src/vs/platform/driver/common/driverIpc.ts b/src/vs/platform/driver/common/driverIpc.ts index 49593c75882..6d5ed5e55c4 100644 --- a/src/vs/platform/driver/common/driverIpc.ts +++ b/src/vs/platform/driver/common/driverIpc.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IDriverOptions, IElement, ILocaleInfo, ILocalizedStrings as ILocalizedStrings, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; +import { IElement, ILocaleInfo, ILocalizedStrings as ILocalizedStrings, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; export class WindowDriverChannel implements IServerChannel { @@ -18,7 +18,6 @@ export class WindowDriverChannel implements IServerChannel { call(_: unknown, command: string, arg?: any): Promise { switch (command) { case 'click': return this.driver.click(arg[0], arg[1], arg[2]); - case 'doubleClick': return this.driver.doubleClick(arg); case 'setValue': return this.driver.setValue(arg[0], arg[1]); case 'getTitle': return this.driver.getTitle(); case 'isActiveElement': return this.driver.isActiveElement(arg); @@ -45,10 +44,6 @@ export class WindowDriverChannelClient implements IWindowDriver { return this.channel.call('click', [selector, xoffset, yoffset]); } - doubleClick(selector: string): Promise { - return this.channel.call('doubleClick', selector); - } - setValue(selector: string, text: string): Promise { return this.channel.call('setValue', [selector, text]); } @@ -96,7 +91,7 @@ export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry constructor(private channel: IChannel) { } - registerWindowDriver(windowId: number): Promise { + registerWindowDriver(windowId: number): Promise { return this.channel.call('registerWindowDriver', windowId); } diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index aa1e5f6ee79..f14f14e40ad 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -12,7 +12,7 @@ import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { OS } from 'vs/base/common/platform'; import { IPCServer, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import { serve as serveNet } from 'vs/base/parts/ipc/node/ipc.net'; -import { IDriver, IDriverOptions, IElement, ILocaleInfo, ILocalizedStrings, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; +import { IDriver, IElement, ILocaleInfo, ILocalizedStrings, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; import { WindowDriverChannelClient } from 'vs/platform/driver/common/driverIpc'; import { DriverChannel, WindowDriverRegistryChannel } from 'vs/platform/driver/node/driver'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; @@ -40,7 +40,6 @@ export class Driver implements IDriver, IWindowDriverRegistry { constructor( private windowServer: IPCServer, - private options: IDriverOptions, @IWindowsMainService private readonly windowsMainService: IWindowsMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IFileService private readonly fileService: IFileService, @@ -48,13 +47,12 @@ export class Driver implements IDriver, IWindowDriverRegistry { @ILogService private readonly logService: ILogService ) { } - async registerWindowDriver(windowId: number): Promise { + async registerWindowDriver(windowId: number): Promise { this.logService.info(`[driver] registerWindowDriver(${windowId})`); this.registeredWindowIds.add(windowId); this.reloadingWindowIds.delete(windowId); this.onDidReloadingChange.fire(); - return this.options; } async reloadWindowDriver(windowId: number): Promise { @@ -111,10 +109,12 @@ export class Driver implements IDriver, IWindowDriverRegistry { this.lifecycleMainService.reload(window); } - exitApplication(): Promise { + async exitApplication(): Promise { this.logService.info(`[driver] exitApplication()`); - return this.lifecycleMainService.quit(); + this.lifecycleMainService.quit(); + + return process.pid; } async dispatchKeybinding(windowId: number, keybinding: string): Promise { @@ -175,11 +175,6 @@ export class Driver implements IDriver, IWindowDriverRegistry { await windowDriver.click(selector, xoffset, yoffset); } - async doubleClick(windowId: number, selector: string): Promise { - const windowDriver = await this.getWindowDriver(windowId); - await windowDriver.doubleClick(selector); - } - async setValue(windowId: number, selector: string, text: string): Promise { const windowDriver = await this.getWindowDriver(windowId); await windowDriver.setValue(selector, text); @@ -249,11 +244,9 @@ export class Driver implements IDriver, IWindowDriverRegistry { export async function serve( windowServer: IPCServer, handle: string, - environmentMainService: IEnvironmentMainService, instantiationService: IInstantiationService ): Promise { - const verbose = environmentMainService.driverVerbose; - const driver = instantiationService.createInstance(Driver, windowServer, { verbose }); + const driver = instantiationService.createInstance(Driver, windowServer); const windowDriverRegistryChannel = new WindowDriverRegistryChannel(driver); windowServer.registerChannel('windowDriverRegistry', windowDriverRegistryChannel); diff --git a/src/vs/platform/driver/electron-sandbox/driver.ts b/src/vs/platform/driver/electron-sandbox/driver.ts index 84bc965bd9b..bc2e4c9ae38 100644 --- a/src/vs/platform/driver/electron-sandbox/driver.ts +++ b/src/vs/platform/driver/electron-sandbox/driver.ts @@ -5,13 +5,32 @@ import { timeout } from 'vs/base/common/async'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { BaseWindowDriver } from 'vs/platform/driver/browser/baseDriver'; +import { BrowserWindowDriver } from 'vs/platform/driver/browser/driver'; import { WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platform/driver/common/driverIpc'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -class WindowDriver extends BaseWindowDriver { +interface INativeWindowDriverHelper { + exitApplication(): Promise; +} + +class NativeWindowDriver extends BrowserWindowDriver { + + constructor(private readonly helper: INativeWindowDriverHelper) { + super(); + } + + exitApplication(): Promise { + return this.helper.exitApplication(); + } +} + +export function registerWindowDriver(helper: INativeWindowDriverHelper): void { + Object.assign(window, { driver: new NativeWindowDriver(helper) }); +} + +class LegacyNativeWindowDriver extends BrowserWindowDriver { constructor( @INativeHostService private readonly nativeHostService: INativeHostService @@ -19,16 +38,13 @@ class WindowDriver extends BaseWindowDriver { super(); } - click(selector: string, xoffset?: number, yoffset?: number): Promise { + override click(selector: string, xoffset?: number, yoffset?: number): Promise { const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined; - return this._click(selector, 1, offset); + + return this.doClick(selector, 1, offset); } - doubleClick(selector: string): Promise { - return this._click(selector, 2); - } - - private async _click(selector: string, clickCount: number, offset?: { x: number; y: number }): Promise { + private async doClick(selector: string, clickCount: number, offset?: { x: number; y: number }): Promise { const { x, y } = await this._getElementXY(selector, offset); await this.nativeHostService.sendInputEvent({ type: 'mouseDown', x, y, button: 'left', clickCount } as any); @@ -37,17 +53,19 @@ class WindowDriver extends BaseWindowDriver { await this.nativeHostService.sendInputEvent({ type: 'mouseUp', x, y, button: 'left', clickCount } as any); await timeout(100); } - - async openDevTools(): Promise { - await this.nativeHostService.openDevTools({ mode: 'detach' }); - } } -export async function registerWindowDriver(accessor: ServicesAccessor, windowId: number): Promise { +/** + * Old school window driver that is implemented by us + * from the main process. + * + * @deprecated + */ +export async function registerLegacyWindowDriver(accessor: ServicesAccessor, windowId: number): Promise { const instantiationService = accessor.get(IInstantiationService); const mainProcessService = accessor.get(IMainProcessService); - const windowDriver = instantiationService.createInstance(WindowDriver); + const windowDriver = instantiationService.createInstance(LegacyNativeWindowDriver); const windowDriverChannel = new WindowDriverChannel(windowDriver); mainProcessService.registerChannel('windowDriver', windowDriverChannel); diff --git a/src/vs/platform/driver/node/driver.ts b/src/vs/platform/driver/node/driver.ts index 4e56bc540e4..29abf734bec 100644 --- a/src/vs/platform/driver/node/driver.ts +++ b/src/vs/platform/driver/node/driver.ts @@ -27,7 +27,6 @@ export class DriverChannel implements IServerChannel { case 'exitApplication': return this.driver.exitApplication(); case 'dispatchKeybinding': return this.driver.dispatchKeybinding(arg[0], arg[1]); case 'click': return this.driver.click(arg[0], arg[1], arg[2], arg[3]); - case 'doubleClick': return this.driver.doubleClick(arg[0], arg[1]); case 'setValue': return this.driver.setValue(arg[0], arg[1], arg[2]); case 'getTitle': return this.driver.getTitle(arg[0]); case 'isActiveElement': return this.driver.isActiveElement(arg[0], arg[1]); @@ -70,7 +69,7 @@ export class DriverChannelClient implements IDriver { return this.channel.call('reloadWindow', windowId); } - exitApplication(): Promise { + exitApplication(): Promise { return this.channel.call('exitApplication'); } @@ -82,10 +81,6 @@ export class DriverChannelClient implements IDriver { return this.channel.call('click', [windowId, selector, xoffset, yoffset]); } - doubleClick(windowId: number, selector: string): Promise { - return this.channel.call('doubleClick', [windowId, selector]); - } - setValue(windowId: number, selector: string, text: string): Promise { return this.channel.call('setValue', [windowId, selector, text]); } diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts index 4815b4a2888..ccac10545b5 100644 --- a/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -79,8 +79,11 @@ export interface NativeParsedArgs { 'max-memory'?: string; 'file-write'?: boolean; 'file-chmod'?: boolean; + /** + * @deprecated use `enable-smoke-test-driver` + */ 'driver'?: string; - 'driver-verbose'?: boolean; + 'enable-smoke-test-driver'?: boolean; 'remote'?: string; 'force'?: boolean; 'do-not-sync'?: boolean; diff --git a/src/vs/platform/environment/electron-main/environmentMainService.ts b/src/vs/platform/environment/electron-main/environmentMainService.ts index beb1896fa2b..6834b8115fe 100644 --- a/src/vs/platform/environment/electron-main/environmentMainService.ts +++ b/src/vs/platform/environment/electron-main/environmentMainService.ts @@ -35,7 +35,6 @@ export interface IEnvironmentMainService extends INativeEnvironmentService { // --- config sandbox: boolean; - driverVerbose: boolean; disableUpdates: boolean; } @@ -59,9 +58,6 @@ export class EnvironmentMainService extends NativeEnvironmentService implements @memoize get sandbox(): boolean { return !!this.args['__sandbox']; } - @memoize - get driverVerbose(): boolean { return !!this.args['driver-verbose']; } - @memoize get disableUpdates(): boolean { return !!this.args['disable-updates']; } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index c671917d1a4..1d7aadc1f14 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -99,6 +99,7 @@ export const OPTIONS: OptionDescriptions> = { 'export-default-configuration': { type: 'string' }, 'install-source': { type: 'string' }, 'driver': { type: 'string' }, + 'enable-smoke-test-driver': { type: 'boolean' }, 'logExtensionHostCommunication': { type: 'boolean' }, 'skip-release-notes': { type: 'boolean' }, 'skip-welcome': { type: 'boolean' }, @@ -114,7 +115,6 @@ export const OPTIONS: OptionDescriptions> = { 'open-url': { type: 'boolean' }, 'file-write': { type: 'boolean' }, 'file-chmod': { type: 'boolean' }, - 'driver-verbose': { type: 'boolean' }, 'install-builtin-extension': { type: 'string[]' }, 'force': { type: 'boolean' }, 'do-not-sync': { type: 'boolean' }, diff --git a/src/vs/workbench/browser/window.ts b/src/vs/workbench/browser/window.ts index cbcbac8602c..5e94ea2bba1 100644 --- a/src/vs/workbench/browser/window.ts +++ b/src/vs/workbench/browser/window.ts @@ -112,16 +112,20 @@ export class BrowserWindow extends Disposable { private create(): void { - // Driver - if (this.environmentService.options?.developmentOptions?.enableSmokeTestDriver) { - (async () => this._register(await registerWindowDriver()))(); - } - // Handle open calls this.setupOpenHandlers(); // Label formatting this.registerLabelFormatters(); + + // Smoke Test Driver + this.setupDriver(); + } + + private setupDriver(): void { + if (this.environmentService.options?.developmentOptions?.enableSmokeTestDriver) { + registerWindowDriver(); + } } private setupOpenHandlers(): void { diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index e4c63f35ce9..6a78e65d27c 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -43,7 +43,6 @@ import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { NativeLogService } from 'vs/workbench/services/log/electron-sandbox/logService'; import { WorkspaceTrustEnablementService, WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust'; import { IWorkspaceTrustEnablementService, IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; -import { registerWindowDriver } from 'vs/platform/driver/electron-sandbox/driver'; import { safeStringify } from 'vs/base/common/objects'; import { ISharedProcessWorkerWorkbenchService, SharedProcessWorkerWorkbenchService } from 'vs/workbench/services/sharedProcess/electron-sandbox/sharedProcessWorkerWorkbenchService'; import { isCI, isMacintosh } from 'vs/base/common/platform'; @@ -115,11 +114,6 @@ export class DesktopMain extends Disposable { // Window this._register(instantiationService.createInstance(NativeWindow)); - - // Driver - if (this.configuration.driver) { - instantiationService.invokeFunction(async accessor => this._register(await registerWindowDriver(accessor, this.configuration.windowId))); - } } private getExtraClasses(): string[] { diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 816fe88f29e..389c1218e67 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -63,6 +63,7 @@ import { whenEditorClosed } from 'vs/workbench/browser/editor'; import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { registerLegacyWindowDriver, registerWindowDriver } from 'vs/platform/driver/electron-sandbox/driver'; export class NativeWindow extends Disposable { @@ -570,6 +571,29 @@ export class NativeWindow extends Disposable { this.nativeHostService.openDevTools(); } } + + // Smoke Test Driver + this.setupDriver(); + } + + private setupDriver(): void { + + // Browser Driver + if (this.environmentService.args['enable-smoke-test-driver']) { + const that = this; + registerWindowDriver({ + async exitApplication(): Promise { + that.nativeHostService.quit(); + + return that.environmentService.mainPid; + } + }); + } + + // Legacy Driver (TODO@bpasero remove me eventually) + else if (this.environmentService.args.driver) { + this.instantiationService.invokeFunction(async accessor => this._register(await registerLegacyWindowDriver(accessor, this.nativeHostService.windowId))); + } } private setupOpenHandlers(): void { diff --git a/test/automation/src/application.ts b/test/automation/src/application.ts index 15b7fbd9a92..2a6df7dc49b 100644 --- a/test/automation/src/application.ts +++ b/test/automation/src/application.ts @@ -52,6 +52,10 @@ export class Application { return !!this.options.web; } + get legacy(): boolean { + return !!this.options.legacy; + } + private _workspacePathOrFolder: string; get workspacePathOrFolder(): string { return this._workspacePathOrFolder; @@ -115,11 +119,11 @@ export class Application { } private async takeScreenshot(name: string): Promise { - if (this.web) { - return; // supported only on desktop + if (this.web || !this.legacy) { + return; // supported only on desktop (legacy) } - // Desktop: call `stopTracing` to take a screenshot + // Desktop (legacy): call `stopTracing` to take a screenshot return this._code?.stopTracing(name, true); } diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index d728c2dfddb..33eba97ba52 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -3,17 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as path from 'path'; +import { join } from 'path'; import * as os from 'os'; import * as cp from 'child_process'; import { IDriver, IDisposable, IElement, Thenable, ILocalizedStrings, ILocaleInfo } from './driver'; import { launch as launchElectron } from './electronDriver'; -import { launch as launchPlaywright } from './playwrightDriver'; +import { launch as launchPlaywrightBrowser } from './playwrightBrowserDriver'; +import { launch as launchPlaywrightElectron } from './playwrightElectronDriver'; import { Logger, measureAndLog } from './logger'; import { copyExtension } from './extensions'; import * as treekill from 'tree-kill'; -const repoPath = path.join(__dirname, '../../..'); +const rootPath = join(__dirname, '../../..'); export interface LaunchOptions { codePath?: string; @@ -21,10 +22,13 @@ export interface LaunchOptions { userDataDir: string; extensionsPath: string; logger: Logger; + logsPath: string; verbose?: boolean; extraArgs?: string[]; remote?: boolean; web?: boolean; + legacy?: boolean; + tracing?: boolean; headless?: boolean; browser?: 'chromium' | 'webkit' | 'firefox'; } @@ -71,22 +75,29 @@ export async function launch(options: LaunchOptions): Promise { throw new Error('Smoke test process has terminated, refusing to spawn Code'); } - await measureAndLog(copyExtension(repoPath, options.extensionsPath, 'vscode-notebook-tests'), 'copyExtension(vscode-notebook-tests)', options.logger); + await measureAndLog(copyExtension(rootPath, options.extensionsPath, 'vscode-notebook-tests'), 'copyExtension(vscode-notebook-tests)', options.logger); // Browser smoke tests if (options.web) { - const { serverProcess, client, driver, kill } = await measureAndLog(launchPlaywright(options), 'launch playwright', options.logger); + const { serverProcess, client, driver, kill } = await measureAndLog(launchPlaywrightBrowser(options), 'launch playwright (browser)', options.logger); registerInstance(serverProcess, options.logger, 'server', kill); - return new Code(client, driver, options.logger, serverProcess); + return new Code(client, driver, options.logger); } - // Electron smoke tests + // Electron smoke tests (playwright) + else if (!options.legacy) { + const { client, driver } = await measureAndLog(launchPlaywrightElectron(options), 'launch playwright (electron)', options.logger); + + return new Code(client, driver, options.logger); + } + + // Electron smoke tests (legacy driver) else { const { electronProcess, client, driver, kill } = await measureAndLog(launchElectron(options), 'launch electron', options.logger); registerInstance(electronProcess, options.logger, 'electron', kill); - return new Code(client, driver, options.logger, electronProcess); + return new Code(client, driver, options.logger); } } @@ -134,8 +145,7 @@ export class Code { constructor( private client: IDisposable, driver: IDriver, - readonly logger: Logger, - private readonly mainProcess: cp.ChildProcess + readonly logger: Logger ) { this.driver = new Proxy(driver, { get(target, prop) { @@ -185,18 +195,13 @@ export class Code { } async exit(): Promise { + + // Start the exit flow via driver + const pid = await measureAndLog(this.driver.exitApplication(), 'driver.exitApplication()', this.logger); + return measureAndLog(new Promise((resolve, reject) => { let done = false; - // Start the exit flow via driver - this.driver.exitApplication().then(veto => { - if (veto) { - done = true; - reject(new Error('Smoke test exit call resulted in unexpected veto')); - } - }); - - // Await the exit of the application (async () => { let retries = 0; while (!done) { @@ -206,7 +211,7 @@ export class Code { this.logger.log('Smoke test exit call did not terminate process after 10s, forcefully exiting the application...'); // no need to await since we're polling for the process to die anyways - treekill(this.mainProcess.pid!, err => { + treekill(pid, err => { this.logger.log('Failed to kill Electron process tree:', err?.message); }); } @@ -217,7 +222,7 @@ export class Code { } try { - process.kill(this.mainProcess.pid!, 0); // throws an exception if the process doesn't exist anymore. + process.kill(pid, 0); // throws an exception if the process doesn't exist anymore. await new Promise(resolve => setTimeout(resolve, 500)); } catch (error) { done = true; diff --git a/test/automation/src/driver.js b/test/automation/src/driver.js index 1da40e42b06..c415029cdf9 100644 --- a/test/automation/src/driver.js +++ b/test/automation/src/driver.js @@ -3,10 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +//@ts-check +'use strict'; + const path = require('path'); exports.connect = function (outPath, handle) { const bootstrapPath = path.join(outPath, 'bootstrap-amd.js'); const { load } = require(bootstrapPath); - return new Promise((c, e) => load('vs/platform/driver/node/driver', ({ connect }) => connect(handle).then(c, e), e)); -}; \ No newline at end of file + + return new Promise((resolve, reject) => load('vs/platform/driver/node/driver', ({ connect }) => connect(handle).then(resolve, reject), reject)); +}; diff --git a/test/automation/src/electronDriver.ts b/test/automation/src/electronDriver.ts index ed6b7726133..e9574a9e725 100644 --- a/test/automation/src/electronDriver.ts +++ b/test/automation/src/electronDriver.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as path from 'path'; -import * as os from 'os'; +import { join } from 'path'; +import { platform } from 'os'; import { tmpName } from 'tmp'; import { connect as connectElectronDriver, IDisposable, IDriver } from './driver'; import { ChildProcess, spawn, SpawnOptions } from 'child_process'; @@ -16,15 +16,17 @@ import { URI } from 'vscode-uri'; import { Logger, measureAndLog } from './logger'; import type { LaunchOptions } from './code'; -const repoPath = path.join(__dirname, '../../..'); +const root = join(__dirname, '..', '..', '..'); -export async function launch(options: LaunchOptions): Promise<{ electronProcess: ChildProcess; client: IDisposable; driver: IDriver; kill: () => Promise }> { - const { codePath, workspacePath, extensionsPath, userDataDir, remote, logger, verbose, extraArgs } = options; +export interface IElectronConfiguration { + readonly electronPath: string; + readonly args: string[]; + readonly env?: NodeJS.ProcessEnv; +} + +export async function resolveElectronConfiguration(options: LaunchOptions): Promise { + const { codePath, workspacePath, extensionsPath, userDataDir, remote, logger, logsPath, extraArgs } = options; const env = { ...process.env }; - const logsPath = path.join(repoPath, '.build', 'logs', remote ? 'smoke-tests-remote' : 'smoke-tests'); - const outPath = codePath ? getBuildOutPath(codePath) : getDevOutPath(); - - const driverIPCHandle = await measureAndLog(createDriverHandle(), 'createDriverHandle', logger); const args = [ workspacePath, @@ -38,8 +40,7 @@ export async function launch(options: LaunchOptions): Promise<{ electronProcess: '--disable-workspace-trust', `--extensions-dir=${extensionsPath}`, `--user-data-dir=${userDataDir}`, - `--logsPath=${logsPath}`, - '--driver', driverIPCHandle + `--logsPath=${logsPath}` ]; if (process.platform === 'linux') { @@ -52,7 +53,7 @@ export async function launch(options: LaunchOptions): Promise<{ electronProcess: if (codePath) { // running against a build: copy the test resolver extension - await measureAndLog(copyExtension(repoPath, extensionsPath, 'vscode-test-resolver'), 'copyExtension(vscode-test-resolver)', logger); + await measureAndLog(copyExtension(root, extensionsPath, 'vscode-test-resolver'), 'copyExtension(vscode-test-resolver)', logger); } args.push('--enable-proposed-api=vscode.vscode-test-resolver'); const remoteDataDir = `${userDataDir}-server`; @@ -60,26 +61,19 @@ export async function launch(options: LaunchOptions): Promise<{ electronProcess: if (codePath) { // running against a build: copy the test resolver extension into remote extensions dir - const remoteExtensionsDir = path.join(remoteDataDir, 'extensions'); + const remoteExtensionsDir = join(remoteDataDir, 'extensions'); mkdirp.sync(remoteExtensionsDir); - await measureAndLog(copyExtension(repoPath, remoteExtensionsDir, 'vscode-notebook-tests'), 'copyExtension(vscode-notebook-tests)', logger); + await measureAndLog(copyExtension(root, remoteExtensionsDir, 'vscode-notebook-tests'), 'copyExtension(vscode-notebook-tests)', logger); } env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir; - env['TESTRESOLVER_LOGS_FOLDER'] = path.join(logsPath, 'server'); + env['TESTRESOLVER_LOGS_FOLDER'] = join(logsPath, 'server'); } - const spawnOptions: SpawnOptions = { env }; - args.push('--enable-proposed-api=vscode.vscode-notebook-tests'); if (!codePath) { - args.unshift(repoPath); - } - - if (verbose) { - args.push('--driver-verbose'); - spawnOptions.stdio = ['ignore', 'inherit', 'inherit']; + args.unshift(root); } if (extraArgs) { @@ -87,6 +81,32 @@ export async function launch(options: LaunchOptions): Promise<{ electronProcess: } const electronPath = codePath ? getBuildElectronPath(codePath) : getDevElectronPath(); + + return { + env, + args, + electronPath + }; +} + +/** + * @deprecated should use the playwright based electron support instead + */ +export async function launch(options: LaunchOptions): Promise<{ electronProcess: ChildProcess; client: IDisposable; driver: IDriver; kill: () => Promise }> { + const { codePath, logger, verbose } = options; + const { env, args, electronPath } = await resolveElectronConfiguration(options); + + const driverIPCHandle = await measureAndLog(createDriverHandle(), 'createDriverHandle', logger); + args.push('--driver', driverIPCHandle); + + const outPath = codePath ? getBuildOutPath(codePath) : getDevOutPath(); + + const spawnOptions: SpawnOptions = { env }; + + if (verbose) { + spawnOptions.stdio = ['ignore', 'inherit', 'inherit']; + } + const electronProcess = spawn(electronPath, args, spawnOptions); logger.log(`Started electron for desktop smoke tests on pid ${electronProcess.pid}`); @@ -150,56 +170,65 @@ async function teardown(electronProcess: ChildProcess, logger: Logger): Promise< logger.log(`Gave up tearing down electron client after ${retries} attempts...`); } -function getDevElectronPath(): string { - const buildPath = path.join(repoPath, '.build'); - const product = require(path.join(repoPath, 'product.json')); +export function getDevElectronPath(): string { + const buildPath = join(root, '.build'); + const product = require(join(root, 'product.json')); switch (process.platform) { case 'darwin': - return path.join(buildPath, 'electron', `${product.nameLong}.app`, 'Contents', 'MacOS', 'Electron'); + return join(buildPath, 'electron', `${product.nameLong}.app`, 'Contents', 'MacOS', 'Electron'); case 'linux': - return path.join(buildPath, 'electron', `${product.applicationName}`); + return join(buildPath, 'electron', `${product.applicationName}`); case 'win32': - return path.join(buildPath, 'electron', `${product.nameShort}.exe`); + return join(buildPath, 'electron', `${product.nameShort}.exe`); default: throw new Error('Unsupported platform.'); } } -function getBuildElectronPath(root: string): string { +export function getBuildElectronPath(root: string): string { switch (process.platform) { case 'darwin': - return path.join(root, 'Contents', 'MacOS', 'Electron'); + return join(root, 'Contents', 'MacOS', 'Electron'); case 'linux': { - const product = require(path.join(root, 'resources', 'app', 'product.json')); - return path.join(root, product.applicationName); + const product = require(join(root, 'resources', 'app', 'product.json')); + return join(root, product.applicationName); } case 'win32': { - const product = require(path.join(root, 'resources', 'app', 'product.json')); - return path.join(root, `${product.nameShort}.exe`); + const product = require(join(root, 'resources', 'app', 'product.json')); + return join(root, `${product.nameShort}.exe`); } default: throw new Error('Unsupported platform.'); } } +export function getBuildVersion(root: string): string { + switch (process.platform) { + case 'darwin': + return require(join(root, 'Contents', 'Resources', 'app', 'package.json')).version; + default: + return require(join(root, 'resources', 'app', 'package.json')).version; + } +} + function getDevOutPath(): string { - return path.join(repoPath, 'out'); + return join(root, 'out'); } function getBuildOutPath(root: string): string { switch (process.platform) { case 'darwin': - return path.join(root, 'Contents', 'Resources', 'app', 'out'); + return join(root, 'Contents', 'Resources', 'app', 'out'); default: - return path.join(root, 'resources', 'app', 'out'); + return join(root, 'resources', 'app', 'out'); } } async function createDriverHandle(): Promise { // Windows - if ('win32' === os.platform()) { + if ('win32' === platform()) { const name = [...Array(15)].map(() => Math.random().toString(36)[3]).join(''); return `\\\\.\\pipe\\${name}`; } diff --git a/test/automation/src/index.ts b/test/automation/src/index.ts index 61f72fe7322..884444f58f5 100644 --- a/test/automation/src/index.ts +++ b/test/automation/src/index.ts @@ -26,3 +26,4 @@ export * from './viewlet'; export * from './localization'; export * from './workbench'; export * from './driver'; +export { getDevElectronPath, getBuildElectronPath, getBuildVersion } from './electronDriver'; diff --git a/test/automation/src/playwrightDriver.ts b/test/automation/src/playwrightBrowserDriver.ts similarity index 76% rename from test/automation/src/playwrightDriver.ts rename to test/automation/src/playwrightBrowserDriver.ts index 4f0f7a94fba..8af107f0681 100644 --- a/test/automation/src/playwrightDriver.ts +++ b/test/automation/src/playwrightBrowserDriver.ts @@ -15,38 +15,32 @@ import { PageFunction } from 'playwright-core/types/structs'; import { Logger, measureAndLog } from './logger'; import type { LaunchOptions } from './code'; -const width = 1200; -const height = 800; +export class PlaywrightDriver implements IDriver { -const root = join(__dirname, '..', '..', '..'); -const logsPath = join(root, '.build', 'logs', 'smoke-tests-browser'); + private static traceCounter = 1; -const vscodeToPlaywrightKey: { [key: string]: string } = { - cmd: 'Meta', - ctrl: 'Control', - shift: 'Shift', - enter: 'Enter', - escape: 'Escape', - right: 'ArrowRight', - up: 'ArrowUp', - down: 'ArrowDown', - left: 'ArrowLeft', - home: 'Home', - esc: 'Escape' -}; - -let traceCounter = 1; - -class PlaywrightDriver implements IDriver { + private static readonly vscodeToPlaywrightKey: { [key: string]: string } = { + cmd: 'Meta', + ctrl: 'Control', + shift: 'Shift', + enter: 'Enter', + escape: 'Escape', + right: 'ArrowRight', + up: 'ArrowUp', + down: 'ArrowDown', + left: 'ArrowLeft', + home: 'Home', + esc: 'Escape' + }; _serviceBrand: undefined; constructor( - private readonly server: ChildProcess, - private readonly browser: playwright.Browser, + private readonly application: playwright.Browser | playwright.ElectronApplication, private readonly context: playwright.BrowserContext, private readonly page: playwright.Page, - private readonly logger: Logger + private readonly serverPid: number | undefined, + private readonly options: LaunchOptions ) { } @@ -59,46 +53,72 @@ class PlaywrightDriver implements IDriver { } async startTracing(windowId: number, name: string): Promise { + if (!this.options.tracing) { + return; // tracing disabled + } + try { - await measureAndLog(this.context.tracing.startChunk({ title: name }), `startTracing for ${name}`, this.logger); + await measureAndLog(this.context.tracing.startChunk({ title: name }), `startTracing for ${name}`, this.options.logger); } catch (error) { // Ignore } } async stopTracing(windowId: number, name: string, persist: boolean): Promise { + if (!this.options.tracing) { + return; // tracing disabled + } + try { let persistPath: string | undefined = undefined; if (persist) { - persistPath = join(logsPath, `playwright-trace-${traceCounter++}-${name.replace(/\s+/g, '-')}.zip`); + persistPath = join(this.options.logsPath, `playwright-trace-${PlaywrightDriver.traceCounter++}-${name.replace(/\s+/g, '-')}.zip`); } - await measureAndLog(this.context.tracing.stopChunk({ path: persistPath }), `stopTracing for ${name}`, this.logger); + await measureAndLog(this.context.tracing.stopChunk({ path: persistPath }), `stopTracing for ${name}`, this.options.logger); } catch (error) { // Ignore } } async reloadWindow(windowId: number) { - throw new Error('Unsupported'); + await this.page.reload(); } async exitApplication() { + + // Stop tracing try { - await measureAndLog(this.context.tracing.stop(), 'stop tracing', this.logger); + if (this.options.tracing) { + await measureAndLog(this.context.tracing.stop(), 'stop tracing', this.options.logger); + } } catch (error) { // Ignore } - try { - await measureAndLog(this.browser.close(), 'Browser.close()', this.logger); - } catch (error) { - // Ignore + // VSCode shutdown (desktop only) + let mainPid: number | undefined = undefined; + if (!this.options.web) { + try { + mainPid = await measureAndLog(this._evaluateWithDriver(([driver]) => (driver as unknown as IDriver).exitApplication()), 'driver.exitApplication()', this.options.logger); + } catch (error) { + this.options.logger.log(`Error exiting appliction (${error})`); + } } - await measureAndLog(teardown(this.server, this.logger), 'teardown server', this.logger); + // Playwright shutdown + try { + await measureAndLog(this.application.close(), 'playwright.close()', this.options.logger); + } catch (error) { + this.options.logger.log(`Error closing appliction (${error})`); + } - return false; + // Server shutdown + if (typeof this.serverPid === 'number') { + await measureAndLog(teardown(this.serverPid, this.options.logger), 'teardown server', this.options.logger); + } + + return mainPid ?? this.serverPid! /* when running web we must have a server Pid */; } async dispatchKeybinding(windowId: number, keybinding: string) { @@ -117,8 +137,8 @@ class PlaywrightDriver implements IDriver { const keys = chord.split('+'); const keysDown: string[] = []; for (let i = 0; i < keys.length; i++) { - if (keys[i] in vscodeToPlaywrightKey) { - keys[i] = vscodeToPlaywrightKey[keys[i]]; + if (keys[i] in PlaywrightDriver.vscodeToPlaywrightKey) { + keys[i] = PlaywrightDriver.vscodeToPlaywrightKey[keys[i]]; } await this.page.keyboard.down(keys[i]); keysDown.push(keys[i]); @@ -136,10 +156,6 @@ class PlaywrightDriver implements IDriver { await this.page.mouse.click(x + (xoffset ? xoffset : 0), y + (yoffset ? yoffset : 0)); } - async doubleClick(windowId: number, selector: string) { - throw new Error('Unsupported'); - } - async setValue(windowId: number, selector: string, text: string) { return this.page.evaluate(([driver, selector, text]) => driver.setValue(selector, text), [await this._getDriverHandle(), selector, text] as const); } @@ -188,12 +204,13 @@ class PlaywrightDriver implements IDriver { return new Promise(resolve => setTimeout(resolve, ms)); } - // TODO: Cache private async _getDriverHandle(): Promise> { return this.page.evaluateHandle('window.driver'); } } +const root = join(__dirname, '..', '..', '..'); + let port = 9000; export async function launch(options: LaunchOptions): Promise<{ serverProcess: ChildProcess; client: IDisposable; driver: IDriver; kill: () => Promise }> { @@ -209,13 +226,13 @@ export async function launch(options: LaunchOptions): Promise<{ serverProcess: C client: { dispose: () => { /* there is no client to dispose for browser, teardown is triggered via exitApplication call */ } }, - driver: new PlaywrightDriver(serverProcess, browser, context, page, options.logger), - kill: () => teardown(serverProcess, options.logger) + driver: new PlaywrightDriver(browser, context, page, serverProcess.pid, options), + kill: () => teardown(serverProcess.pid, options.logger) }; } async function launchServer(options: LaunchOptions) { - const { userDataDir, codePath, extensionsPath, logger } = options; + const { userDataDir, codePath, extensionsPath, logger, logsPath } = options; const codeServerPath = codePath ?? process.env.VSCODE_REMOTE_SERVER_PATH; const agentFolder = userDataDir; await measureAndLog(promisify(mkdir)(agentFolder), `mkdir(${agentFolder})`, logger); @@ -257,21 +274,23 @@ async function launchServer(options: LaunchOptions) { } async function launchBrowser(options: LaunchOptions, endpoint: string) { - const { logger, workspacePath } = options; + const { logger, workspacePath, tracing, headless } = options; - const browser = await measureAndLog(playwright[options.browser ?? 'chromium'].launch({ headless: options.headless ?? false }), 'playwright#launch', logger); + const browser = await measureAndLog(playwright[options.browser ?? 'chromium'].launch({ headless: headless ?? false }), 'playwright#launch', logger); browser.on('disconnected', () => logger.log(`Playwright: browser disconnected`)); const context = await measureAndLog(browser.newContext(), 'browser.newContext', logger); - try { - await measureAndLog(context.tracing.start({ screenshots: true, snapshots: true, sources: true }), 'context.tracing.start()', logger); - } catch (error) { - logger.log(`Failed to start playwright tracing: ${error}`); // do not fail the build when this fails + if (tracing) { + try { + await measureAndLog(context.tracing.start({ screenshots: true, /* remaining options are off for perf reasons */ }), 'context.tracing.start()', logger); + } catch (error) { + logger.log(`Failed to start playwright tracing: ${error}`); // do not fail the build when this fails + } } const page = await measureAndLog(context.newPage(), 'context.newPage()', logger); - await measureAndLog(page.setViewportSize({ width, height }), 'page.setViewportSize', logger); + await measureAndLog(page.setViewportSize({ width: 1200, height: 800 }), 'page.setViewportSize', logger); page.on('pageerror', async (error) => logger.log(`Playwright ERROR: page error: ${error}`)); page.on('crash', () => logger.log('Playwright ERROR: page crash')); @@ -288,8 +307,7 @@ async function launchBrowser(options: LaunchOptions, endpoint: string) { return { browser, context, page }; } -async function teardown(server: ChildProcess, logger: Logger): Promise { - const serverPid = server.pid; +async function teardown(serverPid: number | undefined, logger: Logger): Promise { if (typeof serverPid !== 'number') { return; } diff --git a/test/automation/src/playwrightElectronDriver.ts b/test/automation/src/playwrightElectronDriver.ts new file mode 100644 index 00000000000..de6859240e0 --- /dev/null +++ b/test/automation/src/playwrightElectronDriver.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 * as playwright from '@playwright/test'; +import { IDriver, IDisposable } from './driver'; +import type { LaunchOptions } from './code'; +import { PlaywrightDriver } from './playwrightBrowserDriver'; +import { IElectronConfiguration, resolveElectronConfiguration } from './electronDriver'; +import { measureAndLog } from './logger'; + +export async function launch(options: LaunchOptions): Promise<{ client: IDisposable; driver: IDriver }> { + + // Resolve electron config and update + const { electronPath, args, env } = await resolveElectronConfiguration(options); + args.push('--enable-smoke-test-driver', 'true'); + + // Launch electron via playwright + const { electron, context, page } = await launchElectron({ electronPath, args, env }, options); + + return { + client: { + dispose: () => { /* there is no client to dispose for electron, teardown is triggered via exitApplication call */ } + }, + driver: new PlaywrightDriver(electron, context, page, undefined /* no server */, options) + }; +} + +async function launchElectron(configuration: IElectronConfiguration, options: LaunchOptions) { + const { logger, tracing } = options; + + const electron = await measureAndLog(playwright._electron.launch({ + executablePath: configuration.electronPath, + args: configuration.args, + env: configuration.env as { [key: string]: string } + }), 'playwright-electron#launch', logger); + + const window = await measureAndLog(electron.firstWindow(), 'playwright-electron#firstWindow', logger); + + const context = window.context(); + + if (tracing) { + try { + await measureAndLog(context.tracing.start({ screenshots: true, /* remaining options are off for perf reasons */ }), 'context.tracing.start()', logger); + } catch (error) { + logger.log(`Failed to start playwright tracing: ${error}`); // do not fail the build when this fails + } + } + + window.on('pageerror', async (error) => logger.log(`Playwright ERROR: page error: ${error}`)); + window.on('crash', () => logger.log('Playwright ERROR: page crash')); + window.on('close', () => logger.log('Playwright: page close')); + window.on('response', async (response) => { + if (response.status() >= 400) { + logger.log(`Playwright ERROR: HTTP status ${response.status()} for ${response.url()}`); + } + }); + + return { electron, context, page: window }; +} diff --git a/test/automation/tools/copy-driver-definition.js b/test/automation/tools/copy-driver-definition.js index 5f34e6d7ddc..cf757ecbc38 100644 --- a/test/automation/tools/copy-driver-definition.js +++ b/test/automation/tools/copy-driver-definition.js @@ -3,6 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +//@ts-check +'use strict'; + const fs = require('fs'); const path = require('path'); diff --git a/test/automation/tools/copy-package-version.js b/test/automation/tools/copy-package-version.js index f01739a651f..b9d1560c406 100644 --- a/test/automation/tools/copy-package-version.js +++ b/test/automation/tools/copy-package-version.js @@ -3,6 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +//@ts-check +'use strict'; + const fs = require('fs'); const path = require('path'); diff --git a/test/integration/browser/src/index.ts b/test/integration/browser/src/index.ts index 0510fc4f54d..18350685d5e 100644 --- a/test/integration/browser/src/index.ts +++ b/test/integration/browser/src/index.ts @@ -125,7 +125,7 @@ async function launchServer(browserType: BrowserType): Promise<{ endpoint: url.U const root = path.join(__dirname, '..', '..', '..', '..'); const logsPath = path.join(root, '.build', 'logs', 'integration-tests-browser'); - const serverArgs = ['--driver', 'web', '--enable-proposed-api', '--disable-telemetry', '--server-data-dir', userDataDir, '--accept-server-license-terms', '--disable-workspace-trust']; + const serverArgs = ['--enable-proposed-api', '--disable-telemetry', '--server-data-dir', userDataDir, '--accept-server-license-terms', '--disable-workspace-trust']; let serverLocation: string; if (process.env.VSCODE_REMOTE_SERVER_PATH) { diff --git a/test/integration/electron/testrunner.js b/test/integration/electron/testrunner.js index 8a64744321b..61b8cded132 100644 --- a/test/integration/electron/testrunner.js +++ b/test/integration/electron/testrunner.js @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +//@ts-check 'use strict'; const paths = require('path'); @@ -10,7 +11,9 @@ const glob = require('glob'); // Linux: prevent a weird NPE when mocha on Linux requires the window size from the TTY // Since we are not running in a tty environment, we just implementt he method statically const tty = require('tty'); +// @ts-ignore if (!tty.getWindowSize) { + // @ts-ignore tty.getWindowSize = function () { return [80, 75]; }; } const Mocha = require('mocha'); diff --git a/test/smoke/src/areas/statusbar/statusbar.test.ts b/test/smoke/src/areas/statusbar/statusbar.test.ts index 6cfa745a11e..a383d8a5e51 100644 --- a/test/smoke/src/areas/statusbar/statusbar.test.ts +++ b/test/smoke/src/areas/statusbar/statusbar.test.ts @@ -7,7 +7,7 @@ import { join } from 'path'; import { Application, Quality, StatusBarElement, Logger } from '../../../../automation'; import { installAllHandlers } from '../../utils'; -export function setup(isWeb: boolean, logger: Logger) { +export function setup(logger: Logger) { describe('Statusbar', () => { // Shared before/after handling diff --git a/test/smoke/src/areas/workbench/data-loss.test.ts b/test/smoke/src/areas/workbench/data-loss.test.ts index 2749bb696da..aa6118a16ef 100644 --- a/test/smoke/src/areas/workbench/data-loss.test.ts +++ b/test/smoke/src/areas/workbench/data-loss.test.ts @@ -118,7 +118,7 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger } }); - describe('Data Loss (stable -> insiders)', () => { + describe.skip('Data Loss (stable -> insiders)', () => { //TODO@bpasero enable again once we shipped 1.67.x let insidersApp: Application | undefined = undefined; let stableApp: Application | undefined = undefined; diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 2b8fe48e500..39af65bfb0f 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -13,7 +13,7 @@ import * as rimraf from 'rimraf'; import * as mkdirp from 'mkdirp'; import * as vscodetest from '@vscode/test-electron'; import fetch from 'node-fetch'; -import { Quality, MultiLogger, Logger, ConsoleLogger, FileLogger, measureAndLog } from '../../automation'; +import { Quality, MultiLogger, Logger, ConsoleLogger, FileLogger, measureAndLog, getDevElectronPath, getBuildElectronPath, getBuildVersion } from '../../automation'; import { retry, timeout } from './utils'; import { setup as setupDataLossTests } from './areas/workbench/data-loss.test'; @@ -28,7 +28,7 @@ import { setup as setupLocalizationTests } from './areas/workbench/localization. import { setup as setupLaunchTests } from './areas/workbench/launch.test'; import { setup as setupTerminalTests } from './areas/terminal/terminal.test'; -const repoPath = path.join(__dirname, '..', '..', '..'); +const rootPath = path.join(__dirname, '..', '..', '..'); const [, , ...args] = process.argv; const opts = minimist(args, { @@ -44,7 +44,9 @@ const opts = minimist(args, { 'verbose', 'remote', 'web', - 'headless' + 'headless', + 'legacy', + 'tracing' ], default: { verbose: false @@ -54,12 +56,29 @@ const opts = minimist(args, { remote?: boolean; headless?: boolean; web?: boolean; + legacy?: boolean; + tracing?: boolean; build?: string; 'stable-build'?: string; browser?: string; electronArgs?: string; }; +const logsPath = (() => { + const logsParentPath = path.join(rootPath, '.build', 'logs'); + + let logsName: string; + if (opts.web) { + logsName = 'smoke-tests-browser'; + } else if (opts.remote) { + logsName = opts.legacy ? 'smoke-tests-remote-legacy' : 'smoke-tests-remote'; + } else { + logsName = opts.legacy ? 'smoke-tests-electron-legacy' : 'smoke-tests-electron'; + } + + return path.join(logsParentPath, logsName); +})(); + const logger = createLogger(); function createLogger(): Logger { @@ -70,10 +89,12 @@ function createLogger(): Logger { loggers.push(new ConsoleLogger()); } + // Prepare logs path + fs.rmSync(logsPath, { recursive: true, force: true, maxRetries: 3 }); + mkdirp.sync(logsPath); + // Always log to log file - const logPath = path.join(repoPath, '.build', 'logs', opts.web ? 'smoke-tests-browser' : opts.remote ? 'smoke-tests-remote' : 'smoke-tests'); - mkdirp.sync(logPath); - loggers.push(new FileLogger(path.join(logPath, 'smoke-test-runner.log'))); + loggers.push(new FileLogger(path.join(logsPath, 'smoke-test-runner.log'))); return new MultiLogger(loggers); } @@ -122,49 +143,6 @@ function parseVersion(version: string): { major: number; minor: number; patch: n // #### Electron Smoke Tests #### // if (!opts.web) { - - function getDevElectronPath(): string { - const buildPath = path.join(repoPath, '.build'); - const product = require(path.join(repoPath, 'product.json')); - - switch (process.platform) { - case 'darwin': - return path.join(buildPath, 'electron', `${product.nameLong}.app`, 'Contents', 'MacOS', 'Electron'); - case 'linux': - return path.join(buildPath, 'electron', `${product.applicationName}`); - case 'win32': - return path.join(buildPath, 'electron', `${product.nameShort}.exe`); - default: - throw new Error('Unsupported platform.'); - } - } - - function getBuildElectronPath(root: string): string { - switch (process.platform) { - case 'darwin': - return path.join(root, 'Contents', 'MacOS', 'Electron'); - case 'linux': { - const product = require(path.join(root, 'resources', 'app', 'product.json')); - return path.join(root, product.applicationName); - } - case 'win32': { - const product = require(path.join(root, 'resources', 'app', 'product.json')); - return path.join(root, `${product.nameShort}.exe`); - } - default: - throw new Error('Unsupported platform.'); - } - } - - function getBuildVersion(root: string): string { - switch (process.platform) { - case 'darwin': - return require(path.join(root, 'Contents', 'Resources', 'app', 'package.json')).version; - default: - return require(path.join(root, 'resources', 'app', 'package.json')).version; - } - } - let testCodePath = opts.build; let electronPath: string; @@ -174,7 +152,7 @@ if (!opts.web) { } else { testCodePath = getDevElectronPath(); electronPath = testCodePath; - process.env.VSCODE_REPOSITORY = repoPath; + process.env.VSCODE_REPOSITORY = rootPath; process.env.VSCODE_DEV = '1'; process.env.VSCODE_CLI = '1'; } @@ -213,7 +191,7 @@ else { } if (!testCodeServerPath) { - process.env.VSCODE_REPOSITORY = repoPath; + process.env.VSCODE_REPOSITORY = rootPath; process.env.VSCODE_DEV = '1'; process.env.VSCODE_CLI = '1'; @@ -355,9 +333,12 @@ before(async function () { extensionsPath, waitTime: parseInt(opts['wait-time'] || '0') || 20, logger, + logsPath, verbose: opts.verbose, remote: opts.remote, web: opts.web, + legacy: opts.legacy, + tracing: opts.tracing, headless: opts.headless, browser: opts.browser, extraArgs: (opts.electronArgs || '').split(' ').map(a => a.trim()).filter(a => !!a) @@ -390,14 +371,14 @@ after(async function () { } }); -describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { +describe(`VSCode Smoke Tests (${opts.web ? 'Web' : opts.legacy ? 'Electron (legacy)' : 'Electron'})`, () => { if (!opts.web) { setupDataLossTests(() => opts['stable-build'] /* Do not change, deferred for a reason! */, logger); } - if (!opts.web) { setupPreferencesTests(logger); } + setupPreferencesTests(logger); setupSearchTests(logger); setupNotebookTests(logger); setupLanguagesTests(logger); - if (opts.web) { setupTerminalTests(logger); } // TODO@daniel TODO@meggan: Enable terminal tests for non-web when the desktop driver is moved to playwright - setupStatusbarTests(!!opts.web, logger); + setupTerminalTests(logger); + setupStatusbarTests(logger); if (quality !== Quality.Dev) { setupExtensionTests(logger); } if (!opts.web) { setupMultirootTests(logger); } if (!opts.web && !opts.remote && quality !== Quality.Dev) { setupLocalizationTests(logger); } diff --git a/test/smoke/test/index.js b/test/smoke/test/index.js index 276bcfe37b6..7b2894db1e1 100644 --- a/test/smoke/test/index.js +++ b/test/smoke/test/index.js @@ -3,17 +3,20 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -const path = require('path'); +//@ts-check +'use strict'; + +const { join } = require('path'); const Mocha = require('mocha'); const minimist = require('minimist'); const [, , ...args] = process.argv; const opts = minimist(args, { - boolean: 'web', + boolean: ['web', 'legacy'], string: ['f', 'g'] }); -const suite = opts['web'] ? 'Browser Smoke Tests' : 'Desktop Smoke Tests'; +const suite = opts['web'] ? 'Browser Smoke Tests' : opts['legacy'] ? 'Desktop Smoke Tests (Legacy)' : 'Desktop Smoke Tests'; const options = { color: true, @@ -28,7 +31,7 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { 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`) + mochaFile: join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) } }; } @@ -39,9 +42,8 @@ mocha.run(failures => { // Indicate location of log files for further diagnosis if (failures) { - const repoPath = path.join(__dirname, '..', '..', '..'); - const logPath = path.join(repoPath, '.build', 'logs', opts.web ? 'smoke-tests-browser' : opts.remote ? 'smoke-tests-remote' : 'smoke-tests'); - const logFile = path.join(logPath, 'smoke-test-runner.log'); + const rootPath = join(__dirname, '..', '..', '..'); + const logPath = join(rootPath, '.build', 'logs'); if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { console.log(` @@ -62,7 +64,7 @@ mocha.run(failures => { # '${logPath}'. # # Logs of the smoke test runner are stored into -# '${logFile}'. +# 'smoke-test-runner.log' in respective folder. # ############################################# `); diff --git a/test/unit/browser/index.js b/test/unit/browser/index.js index 6e8a61872a6..f8f871d6d3b 100644 --- a/test/unit/browser/index.js +++ b/test/unit/browser/index.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ //@ts-check +'use strict'; const path = require('path'); const glob = require('glob'); diff --git a/test/unit/node/index.js b/test/unit/node/index.js index 8ef90e8dc4e..f423c6d64fd 100644 --- a/test/unit/node/index.js +++ b/test/unit/node/index.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ //@ts-check +'use strict'; process.env.MOCHA_COLORS = '1'; // Force colors (note that this must come before any mocha imports) From ab559715918529294d44ca4d036baafca999dbe1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 10:15:40 +0200 Subject: [PATCH 027/135] :up: playwright --- package.json | 2 +- yarn.lock | 487 +++++++++++++++++++++++++-------------------------- 2 files changed, 238 insertions(+), 251 deletions(-) diff --git a/package.json b/package.json index 44fbbe4b042..3bbf8110655 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ }, "devDependencies": { "7zip": "0.0.6", - "@playwright/test": "1.18.0", + "@playwright/test": "1.20.2", "@types/applicationinsights": "0.20.0", "@types/cookie": "^0.3.3", "@types/copy-webpack-plugin": "^6.0.3", diff --git a/yarn.lock b/yarn.lock index 8187a7e0699..3da0fb20b3c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -95,6 +95,13 @@ events "^3.0.0" tslib "^2.2.0" +"@babel/code-frame@7.16.7", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + "@babel/code-frame@^7.0.0": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -102,13 +109,6 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" @@ -121,20 +121,20 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== -"@babel/core@^7.14.8": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf" - integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA== +"@babel/core@7.16.12": + version "7.16.12" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.12.tgz#5edc53c1b71e54881315923ae2aedea2522bb784" + integrity sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg== dependencies: "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.16.7" + "@babel/generator" "^7.16.8" "@babel/helper-compilation-targets" "^7.16.7" "@babel/helper-module-transforms" "^7.16.7" "@babel/helpers" "^7.16.7" - "@babel/parser" "^7.16.7" + "@babel/parser" "^7.16.12" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/traverse" "^7.16.10" + "@babel/types" "^7.16.8" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -163,7 +163,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.16.7", "@babel/generator@^7.16.8": +"@babel/generator@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== @@ -172,6 +172,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.17.3": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/generator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" @@ -199,6 +208,19 @@ browserslist "^4.17.5" semver "^6.3.0" +"@babel/helper-create-class-features-plugin@^7.16.10": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" + integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-create-class-features-plugin@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz#9c5b34b53a01f2097daf10678d65135c1b9f84ba" @@ -293,7 +315,7 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": +"@babel/helper-plugin-utils@7.16.7", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== @@ -397,6 +419,11 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.16.12", "@babel/parser@^7.17.3": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== + "@babel/parser@^7.16.7", "@babel/parser@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17" @@ -407,7 +434,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== -"@babel/plugin-proposal-class-properties@^7.14.5": +"@babel/plugin-proposal-class-properties@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== @@ -415,7 +442,7 @@ "@babel/helper-create-class-features-plugin" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-proposal-dynamic-import@^7.14.5": +"@babel/plugin-proposal-dynamic-import@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== @@ -423,7 +450,7 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-namespace-from@^7.14.5": +"@babel/plugin-proposal-export-namespace-from@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== @@ -431,7 +458,7 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": +"@babel/plugin-proposal-logical-assignment-operators@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== @@ -439,7 +466,7 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": +"@babel/plugin-proposal-nullish-coalescing-operator@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== @@ -447,7 +474,7 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-numeric-separator@^7.14.5": +"@babel/plugin-proposal-numeric-separator@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== @@ -455,7 +482,7 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-optional-chaining@^7.14.5": +"@babel/plugin-proposal-optional-chaining@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== @@ -464,15 +491,15 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.14.5": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz#e418e3aa6f86edd6d327ce84eff188e479f571e0" - integrity sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw== +"@babel/plugin-proposal-private-methods@7.16.11": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" + integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.16.10" "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-proposal-private-property-in-object@^7.14.5": +"@babel/plugin-proposal-private-property-in-object@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== @@ -482,7 +509,7 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-syntax-async-generators@^7.8.4": +"@babel/plugin-syntax-async-generators@7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== @@ -503,20 +530,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-json-strings@^7.8.3": +"@babel/plugin-syntax-json-strings@7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" - integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -538,14 +558,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": +"@babel/plugin-syntax-optional-catch-binding@7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== @@ -573,7 +593,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-modules-commonjs@^7.14.5": +"@babel/plugin-transform-modules-commonjs@7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== @@ -583,17 +603,6 @@ "@babel/helper-simple-access" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-react-jsx@^7.14.5": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz#86a6a220552afd0e4e1f0388a68a372be7add0d4" - integrity sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.16.7" - "@babel/types" "^7.16.7" - "@babel/plugin-transform-typescript@^7.16.7": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" @@ -603,7 +612,7 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-typescript" "^7.16.7" -"@babel/preset-typescript@^7.14.5": +"@babel/preset-typescript@7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== @@ -630,6 +639,22 @@ "@babel/parser" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/traverse@^7.16.10": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/traverse@^7.16.7": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.8.tgz#bab2f2b09a5fe8a8d9cad22cbfe3ba1d126fef9c" @@ -669,6 +694,14 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@babel/types@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + "@babel/types@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" @@ -1013,49 +1046,45 @@ node-addon-api "^3.2.1" node-gyp-build "^4.3.0" -"@playwright/test@1.18.0": - version "1.18.0" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.18.0.tgz#e6ac7b588d927fdd028d72f0db1030dd777a79a7" - integrity sha512-ceu4DqerPlyRsdNfke4IUyWH1WccRuBokngFdPAzc5CRzlGmSTT59NBkJyn8Fg/F01CziaMFgNRrHQIMSd4g5A== +"@playwright/test@1.20.2": + version "1.20.2" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.20.2.tgz#0da1f24bf12d5a7249fa771a5344b76170f62653" + integrity sha512-unkLa+xe/lP7MVC0qpgadc9iSG1+LEyGBzlXhGS/vLGAJaSFs8DNfI89hNd5shHjWfNzb34JgPVnkRKCSNo5iw== dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/core" "^7.14.8" - "@babel/plugin-proposal-class-properties" "^7.14.5" - "@babel/plugin-proposal-dynamic-import" "^7.14.5" - "@babel/plugin-proposal-export-namespace-from" "^7.14.5" - "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" - "@babel/plugin-proposal-numeric-separator" "^7.14.5" - "@babel/plugin-proposal-optional-chaining" "^7.14.5" - "@babel/plugin-proposal-private-methods" "^7.14.5" - "@babel/plugin-proposal-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-transform-modules-commonjs" "^7.14.5" - "@babel/plugin-transform-react-jsx" "^7.14.5" - "@babel/preset-typescript" "^7.14.5" - babel-plugin-module-resolver "^4.1.0" + "@babel/code-frame" "7.16.7" + "@babel/core" "7.16.12" + "@babel/helper-plugin-utils" "7.16.7" + "@babel/plugin-proposal-class-properties" "7.16.7" + "@babel/plugin-proposal-dynamic-import" "7.16.7" + "@babel/plugin-proposal-export-namespace-from" "7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "7.16.7" + "@babel/plugin-proposal-numeric-separator" "7.16.7" + "@babel/plugin-proposal-optional-chaining" "7.16.7" + "@babel/plugin-proposal-private-methods" "7.16.11" + "@babel/plugin-proposal-private-property-in-object" "7.16.7" + "@babel/plugin-syntax-async-generators" "7.8.4" + "@babel/plugin-syntax-json-strings" "7.8.3" + "@babel/plugin-syntax-object-rest-spread" "7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "7.8.3" + "@babel/plugin-transform-modules-commonjs" "7.16.8" + "@babel/preset-typescript" "7.16.7" colors "1.4.0" - commander "^8.2.0" - debug "^4.1.1" - expect "=27.2.5" - jest-matcher-utils "=27.2.5" - jpeg-js "^0.4.2" - json5 "^2.2.0" - mime "^2.4.6" - minimatch "^3.0.3" - ms "^2.1.2" - open "^8.3.0" - pirates "^4.0.1" - pixelmatch "^5.2.1" - playwright-core "=1.18.0" - pngjs "^5.0.0" - rimraf "^3.0.2" - source-map-support "^0.4.18" - stack-utils "^2.0.3" - yazl "^2.5.1" + commander "8.3.0" + debug "4.3.3" + expect "27.2.5" + jest-matcher-utils "27.2.5" + json5 "2.2.1" + mime "3.0.0" + minimatch "3.0.4" + ms "2.1.3" + open "8.4.0" + pirates "4.0.4" + playwright-core "1.20.2" + rimraf "3.0.2" + source-map-support "0.4.18" + stack-utils "2.0.5" + yazl "2.5.1" "@sindresorhus/is@^0.14.0": version "0.14.0" @@ -2441,17 +2470,6 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" -babel-plugin-module-resolver@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2" - integrity sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA== - dependencies: - find-babel-config "^1.2.0" - glob "^7.1.6" - pkg-up "^3.1.0" - reselect "^4.0.0" - resolve "^1.13.1" - bach@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880" @@ -3328,6 +3346,11 @@ commander@2.11.x: resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== +commander@8.3.0, commander@^8.2.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + commander@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -3348,11 +3371,6 @@ commander@^7.0.0, commander@^7.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commander@^8.2.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - commandpost@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/commandpost/-/commandpost-1.2.1.tgz#2e9c4c7508b9dc704afefaa91cab92ee6054cc68" @@ -3856,6 +3874,13 @@ debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: dependencies: ms "2.1.2" +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" @@ -3863,13 +3888,6 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -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" - decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -4867,7 +4885,7 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -expect@=27.2.5: +expect@27.2.5: version "27.2.5" resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.5.tgz#16154aaa60b4d9a5b0adacfea3e4d6178f4b93fd" integrity sha512-ZrO0w7bo8BgGoP/bLz+HDCI+0Hfei9jUSZs5yI/Wyn9VkG9w8oJ7rHRgYj+MA7yqqFa0IwHA3flJzZtYugShJA== @@ -4936,17 +4954,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.0.3: - version "1.7.0" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" - integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== - dependencies: - concat-stream "^1.6.2" - debug "^2.6.9" - mkdirp "^0.5.4" - yauzl "^2.10.0" - -extract-zip@^2.0.1: +extract-zip@2.0.1, extract-zip@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== @@ -4957,6 +4965,16 @@ extract-zip@^2.0.1: optionalDependencies: "@types/yauzl" "^2.9.1" +extract-zip@^1.0.3: + version "1.7.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" + integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== + dependencies: + concat-stream "^1.6.2" + debug "^2.6.9" + mkdirp "^0.5.4" + yauzl "^2.10.0" + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -5133,14 +5151,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-babel-config@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2" - integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA== - dependencies: - json5 "^0.5.1" - path-exists "^3.0.0" - find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" @@ -6283,6 +6293,14 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +https-proxy-agent@5.0.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@^2.2.3: version "2.2.4" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" @@ -6299,14 +6317,6 @@ https-proxy-agent@^4.0.0: agent-base "5" 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" - human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -6619,13 +6629,6 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" -is-core-module@^2.8.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" - integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== - dependencies: - has "^1.0.3" - is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -7012,7 +7015,7 @@ jest-get-type@^27.0.6, jest-get-type@^27.4.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== -jest-matcher-utils@=27.2.5: +jest-matcher-utils@27.2.5: version "27.2.5" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.2.5.tgz#4684faaa8eb32bf15e6edaead6834031897e2980" integrity sha512-qNR/kh6bz0Dyv3m68Ck2g1fLW5KlSOUNcFQh87VXHZwWc/gY6XwnKofx76Qytz3x5LDWT09/2+yXndTkaG4aWg== @@ -7061,7 +7064,7 @@ jest-worker@^27.0.2: merge-stream "^2.0.0" supports-color "^8.0.0" -jpeg-js@^0.4.2: +jpeg-js@0.4.3, jpeg-js@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== @@ -7162,10 +7165,10 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= +json5@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== json5@^1.0.1: version "1.0.1" @@ -7188,13 +7191,6 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" -json5@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -7868,6 +7864,11 @@ mime-types@^2.1.27: dependencies: mime-db "1.48.0" +mime@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + mime@^1.3.4: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" @@ -8116,7 +8117,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1, ms@^2.1.2: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -8606,7 +8607,7 @@ only@~0.0.2: resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= -open@^8.3.0: +open@8.4.0: version "8.4.0" resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== @@ -8906,7 +8907,7 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -9036,12 +9037,12 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= -pirates@^4.0.1: +pirates@4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== -pixelmatch@^5.2.1: +pixelmatch@5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65" integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ== @@ -9062,34 +9063,29 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== +playwright-core@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.20.2.tgz#02336afd9a631d59a666f11f3492550201c6c31b" + integrity sha512-iV6+HftSPalynkq0CYJala1vaTOq7+gU9BRfKCdM9bAxNq/lFLrwbluug2Wt5OoUwbMABcnTThIEm3/qUhCdJQ== dependencies: - find-up "^3.0.0" - -playwright-core@=1.18.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.18.0.tgz#b4d2b9068f26357adaa952a13254796fd439f322" - integrity sha512-JTRlCVpfAFcC1nth+XIE07w6M5m6C8PaEoClv7wGWF97cyDMcHIij0xIVEKMKli7IG5N0mqjLDFc/akXSbMZ1g== - dependencies: - commander "^8.2.0" - debug "^4.1.1" - extract-zip "^2.0.1" - https-proxy-agent "^5.0.0" - jpeg-js "^0.4.2" - mime "^2.4.6" - pngjs "^5.0.0" - progress "^2.0.3" - proper-lockfile "^4.1.1" - proxy-from-env "^1.1.0" - rimraf "^3.0.2" - socks-proxy-agent "^6.1.0" - stack-utils "^2.0.3" - ws "^7.4.6" - yauzl "^2.10.0" - yazl "^2.5.1" + colors "1.4.0" + commander "8.3.0" + debug "4.3.3" + extract-zip "2.0.1" + https-proxy-agent "5.0.0" + jpeg-js "0.4.3" + mime "3.0.0" + pixelmatch "5.2.1" + pngjs "6.0.0" + progress "2.0.3" + proper-lockfile "4.1.2" + proxy-from-env "1.1.0" + rimraf "3.0.2" + socks-proxy-agent "6.1.1" + stack-utils "2.0.5" + ws "8.4.2" + yauzl "2.10.0" + yazl "2.5.1" playwright-core@=1.18.1: version "1.18.1" @@ -9149,6 +9145,11 @@ plugin-error@^1.0.0, plugin-error@^1.0.1: arr-union "^3.1.0" extend-shallow "^3.0.2" +pngjs@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" + integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== + pngjs@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe" @@ -9550,22 +9551,22 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= +progress@2.0.3, progress@^2.0.0, progress@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= -progress@^2.0.0, progress@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -proper-lockfile@^4.1.1: +proper-lockfile@4.1.2, proper-lockfile@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== @@ -9579,7 +9580,7 @@ proto-list@~1.2.1: resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= -proxy-from-env@^1.1.0: +proxy-from-env@1.1.0, proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== @@ -9969,11 +9970,6 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -reselect@^4.0.0: - version "4.1.5" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" - integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -10032,15 +10028,6 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.4.0: is-core-module "^2.1.0" path-parse "^1.0.6" -resolve@^1.13.1: - version "1.21.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" - integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== - dependencies: - is-core-module "^2.8.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - resolve@^1.3.2: version "1.14.2" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2" @@ -10110,7 +10097,7 @@ rimraf@2.6.3, rimraf@~2.6.2: dependencies: glob "^7.1.3" -rimraf@^3.0.2: +rimraf@3.0.2, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -10469,6 +10456,15 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +socks-proxy-agent@6.1.1, socks-proxy-agent@^6.1.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + socks-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" @@ -10478,15 +10474,6 @@ socks-proxy-agent@^5.0.0: debug "4" socks "^2.3.3" -socks-proxy-agent@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" - integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== - dependencies: - agent-base "^6.0.2" - debug "^4.3.1" - socks "^2.6.1" - socks@^2.3.3, socks@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" @@ -10519,6 +10506,13 @@ source-map-resolve@^0.6.0: atob "^2.1.2" decode-uri-component "^0.2.0" +source-map-support@0.4.18: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + source-map-support@^0.3.2: version "0.3.3" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.3.3.tgz#34900977d5ba3f07c7757ee72e73bb1a9b53754f" @@ -10526,13 +10520,6 @@ source-map-support@^0.3.2: dependencies: source-map "0.1.32" -source-map-support@^0.4.18: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - source-map-support@~0.5.12, source-map-support@~0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" @@ -10683,7 +10670,7 @@ stack-trace@0.0.10: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= -stack-utils@^2.0.3: +stack-utils@2.0.5, stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== @@ -11005,11 +10992,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -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" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - sver-compat@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" @@ -12266,6 +12248,11 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" +ws@8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b" + integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA== + ws@^7.2.0: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" @@ -12523,7 +12510,7 @@ yaserver@^0.2.0: resolved "https://registry.yarnpkg.com/yaserver/-/yaserver-0.2.0.tgz#56393027dc13f3c1bb89d20e0bd17269aa927802" integrity sha512-onsELrl7Y42M4P3T9R0N/ZJNJRu4cGwzhDyOWIFRMJvPUIrGKInYGh+DJBefrbr1qoyDu7DSCLl9BL5hSSVfDA== -yauzl@^2.10.0, yauzl@^2.4.2, yauzl@^2.9.2: +yauzl@2.10.0, yauzl@^2.10.0, yauzl@^2.4.2, 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= @@ -12539,6 +12526,13 @@ yauzl@^2.2.1: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" +yazl@2.5.1, yazl@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" + integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== + dependencies: + buffer-crc32 "~0.2.3" + yazl@^2.2.1, yazl@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071" @@ -12546,13 +12540,6 @@ yazl@^2.2.1, yazl@^2.4.3: dependencies: buffer-crc32 "~0.2.3" -yazl@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" - integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== - dependencies: - buffer-crc32 "~0.2.3" - ylru@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" From f5dabfc304d0a823937a4e70929a66e5395f7f6a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 10:31:46 +0200 Subject: [PATCH 028/135] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3bbf8110655..41c8f8d1ecb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.67.0", - "distro": "044c89b614724e7c07260fbfd36f607ebce52c99", + "distro": "da25c5fdcddb51e272e33c9bfa6dbfa7ddbdc788", "author": { "name": "Microsoft Corporation" }, From 8736944a3a847e222918cc7a2da4a2209a8fd6d3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 10:36:25 +0200 Subject: [PATCH 029/135] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 41c8f8d1ecb..8da8c4e43ea 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.67.0", - "distro": "da25c5fdcddb51e272e33c9bfa6dbfa7ddbdc788", + "distro": "f74dbae61874e8f1f690a8e501a7dafd45c73d87", "author": { "name": "Microsoft Corporation" }, From 0c11ecd14b2655c9bb72c3babbf80496aa9e6a4d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 10:47:24 +0200 Subject: [PATCH 030/135] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8da8c4e43ea..8c03e5d6c80 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.67.0", - "distro": "f74dbae61874e8f1f690a8e501a7dafd45c73d87", + "distro": "c5695c25f6693722046eff57964fd1e60cab68e8", "author": { "name": "Microsoft Corporation" }, From 68a923d383a7e63fbd02c735610255811f354888 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 4 Apr 2022 10:56:20 +0200 Subject: [PATCH 031/135] Self register configuration resolver for web Part of #146027 --- .../baseConfigurationResolverService.ts | 369 ++++++++++++++++++ .../browser/configurationResolverService.ts | 369 +----------------- .../configurationResolverService.ts | 2 +- .../configurationResolverService.test.ts | 2 +- src/vs/workbench/workbench.web.main.ts | 4 +- 5 files changed, 380 insertions(+), 366 deletions(-) create mode 100644 src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts diff --git a/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts new file mode 100644 index 00000000000..f6f0d6fa353 --- /dev/null +++ b/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts @@ -0,0 +1,369 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { URI as uri } from 'vs/base/common/uri'; +import * as nls from 'vs/nls'; +import * as Types from 'vs/base/common/types'; +import { Schemas } from 'vs/base/common/network'; +import { SideBySideEditor, EditorResourceAccessor } from 'vs/workbench/common/editor'; +import { IStringDictionary, forEach, fromMap } from 'vs/base/common/collections'; +import { IConfigurationService, IConfigurationOverrides, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IWorkspaceFolder, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; +import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; +import { IQuickInputService, IInputOptions, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; +import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; +import { IProcessEnvironment } from 'vs/base/common/platform'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { IPathService } from 'vs/workbench/services/path/common/pathService'; + +export abstract class BaseConfigurationResolverService extends AbstractVariableResolverService { + + static readonly INPUT_OR_COMMAND_VARIABLES_PATTERN = /\${((input|command):(.*?))}/g; + + constructor( + context: { + getAppRoot: () => string | undefined; + getExecPath: () => string | undefined; + }, + envVariablesPromise: Promise, + editorService: IEditorService, + private readonly configurationService: IConfigurationService, + private readonly commandService: ICommandService, + private readonly workspaceContextService: IWorkspaceContextService, + private readonly quickInputService: IQuickInputService, + private readonly labelService: ILabelService, + private readonly pathService: IPathService + ) { + super({ + getFolderUri: (folderName: string): uri | undefined => { + const folder = workspaceContextService.getWorkspace().folders.filter(f => f.name === folderName).pop(); + return folder ? folder.uri : undefined; + }, + getWorkspaceFolderCount: (): number => { + return workspaceContextService.getWorkspace().folders.length; + }, + getConfigurationValue: (folderUri: uri | undefined, suffix: string): string | undefined => { + return configurationService.getValue(suffix, folderUri ? { resource: folderUri } : {}); + }, + getAppRoot: (): string | undefined => { + return context.getAppRoot(); + }, + getExecPath: (): string | undefined => { + return context.getExecPath(); + }, + getFilePath: (): string | undefined => { + const fileResource = EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { + supportSideBySide: SideBySideEditor.PRIMARY, + filterByScheme: [Schemas.file, Schemas.vscodeUserData, this.pathService.defaultUriScheme] + }); + if (!fileResource) { + return undefined; + } + return this.labelService.getUriLabel(fileResource, { noPrefix: true }); + }, + getWorkspaceFolderPathForFile: (): string | undefined => { + const fileResource = EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { + supportSideBySide: SideBySideEditor.PRIMARY, + filterByScheme: [Schemas.file, Schemas.vscodeUserData, this.pathService.defaultUriScheme] + }); + if (!fileResource) { + return undefined; + } + const wsFolder = workspaceContextService.getWorkspaceFolder(fileResource); + if (!wsFolder) { + return undefined; + } + return this.labelService.getUriLabel(wsFolder.uri, { noPrefix: true }); + }, + getSelectedText: (): string | undefined => { + const activeTextEditorControl = editorService.activeTextEditorControl; + + let activeControl: ICodeEditor | null = null; + + if (isCodeEditor(activeTextEditorControl)) { + activeControl = activeTextEditorControl; + } else if (isDiffEditor(activeTextEditorControl)) { + const original = activeTextEditorControl.getOriginalEditor(); + const modified = activeTextEditorControl.getModifiedEditor(); + activeControl = original.hasWidgetFocus() ? original : modified; + } + + const activeModel = activeControl?.getModel(); + const activeSelection = activeControl?.getSelection(); + if (activeModel && activeSelection) { + return activeModel.getValueInRange(activeSelection); + } + return undefined; + }, + getLineNumber: (): string | undefined => { + const activeTextEditorControl = editorService.activeTextEditorControl; + if (isCodeEditor(activeTextEditorControl)) { + const selection = activeTextEditorControl.getSelection(); + if (selection) { + const lineNumber = selection.positionLineNumber; + return String(lineNumber); + } + } + return undefined; + } + }, labelService, pathService.userHome().then(home => home.path), envVariablesPromise); + } + + public override async resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise { + // resolve any non-interactive variables and any contributed variables + config = await this.resolveAnyAsync(folder, config); + + // resolve input variables in the order in which they are encountered + return this.resolveWithInteraction(folder, config, section, variables, target).then(mapping => { + // finally substitute evaluated command variables (if there are any) + if (!mapping) { + return null; + } else if (mapping.size > 0) { + return this.resolveAnyAsync(folder, config, fromMap(mapping)); + } else { + return config; + } + }); + } + + public override async resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise | undefined> { + // resolve any non-interactive variables and any contributed variables + const resolved = await this.resolveAnyMap(folder, config); + config = resolved.newConfig; + const allVariableMapping: Map = resolved.resolvedVariables; + + // resolve input and command variables in the order in which they are encountered + return this.resolveWithInputAndCommands(folder, config, variables, section, target).then(inputOrCommandMapping => { + if (this.updateMapping(inputOrCommandMapping, allVariableMapping)) { + return allVariableMapping; + } + return undefined; + }); + } + + /** + * Add all items from newMapping to fullMapping. Returns false if newMapping is undefined. + */ + private updateMapping(newMapping: IStringDictionary | undefined, fullMapping: Map): boolean { + if (!newMapping) { + return false; + } + forEach(newMapping, (entry) => { + fullMapping.set(entry.key, entry.value); + }); + return true; + } + + /** + * Finds and executes all input and command variables in the given configuration and returns their values as a dictionary. + * Please note: this method does not substitute the input or command variables (so the configuration is not modified). + * The returned dictionary can be passed to "resolvePlatform" for the actual substitution. + * See #6569. + * + * @param variableToCommandMap Aliases for commands + */ + private async resolveWithInputAndCommands(folder: IWorkspaceFolder | undefined, configuration: any, variableToCommandMap?: IStringDictionary, section?: string, target?: ConfigurationTarget): Promise | undefined> { + + if (!configuration) { + return Promise.resolve(undefined); + } + + // get all "inputs" + let inputs: ConfiguredInput[] = []; + if (this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && section) { + const overrides: IConfigurationOverrides = folder ? { resource: folder.uri } : {}; + let result = this.configurationService.inspect(section, overrides); + if (result && (result.userValue || result.workspaceValue || result.workspaceFolderValue)) { + switch (target) { + case ConfigurationTarget.USER: inputs = (result.userValue)?.inputs; break; + case ConfigurationTarget.WORKSPACE: inputs = (result.workspaceValue)?.inputs; break; + default: inputs = (result.workspaceFolderValue)?.inputs; + } + } else { + const valueResult = this.configurationService.getValue(section, overrides); + if (valueResult) { + inputs = valueResult.inputs; + } + } + } + + // extract and dedupe all "input" and "command" variables and preserve their order in an array + const variables: string[] = []; + this.findVariables(configuration, variables); + + const variableValues: IStringDictionary = Object.create(null); + + for (const variable of variables) { + + const [type, name] = variable.split(':', 2); + + let result: string | undefined; + + switch (type) { + + case 'input': + result = await this.showUserInput(name, inputs); + break; + + case 'command': { + // use the name as a command ID #12735 + const commandId = (variableToCommandMap ? variableToCommandMap[name] : undefined) || name; + result = await this.commandService.executeCommand(commandId, configuration); + if (typeof result !== 'string' && !Types.isUndefinedOrNull(result)) { + throw new Error(nls.localize('commandVariable.noStringType', "Cannot substitute command variable '{0}' because command did not return a result of type string.", commandId)); + } + break; + } + default: + // Try to resolve it as a contributed variable + if (this._contributedVariables.has(variable)) { + result = await this._contributedVariables.get(variable)!(); + } + } + + if (typeof result === 'string') { + variableValues[variable] = result; + } else { + return undefined; + } + } + + return variableValues; + } + + /** + * Recursively finds all command or input variables in object and pushes them into variables. + * @param object object is searched for variables. + * @param variables All found variables are returned in variables. + */ + private findVariables(object: any, variables: string[]) { + if (typeof object === 'string') { + let matches; + while ((matches = BaseConfigurationResolverService.INPUT_OR_COMMAND_VARIABLES_PATTERN.exec(object)) !== null) { + if (matches.length === 4) { + const command = matches[1]; + if (variables.indexOf(command) < 0) { + variables.push(command); + } + } + } + this._contributedVariables.forEach((value, contributed: string) => { + if ((variables.indexOf(contributed) < 0) && (object.indexOf('${' + contributed + '}') >= 0)) { + variables.push(contributed); + } + }); + } else if (Types.isArray(object)) { + object.forEach(value => { + this.findVariables(value, variables); + }); + } else if (object) { + Object.keys(object).forEach(key => { + const value = object[key]; + this.findVariables(value, variables); + }); + } + } + + /** + * Takes the provided input info and shows the quick pick so the user can provide the value for the input + * @param variable Name of the input variable. + * @param inputInfos Information about each possible input variable. + */ + private showUserInput(variable: string, inputInfos: ConfiguredInput[]): Promise { + + if (!inputInfos) { + return Promise.reject(new Error(nls.localize('inputVariable.noInputSection', "Variable '{0}' must be defined in an '{1}' section of the debug or task configuration.", variable, 'input'))); + } + + // find info for the given input variable + const info = inputInfos.filter(item => item.id === variable).pop(); + if (info) { + + const missingAttribute = (attrName: string) => { + throw new Error(nls.localize('inputVariable.missingAttribute', "Input variable '{0}' is of type '{1}' and must include '{2}'.", variable, info.type, attrName)); + }; + + switch (info.type) { + + case 'promptString': { + if (!Types.isString(info.description)) { + missingAttribute('description'); + } + const inputOptions: IInputOptions = { prompt: info.description, ignoreFocusLost: true }; + if (info.default) { + inputOptions.value = info.default; + } + if (info.password) { + inputOptions.password = info.password; + } + return this.quickInputService.input(inputOptions).then(resolvedInput => { + return resolvedInput; + }); + } + + case 'pickString': { + if (!Types.isString(info.description)) { + missingAttribute('description'); + } + if (Types.isArray(info.options)) { + info.options.forEach(pickOption => { + if (!Types.isString(pickOption) && !Types.isString(pickOption.value)) { + missingAttribute('value'); + } + }); + } else { + missingAttribute('options'); + } + interface PickStringItem extends IQuickPickItem { + value: string; + } + const picks = new Array(); + info.options.forEach(pickOption => { + const value = Types.isString(pickOption) ? pickOption : pickOption.value; + const label = Types.isString(pickOption) ? undefined : pickOption.label; + + // If there is no label defined, use value as label + const item: PickStringItem = { + label: label ? `${label}: ${value}` : value, + value: value + }; + + if (value === info.default) { + item.description = nls.localize('inputVariable.defaultInputValue', "(Default)"); + picks.unshift(item); + } else { + picks.push(item); + } + }); + const pickOptions: IPickOptions = { placeHolder: info.description, matchOnDetail: true, ignoreFocusLost: true }; + return this.quickInputService.pick(picks, pickOptions, undefined).then(resolvedInput => { + if (resolvedInput) { + return resolvedInput.value; + } + return undefined; + }); + } + + case 'command': { + if (!Types.isString(info.command)) { + missingAttribute('command'); + } + return this.commandService.executeCommand(info.command, info.args).then(result => { + if (typeof result === 'string' || Types.isUndefinedOrNull(result)) { + return result; + } + throw new Error(nls.localize('inputVariable.command.noStringType', "Cannot substitute input variable '{0}' because command '{1}' did not return a result of type string.", variable, info.command)); + }); + } + + default: + throw new Error(nls.localize('inputVariable.unknownType', "Input variable '{0}' can only be of type 'promptString', 'pickString', or 'command'.", variable)); + } + } + return Promise.reject(new Error(nls.localize('inputVariable.undefinedVariable', "Undefined input variable '{0}' encountered. Remove or define '{0}' to continue.", variable))); + } +} diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index acbac82cf51..c4de8509832 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -3,371 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI as uri } from 'vs/base/common/uri'; -import * as nls from 'vs/nls'; -import * as Types from 'vs/base/common/types'; -import { Schemas } from 'vs/base/common/network'; -import { SideBySideEditor, EditorResourceAccessor } from 'vs/workbench/common/editor'; -import { IStringDictionary, forEach, fromMap } from 'vs/base/common/collections'; -import { IConfigurationService, IConfigurationOverrides, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IWorkspaceFolder, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; -import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; -import { IQuickInputService, IInputOptions, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; -import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IProcessEnvironment } from 'vs/base/common/platform'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ILabelService } from 'vs/platform/label/common/label'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; - -export abstract class BaseConfigurationResolverService extends AbstractVariableResolverService { - - static readonly INPUT_OR_COMMAND_VARIABLES_PATTERN = /\${((input|command):(.*?))}/g; - - constructor( - context: { - getAppRoot: () => string | undefined; - getExecPath: () => string | undefined; - }, - envVariablesPromise: Promise, - editorService: IEditorService, - private readonly configurationService: IConfigurationService, - private readonly commandService: ICommandService, - private readonly workspaceContextService: IWorkspaceContextService, - private readonly quickInputService: IQuickInputService, - private readonly labelService: ILabelService, - private readonly pathService: IPathService - ) { - super({ - getFolderUri: (folderName: string): uri | undefined => { - const folder = workspaceContextService.getWorkspace().folders.filter(f => f.name === folderName).pop(); - return folder ? folder.uri : undefined; - }, - getWorkspaceFolderCount: (): number => { - return workspaceContextService.getWorkspace().folders.length; - }, - getConfigurationValue: (folderUri: uri | undefined, suffix: string): string | undefined => { - return configurationService.getValue(suffix, folderUri ? { resource: folderUri } : {}); - }, - getAppRoot: (): string | undefined => { - return context.getAppRoot(); - }, - getExecPath: (): string | undefined => { - return context.getExecPath(); - }, - getFilePath: (): string | undefined => { - const fileResource = EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { - supportSideBySide: SideBySideEditor.PRIMARY, - filterByScheme: [Schemas.file, Schemas.vscodeUserData, this.pathService.defaultUriScheme] - }); - if (!fileResource) { - return undefined; - } - return this.labelService.getUriLabel(fileResource, { noPrefix: true }); - }, - getWorkspaceFolderPathForFile: (): string | undefined => { - const fileResource = EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { - supportSideBySide: SideBySideEditor.PRIMARY, - filterByScheme: [Schemas.file, Schemas.vscodeUserData, this.pathService.defaultUriScheme] - }); - if (!fileResource) { - return undefined; - } - const wsFolder = workspaceContextService.getWorkspaceFolder(fileResource); - if (!wsFolder) { - return undefined; - } - return this.labelService.getUriLabel(wsFolder.uri, { noPrefix: true }); - }, - getSelectedText: (): string | undefined => { - const activeTextEditorControl = editorService.activeTextEditorControl; - - let activeControl: ICodeEditor | null = null; - - if (isCodeEditor(activeTextEditorControl)) { - activeControl = activeTextEditorControl; - } else if (isDiffEditor(activeTextEditorControl)) { - const original = activeTextEditorControl.getOriginalEditor(); - const modified = activeTextEditorControl.getModifiedEditor(); - activeControl = original.hasWidgetFocus() ? original : modified; - } - - const activeModel = activeControl?.getModel(); - const activeSelection = activeControl?.getSelection(); - if (activeModel && activeSelection) { - return activeModel.getValueInRange(activeSelection); - } - return undefined; - }, - getLineNumber: (): string | undefined => { - const activeTextEditorControl = editorService.activeTextEditorControl; - if (isCodeEditor(activeTextEditorControl)) { - const selection = activeTextEditorControl.getSelection(); - if (selection) { - const lineNumber = selection.positionLineNumber; - return String(lineNumber); - } - } - return undefined; - } - }, labelService, pathService.userHome().then(home => home.path), envVariablesPromise); - } - - public override async resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise { - // resolve any non-interactive variables and any contributed variables - config = await this.resolveAnyAsync(folder, config); - - // resolve input variables in the order in which they are encountered - return this.resolveWithInteraction(folder, config, section, variables, target).then(mapping => { - // finally substitute evaluated command variables (if there are any) - if (!mapping) { - return null; - } else if (mapping.size > 0) { - return this.resolveAnyAsync(folder, config, fromMap(mapping)); - } else { - return config; - } - }); - } - - public override async resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise | undefined> { - // resolve any non-interactive variables and any contributed variables - const resolved = await this.resolveAnyMap(folder, config); - config = resolved.newConfig; - const allVariableMapping: Map = resolved.resolvedVariables; - - // resolve input and command variables in the order in which they are encountered - return this.resolveWithInputAndCommands(folder, config, variables, section, target).then(inputOrCommandMapping => { - if (this.updateMapping(inputOrCommandMapping, allVariableMapping)) { - return allVariableMapping; - } - return undefined; - }); - } - - /** - * Add all items from newMapping to fullMapping. Returns false if newMapping is undefined. - */ - private updateMapping(newMapping: IStringDictionary | undefined, fullMapping: Map): boolean { - if (!newMapping) { - return false; - } - forEach(newMapping, (entry) => { - fullMapping.set(entry.key, entry.value); - }); - return true; - } - - /** - * Finds and executes all input and command variables in the given configuration and returns their values as a dictionary. - * Please note: this method does not substitute the input or command variables (so the configuration is not modified). - * The returned dictionary can be passed to "resolvePlatform" for the actual substitution. - * See #6569. - * - * @param variableToCommandMap Aliases for commands - */ - private async resolveWithInputAndCommands(folder: IWorkspaceFolder | undefined, configuration: any, variableToCommandMap?: IStringDictionary, section?: string, target?: ConfigurationTarget): Promise | undefined> { - - if (!configuration) { - return Promise.resolve(undefined); - } - - // get all "inputs" - let inputs: ConfiguredInput[] = []; - if (this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && section) { - const overrides: IConfigurationOverrides = folder ? { resource: folder.uri } : {}; - let result = this.configurationService.inspect(section, overrides); - if (result && (result.userValue || result.workspaceValue || result.workspaceFolderValue)) { - switch (target) { - case ConfigurationTarget.USER: inputs = (result.userValue)?.inputs; break; - case ConfigurationTarget.WORKSPACE: inputs = (result.workspaceValue)?.inputs; break; - default: inputs = (result.workspaceFolderValue)?.inputs; - } - } else { - const valueResult = this.configurationService.getValue(section, overrides); - if (valueResult) { - inputs = valueResult.inputs; - } - } - } - - // extract and dedupe all "input" and "command" variables and preserve their order in an array - const variables: string[] = []; - this.findVariables(configuration, variables); - - const variableValues: IStringDictionary = Object.create(null); - - for (const variable of variables) { - - const [type, name] = variable.split(':', 2); - - let result: string | undefined; - - switch (type) { - - case 'input': - result = await this.showUserInput(name, inputs); - break; - - case 'command': { - // use the name as a command ID #12735 - const commandId = (variableToCommandMap ? variableToCommandMap[name] : undefined) || name; - result = await this.commandService.executeCommand(commandId, configuration); - if (typeof result !== 'string' && !Types.isUndefinedOrNull(result)) { - throw new Error(nls.localize('commandVariable.noStringType', "Cannot substitute command variable '{0}' because command did not return a result of type string.", commandId)); - } - break; - } - default: - // Try to resolve it as a contributed variable - if (this._contributedVariables.has(variable)) { - result = await this._contributedVariables.get(variable)!(); - } - } - - if (typeof result === 'string') { - variableValues[variable] = result; - } else { - return undefined; - } - } - - return variableValues; - } - - /** - * Recursively finds all command or input variables in object and pushes them into variables. - * @param object object is searched for variables. - * @param variables All found variables are returned in variables. - */ - private findVariables(object: any, variables: string[]) { - if (typeof object === 'string') { - let matches; - while ((matches = BaseConfigurationResolverService.INPUT_OR_COMMAND_VARIABLES_PATTERN.exec(object)) !== null) { - if (matches.length === 4) { - const command = matches[1]; - if (variables.indexOf(command) < 0) { - variables.push(command); - } - } - } - this._contributedVariables.forEach((value, contributed: string) => { - if ((variables.indexOf(contributed) < 0) && (object.indexOf('${' + contributed + '}') >= 0)) { - variables.push(contributed); - } - }); - } else if (Types.isArray(object)) { - object.forEach(value => { - this.findVariables(value, variables); - }); - } else if (object) { - Object.keys(object).forEach(key => { - const value = object[key]; - this.findVariables(value, variables); - }); - } - } - - /** - * Takes the provided input info and shows the quick pick so the user can provide the value for the input - * @param variable Name of the input variable. - * @param inputInfos Information about each possible input variable. - */ - private showUserInput(variable: string, inputInfos: ConfiguredInput[]): Promise { - - if (!inputInfos) { - return Promise.reject(new Error(nls.localize('inputVariable.noInputSection', "Variable '{0}' must be defined in an '{1}' section of the debug or task configuration.", variable, 'input'))); - } - - // find info for the given input variable - const info = inputInfos.filter(item => item.id === variable).pop(); - if (info) { - - const missingAttribute = (attrName: string) => { - throw new Error(nls.localize('inputVariable.missingAttribute', "Input variable '{0}' is of type '{1}' and must include '{2}'.", variable, info.type, attrName)); - }; - - switch (info.type) { - - case 'promptString': { - if (!Types.isString(info.description)) { - missingAttribute('description'); - } - const inputOptions: IInputOptions = { prompt: info.description, ignoreFocusLost: true }; - if (info.default) { - inputOptions.value = info.default; - } - if (info.password) { - inputOptions.password = info.password; - } - return this.quickInputService.input(inputOptions).then(resolvedInput => { - return resolvedInput; - }); - } - - case 'pickString': { - if (!Types.isString(info.description)) { - missingAttribute('description'); - } - if (Types.isArray(info.options)) { - info.options.forEach(pickOption => { - if (!Types.isString(pickOption) && !Types.isString(pickOption.value)) { - missingAttribute('value'); - } - }); - } else { - missingAttribute('options'); - } - interface PickStringItem extends IQuickPickItem { - value: string; - } - const picks = new Array(); - info.options.forEach(pickOption => { - const value = Types.isString(pickOption) ? pickOption : pickOption.value; - const label = Types.isString(pickOption) ? undefined : pickOption.label; - - // If there is no label defined, use value as label - const item: PickStringItem = { - label: label ? `${label}: ${value}` : value, - value: value - }; - - if (value === info.default) { - item.description = nls.localize('inputVariable.defaultInputValue', "(Default)"); - picks.unshift(item); - } else { - picks.push(item); - } - }); - const pickOptions: IPickOptions = { placeHolder: info.description, matchOnDetail: true, ignoreFocusLost: true }; - return this.quickInputService.pick(picks, pickOptions, undefined).then(resolvedInput => { - if (resolvedInput) { - return resolvedInput.value; - } - return undefined; - }); - } - - case 'command': { - if (!Types.isString(info.command)) { - missingAttribute('command'); - } - return this.commandService.executeCommand(info.command, info.args).then(result => { - if (typeof result === 'string' || Types.isUndefinedOrNull(result)) { - return result; - } - throw new Error(nls.localize('inputVariable.command.noStringType', "Cannot substitute input variable '{0}' because command '{1}' did not return a result of type string.", variable, info.command)); - }); - } - - default: - throw new Error(nls.localize('inputVariable.unknownType', "Input variable '{0}' can only be of type 'promptString', 'pickString', or 'command'.", variable)); - } - } - return Promise.reject(new Error(nls.localize('inputVariable.undefinedVariable', "Undefined input variable '{0}' encountered. Remove or define '{0}' to continue.", variable))); - } -} +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService'; export class ConfigurationResolverService extends BaseConfigurationResolverService { @@ -385,3 +30,5 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi commandService, workspaceContextService, quickInputService, labelService, pathService); } } + +registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); diff --git a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts index b98d3a68357..f4fcf389c87 100644 --- a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts @@ -11,7 +11,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; +import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService'; import { ILabelService } from 'vs/platform/label/common/label'; import { IShellEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentService'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index 014d9f42c43..ed179a4847b 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -19,7 +19,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { IFormatterChangeEvent, ILabelService, ResourceLabelFormatter } from 'vs/platform/label/common/label'; import { IWorkspace, IWorkspaceFolder, IWorkspaceIdentifier, Workspace } from 'vs/platform/workspace/common/workspace'; import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; -import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; +import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 8f3d9020fd0..b4b1806ff41 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -61,6 +61,7 @@ import 'vs/workbench/services/tunnel/browser/tunnelService'; import 'vs/workbench/services/files/browser/elevatedFileService'; import 'vs/workbench/services/workingCopy/browser/workingCopyHistoryService'; import 'vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService'; +import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -85,8 +86,6 @@ import { NullEndpointTelemetryService } from 'vs/platform/telemetry/common/telem import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart'; import { ITimerService, TimerService } from 'vs/workbench/services/timer/browser/timerService'; -import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { IDiagnosticsService, NullDiagnosticsService } from 'vs/platform/diagnostics/common/diagnostics'; registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService); @@ -102,7 +101,6 @@ registerSingleton(IUserDataAutoSyncService, UserDataAutoSyncService); registerSingleton(ITitleService, TitlebarPart); registerSingleton(IExtensionTipsService, ExtensionTipsService); registerSingleton(ITimerService, TimerService); -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); registerSingleton(ICustomEndpointTelemetryService, NullEndpointTelemetryService, true); registerSingleton(IDiagnosticsService, NullDiagnosticsService, true); From 8c75800b23119abc932a09e38647921a65b4193c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 11:01:53 +0200 Subject: [PATCH 032/135] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c03e5d6c80..7c6dd4e2af0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.67.0", - "distro": "c5695c25f6693722046eff57964fd1e60cab68e8", + "distro": "4f29ad7e15c7b963c9aa9c6c97e57698f544f97b", "author": { "name": "Microsoft Corporation" }, From 145e5934e91295ef643026f5b48289fceb69575a Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 4 Apr 2022 11:15:21 +0200 Subject: [PATCH 033/135] Fixes #146434 --- src/vs/editor/contrib/multicursor/browser/multicursor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/multicursor/browser/multicursor.ts b/src/vs/editor/contrib/multicursor/browser/multicursor.ts index 574a5be3e99..7c658f0fa9b 100644 --- a/src/vs/editor/contrib/multicursor/browser/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/browser/multicursor.ts @@ -1095,7 +1095,7 @@ export class FocusNextCursor extends EditorAction { constructor() { super({ id: 'editor.action.focusNextCursor', - label: nls.localize('mutlicursor.focusNextCursor', "Focus next cursor"), + label: nls.localize('mutlicursor.focusNextCursor', "Focus Next Cursor"), description: { description: nls.localize('mutlicursor.focusNextCursor.description', "Focuses the next cursor"), args: [], @@ -1134,7 +1134,7 @@ export class FocusPreviousCursor extends EditorAction { constructor() { super({ id: 'editor.action.focusPreviousCursor', - label: nls.localize('mutlicursor.focusPreviousCursor', "Focus previous cursor"), + label: nls.localize('mutlicursor.focusPreviousCursor', "Focus Previous Cursor"), description: { description: nls.localize('mutlicursor.focusPreviousCursor.description', "Focuses the previous cursor"), args: [], From 693b2fdbaf7a67b56245fd7b763c9ba925376ac0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 11:21:57 +0200 Subject: [PATCH 034/135] debt - make `URL` available as core type --- build/lib/layersChecker.js | 24 ++++++++++++------------ build/lib/layersChecker.ts | 25 ++++++++++++------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/build/lib/layersChecker.js b/build/lib/layersChecker.js index 113f15245b6..ab467bf2823 100644 --- a/build/lib/layersChecker.js +++ b/build/lib/layersChecker.js @@ -70,7 +70,17 @@ const CORE_TYPES = [ 'atob', 'AbortSignal', 'MessageChannel', - 'MessagePort' + 'MessagePort', + 'URLSearchParams', + 'URL', + 'protocol', + 'hostname', + 'port', + 'pathname', + 'search', + 'username', + 'password', + 'origin' ]; // Types that are defined in a common layer but are known to be only // available in native environments should not be allowed in browser @@ -181,17 +191,7 @@ const RULES = [ { target: '**/vs/**/node/**', allowedTypes: [ - ...CORE_TYPES, - // --> types from node.d.ts that duplicate from lib.dom.d.ts - 'URL', - 'protocol', - 'hostname', - 'port', - 'pathname', - 'search', - 'username', - 'password', - 'origin' + ...CORE_TYPES ], disallowedDefinitions: [ 'lib.dom.d.ts' // no DOM diff --git a/build/lib/layersChecker.ts b/build/lib/layersChecker.ts index e8cea015a75..ef1472786ab 100644 --- a/build/lib/layersChecker.ts +++ b/build/lib/layersChecker.ts @@ -71,7 +71,17 @@ const CORE_TYPES = [ 'atob', 'AbortSignal', 'MessageChannel', - 'MessagePort' + 'MessagePort', + 'URLSearchParams', + 'URL', + 'protocol', + 'hostname', + 'port', + 'pathname', + 'search', + 'username', + 'password', + 'origin' ]; // Types that are defined in a common layer but are known to be only @@ -196,18 +206,7 @@ const RULES = [ { target: '**/vs/**/node/**', allowedTypes: [ - ...CORE_TYPES, - - // --> types from node.d.ts that duplicate from lib.dom.d.ts - 'URL', - 'protocol', - 'hostname', - 'port', - 'pathname', - 'search', - 'username', - 'password', - 'origin' + ...CORE_TYPES ], disallowedDefinitions: [ 'lib.dom.d.ts' // no DOM From 27729fb7c6d390dbdba51fc91693a4021578bb65 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 4 Apr 2022 11:30:34 +0200 Subject: [PATCH 035/135] JSON language status isn't "pin friendly". Fixes #146561 --- .../json-language-features/client/src/languageStatus.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/extensions/json-language-features/client/src/languageStatus.ts b/extensions/json-language-features/client/src/languageStatus.ts index 63541be773d..3be3dd3206f 100644 --- a/extensions/json-language-features/client/src/languageStatus.ts +++ b/extensions/json-language-features/client/src/languageStatus.ts @@ -101,10 +101,12 @@ export function createLanguageStatusItem(documentSelector: string[], statusReque const schemas = (await statusRequest(document.uri.toString())).schemas; statusItem.detail = undefined; if (schemas.length === 0) { - statusItem.text = localize('status.noSchema', 'Validated without JSON schema'); + statusItem.text = localize('status.noSchema.short', "No Schema Validation"); + statusItem.detail = localize('status.noSchema', 'No JSON schema configured.'); } else if (schemas.length === 1) { const item = renderShowSchemasItem(schemas[0]); - statusItem.text = localize('status.singleSchema', 'Validated with JSON schema'); + statusItem.text = localize('status.withSchema.short', "Schema Validated"); + statusItem.detail = localize('status.singleSchema', 'JSON schema configured.'); statusItem.command = { command: 'vscode.open', title: localize('status.openSchemaLink', 'Open Schema'), @@ -112,7 +114,8 @@ export function createLanguageStatusItem(documentSelector: string[], statusReque arguments: [item.uri] }; } else { - statusItem.text = localize('status.multipleSchema', 'Validated with multiple JSON schemas'); + statusItem.text = localize('status.withSchemas.short', "Schema Validated"); + statusItem.detail = localize('status.multipleSchema', 'Multiple JSON schemas configured.'); statusItem.command = { command: '_json.showAssociatedSchemaList', title: localize('status.openSchemasLink', 'Show Schemas'), From d6e89ba74f5c36b765fd1a47fbc12a8ec441c070 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 4 Apr 2022 11:36:26 +0200 Subject: [PATCH 036/135] check with suggest memory when doing inline suggestions, https://github.com/microsoft/vscode/issues/146531 --- .../suggest/browser/suggestInlineCompletions.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestInlineCompletions.ts b/src/vs/editor/contrib/suggest/browser/suggestInlineCompletions.ts index 40358156aac..060b60d499d 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestInlineCompletions.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestInlineCompletions.ts @@ -5,6 +5,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { FuzzyScore } from 'vs/base/common/filters'; +import { Iterable } from 'vs/base/common/iterator'; import { IDisposable, RefCountedDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; @@ -20,6 +21,7 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat import { CompletionItemInsertTextRule } from 'vs/editor/common/standalone/standaloneEnums'; import { CompletionModel, LineContext } from 'vs/editor/contrib/suggest/browser/completionModel'; import { CompletionItemModel, provideSuggestionItems, QuickSuggestionsOptions } from 'vs/editor/contrib/suggest/browser/suggest'; +import { ISuggestMemoryService } from 'vs/editor/contrib/suggest/browser/suggestMemory'; import { WordDistance } from 'vs/editor/contrib/suggest/browser/wordDistance'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -32,6 +34,7 @@ class InlineCompletionResults extends RefCountedDisposable implements InlineComp readonly word: IWordAtPosition, readonly completionModel: CompletionModel, completions: CompletionItemModel, + @ISuggestMemoryService private readonly _suggestMemoryService: ISuggestMemoryService, ) { super(completions.disposable); } @@ -44,7 +47,15 @@ class InlineCompletionResults extends RefCountedDisposable implements InlineComp get items(): InlineCompletion[] { const result: InlineCompletion[] = []; - for (const item of this.completionModel.items) { + + // Split items by preselected index. This ensures the memory-selected item shows first and that better/worst + // ranked items are before/after + const { items } = this.completionModel; + const selectedIndex = this._suggestMemoryService.select(this.model, { lineNumber: this.line, column: this.word.endColumn + this.completionModel.lineContext.characterCountDelta }, items); + const first = Iterable.slice(items, selectedIndex); + const second = Iterable.slice(items, 0, selectedIndex); + + for (const item of Iterable.concat(first, second)) { if (item.score === FuzzyScore.Default) { // skip items that have no overlap @@ -80,6 +91,7 @@ class SuggestInlineCompletions implements InlineCompletionsProvider(id: T, model: ITextModel) => FindComputedEditorOptionValueById, @ILanguageFeaturesService private readonly _languageFeatureService: ILanguageFeaturesService, @IClipboardService private readonly _clipboardService: IClipboardService, + @ISuggestMemoryService private readonly _suggestMemoryService: ISuggestMemoryService, ) { } async provideInlineCompletions(model: ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): Promise { @@ -143,7 +155,7 @@ class SuggestInlineCompletions implements InlineCompletionsProvider Date: Mon, 4 Apr 2022 19:34:08 +0900 Subject: [PATCH 037/135] chore: bump distro Fixes https://github.com/microsoft/vscode/issues/146390 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7c6dd4e2af0..1bc8ed75957 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.67.0", - "distro": "4f29ad7e15c7b963c9aa9c6c97e57698f544f97b", + "distro": "0fd94ba0644559917aaf4e789db83f3801f35d6d", "author": { "name": "Microsoft Corporation" }, From 3451fabc241cdafa041e01a68321cca5deff5079 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 4 Apr 2022 17:16:54 +0530 Subject: [PATCH 038/135] Fix #144294 --- .../browser/extensionEnablementService.ts | 32 +++++++++++++++++++ .../extensionEnablementService.test.ts | 31 ++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index f57e3cb5db6..1040b35beff 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -182,6 +182,11 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } async setEnablement(extensions: IExtension[], newState: EnablementState): Promise { + await this.extensionsManager.whenInitialized(); + + if (newState === EnablementState.EnabledGlobally || newState === EnablementState.EnabledWorkspace) { + extensions.push(...this.getExtensionsToEnableRecursively(extensions, this.extensionsManager.extensions, newState, { dependencies: true, pack: true })); + } const workspace = newState === EnablementState.DisabledWorkspace || newState === EnablementState.EnabledWorkspace; for (const extension of extensions) { @@ -213,6 +218,33 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench return result; } + private getExtensionsToEnableRecursively(extensions: IExtension[], allExtensions: ReadonlyArray, enablementState: EnablementState, options: { dependencies: boolean; pack: boolean }, checked: IExtension[] = []): IExtension[] { + const toCheck = extensions.filter(e => checked.indexOf(e) === -1); + if (toCheck.length) { + for (const extension of toCheck) { + checked.push(extension); + } + const extensionsToDisable = allExtensions.filter(i => { + if (checked.indexOf(i) !== -1) { + return false; + } + if (this.getEnablementState(i) === enablementState) { + return false; + } + return (options.dependencies || options.pack) + && extensions.some(extension => + (options.dependencies && extension.manifest.extensionDependencies?.some(id => areSameExtensions({ id }, i.identifier))) + || (options.pack && extension.manifest.extensionPack?.some(id => areSameExtensions({ id }, i.identifier))) + ); + }); + if (extensionsToDisable.length) { + extensionsToDisable.push(...this.getExtensionsToEnableRecursively(extensionsToDisable, allExtensions, enablementState, options, checked)); + } + return extensionsToDisable; + } + return []; + } + private _setUserEnablementState(extension: IExtension, newState: EnablementState): Promise { const currentState = this._getUserEnablementState(extension.identifier); diff --git a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts index 894fc37142d..660c2fcd2e7 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -386,6 +386,31 @@ suite('ExtensionEnablementService Test', () => { assert.strictEqual(testObject.getEnablementState(extension), EnablementState.EnabledGlobally); }); + test('test enable an extension also enables dependencies', async () => { + installed.push(...[aLocalExtension2('pub.a', { extensionDependencies: ['pub.b'] }), aLocalExtension('pub.b')]); + const target = installed[0]; + const dep = installed[1]; + await (testObject).waitUntilInitialized(); + await testObject.setEnablement([dep, target], EnablementState.DisabledGlobally); + await testObject.setEnablement([target], EnablementState.EnabledGlobally); + assert.ok(testObject.isEnabled(target)); + assert.ok(testObject.isEnabled(dep)); + assert.strictEqual(testObject.getEnablementState(target), EnablementState.EnabledGlobally); + assert.strictEqual(testObject.getEnablementState(dep), EnablementState.EnabledGlobally); + }); + + test('test enable an extension also enables packed extensions', async () => { + installed.push(...[aLocalExtension2('pub.a', { extensionPack: ['pub.b'] }), aLocalExtension('pub.b')]); + const target = installed[0]; + const dep = installed[1]; + await testObject.setEnablement([dep, target], EnablementState.DisabledGlobally); + await testObject.setEnablement([target], EnablementState.EnabledGlobally); + assert.ok(testObject.isEnabled(target)); + assert.ok(testObject.isEnabled(dep)); + assert.strictEqual(testObject.getEnablementState(target), EnablementState.EnabledGlobally); + assert.strictEqual(testObject.getEnablementState(dep), EnablementState.EnabledGlobally); + }); + test('test remove an extension from disablement list when uninstalled', async () => { const extension = aLocalExtension('pub.a'); installed.push(extension); @@ -513,7 +538,7 @@ suite('ExtensionEnablementService Test', () => { const extension = aLocalExtension('pub.a'); installed.push(extension); - testObject.setEnablement([extension], EnablementState.EnabledWorkspace); + await testObject.setEnablement([extension], EnablementState.EnabledWorkspace); instantiationService.stub(IWorkbenchEnvironmentService, { enableExtensions: ['pub.a'] } as IWorkbenchEnvironmentService); testObject = new TestExtensionEnablementService(instantiationService); @@ -525,7 +550,7 @@ suite('ExtensionEnablementService Test', () => { const extension = aLocalExtension('pub.a'); installed.push(extension); - testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); instantiationService.stub(IWorkbenchEnvironmentService, { enableExtensions: ['pub.a'] } as IWorkbenchEnvironmentService); testObject = new TestExtensionEnablementService(instantiationService); @@ -537,7 +562,7 @@ suite('ExtensionEnablementService Test', () => { const extension = aLocalExtension('pub.a'); installed.push(extension); - testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); instantiationService.stub(IWorkbenchEnvironmentService, { enableExtensions: ['pub.a'] } as IWorkbenchEnvironmentService); testObject = new TestExtensionEnablementService(instantiationService); From 65bfe1ef11907242c88efbe5419b12680051c941 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 13:47:33 +0200 Subject: [PATCH 039/135] smoke - enable multi root tests in web --- test/automation/src/playwrightBrowserDriver.ts | 2 +- test/smoke/src/main.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/automation/src/playwrightBrowserDriver.ts b/test/automation/src/playwrightBrowserDriver.ts index 8af107f0681..58f40f38033 100644 --- a/test/automation/src/playwrightBrowserDriver.ts +++ b/test/automation/src/playwrightBrowserDriver.ts @@ -302,7 +302,7 @@ async function launchBrowser(options: LaunchOptions, endpoint: string) { }); const payloadParam = `[["enableProposedApi",""],["webviewExternalEndpointCommit","181b43c0e2949e36ecb623d8cc6de29d4fa2bae8"],["skipWelcome","true"]]`; - await measureAndLog(page.goto(`${endpoint}&folder=${URI.file(workspacePath!).path}&payload=${payloadParam}`), 'page.goto()', logger); + await measureAndLog(page.goto(`${endpoint}&${workspacePath.endsWith('.code-workspace') ? 'workspace' : 'folder'}=${URI.file(workspacePath!).path}&payload=${payloadParam}`), 'page.goto()', logger); return { browser, context, page }; } diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 39af65bfb0f..1d2a7c364d9 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -380,7 +380,7 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : opts.legacy ? 'Electron (lega setupTerminalTests(logger); setupStatusbarTests(logger); if (quality !== Quality.Dev) { setupExtensionTests(logger); } - if (!opts.web) { setupMultirootTests(logger); } + setupMultirootTests(logger); if (!opts.web && !opts.remote && quality !== Quality.Dev) { setupLocalizationTests(logger); } if (!opts.web && !opts.remote) { setupLaunchTests(logger); } }); From 1f2fdee4097dda63abed1ccbc0ef582955596b69 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 14:17:31 +0200 Subject: [PATCH 040/135] files - expose watch options --- src/vs/platform/files/common/files.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 1b75291e899..028d33a315c 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -238,7 +238,7 @@ export interface IFileService { * Note: recursive file watching is not supported from this method. Only events from files * that are direct children of the provided resource will be reported. */ - watch(resource: URI): IDisposable; + watch(resource: URI, options?: IWatchOptions): IDisposable; /** * Frees up any resources occupied by this service. From a9c3c0e4b0384fe2b2c907b94a99fda18d3f34a6 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 4 Apr 2022 14:51:40 +0200 Subject: [PATCH 041/135] Fix file icon showing in custom tree views Fixes #146479 --- .../workbench/browser/parts/views/treeView.ts | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 91df2786f62..345a4f9e5a2 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -65,6 +65,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { Mimes } from 'vs/base/common/mime'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IDataTransfer } from 'vs/workbench/common/dnd'; +import { ThemeSettings } from 'vs/workbench/services/themes/common/workbenchThemeService'; export class TreeViewPane extends ViewPane { @@ -1018,13 +1019,14 @@ class TreeRenderer extends Disposable implements ITreeRenderer('explorer.decorations'); const labelResource = resource ? resource : URI.parse('missing:_icon_resource'); templateData.resourceLabel.setResource({ name: label, description, resource: labelResource }, { fileKind: this.getFileKind(node), title, - hideIcon: !!iconUrl || !!node.themeIcon, + hideIcon: !!iconUrl || this.shouldShowThemeIcon(!!resource, node.themeIcon), fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData), @@ -1047,7 +1049,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer Date: Mon, 4 Apr 2022 15:03:17 +0200 Subject: [PATCH 042/135] smoke - run legacy tests again, do not fail new playwright tests for a while to figure out flakiness --- .../darwin/product-build-darwin.yml | 22 +++++++++++++++++++ .../linux/product-build-linux-client.yml | 20 +++++++++++++++++ .../win32/product-build-win32.yml | 22 +++++++++++++++++++ test/smoke/src/main.ts | 2 +- 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 1c529a95362..2b4a19c42aa 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -249,6 +249,7 @@ steps: # Increased timeout because this test downloads stable code timeoutInMinutes: 20 displayName: Run smoke tests (Electron) + continueOnError: true condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | @@ -259,6 +260,27 @@ steps: yarn smoketest-no-compile --tracing --remote --build "$APP_ROOT/$APP_NAME" timeoutInMinutes: 10 displayName: Run smoke tests (Remote) + continueOnError: true + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + yarn smoketest-no-compile --legacy --tracing --build "$APP_ROOT/$APP_NAME" + # Increased timeout because this test downloads stable code + timeoutInMinutes: 20 + displayName: Run smoke tests (Legacy, Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + APP_NAME="`ls $APP_ROOT | head -n 1`" + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin-$(VSCODE_ARCH)" \ + yarn smoketest-no-compile --legacy --tracing --remote --build "$APP_ROOT/$APP_NAME" + timeoutInMinutes: 10 + displayName: Run smoke tests (Legacy, Remote) condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - task: PublishPipelineArtifact@0 diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 5f15732ad85..3e04ef34233 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -271,6 +271,7 @@ steps: # Increased timeout because this test downloads stable code timeoutInMinutes: 20 displayName: Run smoke tests (Electron) + continueOnError: true condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | @@ -280,6 +281,25 @@ steps: yarn smoketest-no-compile --tracing --remote --build "$APP_PATH" timeoutInMinutes: 10 displayName: Run smoke tests (Remote) + continueOnError: true + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + + - script: | + set -e + APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + yarn smoketest-no-compile --legacy --tracing --build "$APP_PATH" + # Increased timeout because this test downloads stable code + timeoutInMinutes: 20 + displayName: Run smoke tests (Legacy, Electron) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + + - script: | + set -e + APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-$(VSCODE_ARCH)" \ + yarn smoketest-no-compile --legacy --tracing --remote --build "$APP_PATH" + timeoutInMinutes: 10 + displayName: Run smoke tests (Legacy, Remote) condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - task: PublishPipelineArtifact@0 diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index cd18ffe4c7a..b68783b2e2c 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -231,6 +231,7 @@ steps: $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" exec { yarn smoketest-no-compile --tracing --build "$AppRoot" } displayName: Run smoke tests (Electron) + continueOnError: true # Increased timeout because this test downloads stable code timeoutInMinutes: 20 condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) @@ -242,6 +243,27 @@ steps: $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)" exec { yarn smoketest-no-compile --tracing --remote --build "$AppRoot" } displayName: Run smoke tests (Remote) + continueOnError: true + timeoutInMinutes: 10 + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + exec { yarn smoketest-no-compile --legacy --tracing --build "$AppRoot" } + displayName: Run smoke tests (Legacy, Electron) + # Increased timeout because this test downloads stable code + timeoutInMinutes: 20 + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)" + exec { yarn smoketest-no-compile --legacy --tracing --remote --build "$AppRoot" } + displayName: Run smoke tests (Legacy, Remote) timeoutInMinutes: 10 condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 1d2a7c364d9..a5a2710d34d 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -377,7 +377,7 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : opts.legacy ? 'Electron (lega setupSearchTests(logger); setupNotebookTests(logger); setupLanguagesTests(logger); - setupTerminalTests(logger); + if (!opts.legacy) { setupTerminalTests(logger); } setupStatusbarTests(logger); if (quality !== Quality.Dev) { setupExtensionTests(logger); } setupMultirootTests(logger); From 56e31e29960681b728b783557a000a9881b0c204 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 4 Apr 2022 15:03:46 +0200 Subject: [PATCH 043/135] Fix typo --- .../contrib/comments/browser/commentThreadZoneWidget.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts index 151a49ffbb6..14ad6544915 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts @@ -85,7 +85,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget private readonly _globalToDispose = new DisposableStore(); private _commentThreadDisposables: IDisposable[] = []; private _contextKeyService: IContextKeyService; - private _scopedInstatiationService: IInstantiationService; + private _scopedInstantiationService: IInstantiationService; public get owner(): string { return this._owner; @@ -109,7 +109,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget super(editor, { keepEditorSelection: true }); this._contextKeyService = contextKeyService.createScoped(this.domNode); - this._scopedInstatiationService = instantiationService.createChild(new ServiceCollection( + this._scopedInstantiationService = instantiationService.createChild(new ServiceCollection( [IContextKeyService, this._contextKeyService] )); @@ -184,13 +184,13 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget protected _fillContainer(container: HTMLElement): void { this.setCssClass('review-widget'); - this._commentThreadWidget = this._scopedInstatiationService.createInstance( + this._commentThreadWidget = this._scopedInstantiationService.createInstance( CommentThreadWidget, container, this._owner, this.editor.getModel()!.uri, this._contextKeyService, - this._scopedInstatiationService, + this._scopedInstantiationService, this._commentThread as unknown as languages.CommentThread, this._pendingComment, { editor: this.editor }, From d06e16b59a72373e3fd2415012cac47491b08794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 4 Apr 2022 15:04:29 +0200 Subject: [PATCH 044/135] layer checker: follow parent symbols --- build/lib/layersChecker.js | 96 ++++++++++++++--------------------- build/lib/layersChecker.ts | 101 +++++++++++++++---------------------- 2 files changed, 79 insertions(+), 118 deletions(-) diff --git a/build/lib/layersChecker.js b/build/lib/layersChecker.js index ab467bf2823..8caccef815e 100644 --- a/build/lib/layersChecker.js +++ b/build/lib/layersChecker.js @@ -29,30 +29,13 @@ const CORE_TYPES = [ 'setInterval', 'clearInterval', 'console', - 'log', - 'info', - 'warn', - 'error', - 'trace', - 'group', - 'groupEnd', - 'table', - 'assert', + 'Console', 'Error', + 'ErrorConstructor', 'String', - 'throws', - 'stack', - 'captureStackTrace', - 'stackTraceLimit', 'TextDecoder', 'TextEncoder', - 'encode', - 'decode', 'self', - 'trimStart', - 'trimEnd', - 'trimLeft', - 'trimRight', 'queueMicrotask', 'Array', 'Uint8Array', @@ -71,16 +54,8 @@ const CORE_TYPES = [ 'AbortSignal', 'MessageChannel', 'MessagePort', - 'URLSearchParams', 'URL', - 'protocol', - 'hostname', - 'port', - 'pathname', - 'search', - 'username', - 'password', - 'origin' + 'URLSearchParams' ]; // Types that are defined in a common layer but are known to be only // available in native environments should not be allowed in browser @@ -104,7 +79,6 @@ const RULES = [ ...CORE_TYPES, // Safe access to postMessage() and friends 'MessageEvent', - 'data' ], disallowedTypes: NATIVE_TYPES, disallowedDefinitions: [ @@ -190,9 +164,7 @@ const RULES = [ // node.js { target: '**/vs/**/node/**', - allowedTypes: [ - ...CORE_TYPES - ], + allowedTypes: CORE_TYPES, disallowedDefinitions: [ 'lib.dom.d.ts' // no DOM ] @@ -232,43 +204,49 @@ function checkFile(program, sourceFile, rule) { if (node.kind !== ts.SyntaxKind.Identifier) { return ts.forEachChild(node, checkNode); // recurse down } - const text = node.getText(sourceFile); + const checker = program.getTypeChecker(); + const symbol = checker.getSymbolAtLocation(node); + if (!symbol) { + return; + } + let _parentSymbol = symbol; + while (_parentSymbol.parent) { + _parentSymbol = _parentSymbol.parent; + } + const parentSymbol = _parentSymbol; + const text = parentSymbol.getName(); if (rule.allowedTypes?.some(allowed => allowed === text)) { return; // override } if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); hasErrors = true; return; } - const checker = program.getTypeChecker(); - const symbol = checker.getSymbolAtLocation(node); - if (symbol) { - const declarations = symbol.declarations; - if (Array.isArray(declarations)) { - DeclarationLoop: for (const declaration of declarations) { - if (declaration) { - const parent = declaration.parent; - if (parent) { - const parentSourceFile = parent.getSourceFile(); - if (parentSourceFile) { - const definitionFileName = parentSourceFile.fileName; - if (rule.allowedDefinitions) { - for (const allowedDefinition of rule.allowedDefinitions) { - if (definitionFileName.indexOf(allowedDefinition) >= 0) { - continue DeclarationLoop; - } + const declarations = symbol.declarations; + if (Array.isArray(declarations)) { + DeclarationLoop: for (const declaration of declarations) { + if (declaration) { + const parent = declaration.parent; + if (parent) { + const parentSourceFile = parent.getSourceFile(); + if (parentSourceFile) { + const definitionFileName = parentSourceFile.fileName; + if (rule.allowedDefinitions) { + for (const allowedDefinition of rule.allowedDefinitions) { + if (definitionFileName.indexOf(allowedDefinition) >= 0) { + continue DeclarationLoop; } } - if (rule.disallowedDefinitions) { - for (const disallowedDefinition of rule.disallowedDefinitions) { - if (definitionFileName.indexOf(disallowedDefinition) >= 0) { - const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); - hasErrors = true; - return; - } + } + if (rule.disallowedDefinitions) { + for (const disallowedDefinition of rule.disallowedDefinitions) { + if (definitionFileName.indexOf(disallowedDefinition) >= 0) { + const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); + console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + hasErrors = true; + return; } } } diff --git a/build/lib/layersChecker.ts b/build/lib/layersChecker.ts index ef1472786ab..af9ccd0ae92 100644 --- a/build/lib/layersChecker.ts +++ b/build/lib/layersChecker.ts @@ -30,30 +30,13 @@ const CORE_TYPES = [ 'setInterval', 'clearInterval', 'console', - 'log', - 'info', - 'warn', - 'error', - 'trace', - 'group', - 'groupEnd', - 'table', - 'assert', + 'Console', 'Error', + 'ErrorConstructor', 'String', - 'throws', - 'stack', - 'captureStackTrace', - 'stackTraceLimit', 'TextDecoder', 'TextEncoder', - 'encode', - 'decode', 'self', - 'trimStart', - 'trimEnd', - 'trimLeft', - 'trimRight', 'queueMicrotask', 'Array', 'Uint8Array', @@ -72,16 +55,8 @@ const CORE_TYPES = [ 'AbortSignal', 'MessageChannel', 'MessagePort', - 'URLSearchParams', 'URL', - 'protocol', - 'hostname', - 'port', - 'pathname', - 'search', - 'username', - 'password', - 'origin' + 'URLSearchParams' ]; // Types that are defined in a common layer but are known to be only @@ -110,7 +85,6 @@ const RULES = [ // Safe access to postMessage() and friends 'MessageEvent', - 'data' ], disallowedTypes: NATIVE_TYPES, disallowedDefinitions: [ @@ -205,9 +179,7 @@ const RULES = [ // node.js { target: '**/vs/**/node/**', - allowedTypes: [ - ...CORE_TYPES - ], + allowedTypes: CORE_TYPES, disallowedDefinitions: [ 'lib.dom.d.ts' // no DOM ] @@ -265,7 +237,21 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) return ts.forEachChild(node, checkNode); // recurse down } - const text = node.getText(sourceFile); + const checker = program.getTypeChecker(); + const symbol = checker.getSymbolAtLocation(node); + + if (!symbol) { + return; + } + + let _parentSymbol: any = symbol; + + while (_parentSymbol.parent) { + _parentSymbol = _parentSymbol.parent; + } + + const parentSymbol = _parentSymbol as ts.Symbol; + const text = parentSymbol.getName(); if (rule.allowedTypes?.some(allowed => allowed === text)) { return; // override @@ -273,40 +259,37 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) if (rule.disallowedTypes?.some(disallowed => disallowed === text)) { const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); hasErrors = true; return; } - const checker = program.getTypeChecker(); - const symbol = checker.getSymbolAtLocation(node); - if (symbol) { - const declarations = symbol.declarations; - if (Array.isArray(declarations)) { - DeclarationLoop: for (const declaration of declarations) { - if (declaration) { - const parent = declaration.parent; - if (parent) { - const parentSourceFile = parent.getSourceFile(); - if (parentSourceFile) { - const definitionFileName = parentSourceFile.fileName; - if (rule.allowedDefinitions) { - for (const allowedDefinition of rule.allowedDefinitions) { - if (definitionFileName.indexOf(allowedDefinition) >= 0) { - continue DeclarationLoop; - } + const declarations = symbol.declarations; + if (Array.isArray(declarations)) { + DeclarationLoop: for (const declaration of declarations) { + if (declaration) { + const parent = declaration.parent; + if (parent) { + const parentSourceFile = parent.getSourceFile(); + if (parentSourceFile) { + const definitionFileName = parentSourceFile.fileName; + if (rule.allowedDefinitions) { + for (const allowedDefinition of rule.allowedDefinitions) { + if (definitionFileName.indexOf(allowedDefinition) >= 0) { + continue DeclarationLoop; } } - if (rule.disallowedDefinitions) { - for (const disallowedDefinition of rule.disallowedDefinitions) { - if (definitionFileName.indexOf(disallowedDefinition) >= 0) { - const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + } + if (rule.disallowedDefinitions) { + for (const disallowedDefinition of rule.disallowedDefinitions) { + if (definitionFileName.indexOf(disallowedDefinition) >= 0) { + const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - hasErrors = true; - return; - } + console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); + + hasErrors = true; + return; } } } From 44aea76875e2a50053676c3eb52fa174725129bf Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 15:38:22 +0200 Subject: [PATCH 045/135] :lipstick: --- test/automation/src/code.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index 33eba97ba52..f7cbcda189f 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -140,7 +140,7 @@ async function poll( export class Code { private _activeWindowId: number | undefined = undefined; - driver: IDriver; + readonly driver: IDriver; constructor( private client: IDisposable, @@ -173,16 +173,12 @@ export class Code { async startTracing(name: string): Promise { const windowId = await this.getActiveWindowId(); - if (typeof this.driver.startTracing === 'function') { // added only in 1.64 - return await this.driver.startTracing(windowId, name); - } + return await this.driver.startTracing(windowId, name); } async stopTracing(name: string, persist: boolean): Promise { const windowId = await this.getActiveWindowId(); - if (typeof this.driver.stopTracing === 'function') { // added only in 1.64 - return await this.driver.stopTracing(windowId, name, persist); - } + return await this.driver.stopTracing(windowId, name, persist); } async waitForWindowIds(accept: (windowIds: number[]) => boolean): Promise { From 0390d4f2a426f392091acbcc2c039b240f351b34 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 4 Apr 2022 15:47:15 +0200 Subject: [PATCH 046/135] smoke - try to use locator API for window ready --- test/automation/src/application.ts | 9 ++++++++- test/automation/src/playwrightBrowserDriver.ts | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/automation/src/application.ts b/test/automation/src/application.ts index 2a6df7dc49b..252d809edcd 100644 --- a/test/automation/src/application.ts +++ b/test/automation/src/application.ts @@ -6,6 +6,7 @@ import { Workbench } from './workbench'; import { Code, launch, LaunchOptions } from './code'; import { Logger } from './logger'; +import { PlaywrightDriver } from './playwrightBrowserDriver'; export const enum Quality { Dev, @@ -142,7 +143,13 @@ export class Application { this.logger.log('checkWindowReady: begin'); await code.waitForWindowIds(ids => ids.length > 0); - await code.waitForElement('.monaco-workbench'); + + // TODO@bpasero productize this hack + if (code.driver instanceof PlaywrightDriver) { + await code.driver.page.locator('.monaco-workbench').waitFor({ timeout: 40000 }); + } else { + await code.waitForElement('.monaco-workbench'); + } // Remote but not web: wait for a remote connection state change if (this.remote) { diff --git a/test/automation/src/playwrightBrowserDriver.ts b/test/automation/src/playwrightBrowserDriver.ts index 58f40f38033..e53d8e68c20 100644 --- a/test/automation/src/playwrightBrowserDriver.ts +++ b/test/automation/src/playwrightBrowserDriver.ts @@ -38,7 +38,7 @@ export class PlaywrightDriver implements IDriver { constructor( private readonly application: playwright.Browser | playwright.ElectronApplication, private readonly context: playwright.BrowserContext, - private readonly page: playwright.Page, + readonly page: playwright.Page, // TODO@bpasero make private again private readonly serverPid: number | undefined, private readonly options: LaunchOptions ) { From c27b6d1c243832bd6b6a433485ee43d23ba04d89 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 4 Apr 2022 16:16:27 +0200 Subject: [PATCH 047/135] add `editor.inlayHints.toggle` option to quickly show or hide inlay hints, https://github.com/microsoft/vscode/issues/128162 --- src/vs/editor/common/config/editorOptions.ts | 18 ++++- .../browser/inlayHintsController.ts | 68 ++++++++++++++----- src/vs/monaco.d.ts | 4 ++ 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 2d38b52d373..febb7dac4d6 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2503,6 +2503,11 @@ export interface IEditorInlayHintsOptions { */ enabled?: boolean; + /** + * + */ + toggle?: 'show' | 'hide' | null; + /** * Font size of inline hints. * Default to 90% of the editor font size. @@ -2531,7 +2536,7 @@ export type EditorInlayHintsOptions = Readonly { constructor() { - const defaults: EditorInlayHintsOptions = { enabled: true, fontSize: 0, fontFamily: '', displayStyle: 'compact' }; + const defaults: EditorInlayHintsOptions = { enabled: true, toggle: null, fontSize: 0, fontFamily: '', displayStyle: 'compact' }; super( EditorOption.inlayHints, 'inlayHints', defaults, { @@ -2540,6 +2545,16 @@ class EditorInlayHints extends BaseEditorOption